Skip to content

Bootstrap dev Key Vault access before Terraform apply#84

Merged
JustAGhosT merged 1 commit into
mainfrom
fix/dev-keyvault-bootstrap
Jul 17, 2026
Merged

Bootstrap dev Key Vault access before Terraform apply#84
JustAGhosT merged 1 commit into
mainfrom
fix/dev-keyvault-bootstrap

Conversation

@JustAGhosT

Copy link
Copy Markdown
Collaborator

Summary

  • add a dev-only pre-apply bootstrap step that grants the GitHub Actions OIDC principal Key Vault secret permissions
  • run the bootstrap after Azure OIDC login and before Terraform init/apply, so Terraform can refresh existing Key Vault secrets

Fixes

Validation

  • git diff --check -- .github/workflows/infrastructure.yml

@github-actions

Copy link
Copy Markdown

Terraform Plan (dev)

Click to expand
Acquiring state lock. This may take a few moments...
data.azurerm_client_config.current: Reading...
azurerm_resource_group.rg: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg]
data.azurerm_client_config.current: Read complete after 0s [id=Y2xpZW50Q29uZmlncy9jbGllbnRJZD04ZjU3YTM0OS1lYjg4LTQwZmQtODFlYi0xMDY1Zjg0ZTY2OGI7b2JqZWN0SWQ9ZDQ4NzYyOWQtMDc1OC00MTkyLWJmMDAtZGZkNGYyMTRhNzM4O3N1YnNjcmlwdGlvbklkPWJiNGUzODgyLTIwNzktNGJhYi04OTc0LTYxMWJjMGI4YmI1ODt0ZW5hbnRJZD05NTMwY2QzMi05ZTMzLTQ3ZjAtOTI0Ny1lZDk2NDczMGI1ODA=]
azurerm_log_analytics_workspace.law: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.OperationalInsights/workspaces/nl-dev-convolens-law]
azurerm_key_vault.kv: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.KeyVault/vaults/nl-dev-convolens-kv]
azurerm_static_web_app.swa[0]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.Web/staticSites/nl-dev-convolens-swa]
azurerm_cosmosdb_account.cosmos[0]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.DocumentDB/databaseAccounts/nl-dev-convolens-cosmos]
azurerm_storage_account.st: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.Storage/storageAccounts/nldevconvolensst]
azurerm_container_app_environment.cae[0]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.App/managedEnvironments/nl-dev-convolens-cae]
azurerm_application_insights.ai: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.Insights/components/nl-dev-convolens-appi]
azurerm_key_vault_access_policy.deployer: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.KeyVault/vaults/nl-dev-convolens-kv/objectId/99b63adb-8f1a-4d7a-a98c-5bfe9c7fcd96]
azurerm_key_vault_secret.cosmos_connection_string[0]: Refreshing state... [id=https://nl-dev-convolens-kv.vault.azure.net/secrets/cosmos-db-connection-string/257323432daf46b0bea651cb955280b4]
azurerm_cosmosdb_sql_database.db[0]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.DocumentDB/databaseAccounts/nl-dev-convolens-cosmos/sqlDatabases/convolens]
azurerm_key_vault_secret.cosmos_key[0]: Refreshing state... [id=https://nl-dev-convolens-kv.vault.azure.net/secrets/cosmos-db-key/9f5c0fca48b048ff97f93e9099863eb1]
azurerm_key_vault_secret.cosmos_endpoint[0]: Refreshing state... [id=https://nl-dev-convolens-kv.vault.azure.net/secrets/cosmos-db-endpoint/83825780119644b2bc46d5a75da2b552]
azurerm_cosmosdb_sql_container.containers["chats"]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.DocumentDB/databaseAccounts/nl-dev-convolens-cosmos/sqlDatabases/convolens/containers/chats]
azurerm_cosmosdb_sql_container.containers["users"]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.DocumentDB/databaseAccounts/nl-dev-convolens-cosmos/sqlDatabases/convolens/containers/users]
azurerm_cosmosdb_sql_container.containers["summaries"]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.DocumentDB/databaseAccounts/nl-dev-convolens-cosmos/sqlDatabases/convolens/containers/summaries]
azurerm_storage_container.containers["user-uploads"]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.Storage/storageAccounts/nldevconvolensst/blobServices/default/containers/user-uploads]
azurerm_storage_container.containers["chat-exports"]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.Storage/storageAccounts/nldevconvolensst/blobServices/default/containers/chat-exports]
azurerm_storage_container.containers["summaries"]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.Storage/storageAccounts/nldevconvolensst/blobServices/default/containers/summaries]
azurerm_key_vault_secret.storage_connection_string: Refreshing state... [id=https://nl-dev-convolens-kv.vault.azure.net/secrets/storage-connection-string/f437ca08a54d46ebbf12b9a39387efa2]
azurerm_key_vault_secret.appinsights_connection_string: Refreshing state... [id=https://nl-dev-convolens-kv.vault.azure.net/secrets/appinsights-connection-string/b49878c8df8c451986ff9d02d8905090]
azurerm_container_app.api[0]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.App/containerApps/nl-dev-convolens-api]
azurerm_key_vault_access_policy.container_app[0]: Refreshing state... [id=/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.KeyVault/vaults/nl-dev-convolens-kv/objectId/801ba185-32e1-4a45-a385-629c79cb6a4c]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place
-/+ destroy and then create replacement

Terraform planned the following actions, but then encountered a problem:

  # azurerm_container_app.api[0] will be updated in-place
  ~ resource "azurerm_container_app" "api" {
        id                            = "/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.App/containerApps/nl-dev-convolens-api"
        name                          = "nl-dev-convolens-api"
        tags                          = {
            "costCenter"  = "development"
            "environment" = "dev"
            "managedBy"   = "terraform"
            "org"         = "nl"
            "project"     = "convolens"
        }
        # (10 unchanged attributes hidden)

      ~ template {
            # (6 unchanged attributes hidden)

          ~ container {
              ~ memory            = "1Gi" -> "1.0Gi"
                name              = "api"
                # (5 unchanged attributes hidden)

                # (8 unchanged blocks hidden)
            }

            # (1 unchanged block hidden)
        }

        # (3 unchanged blocks hidden)
    }

  # azurerm_cosmosdb_sql_container.containers["chats"] will be updated in-place
  ~ resource "azurerm_cosmosdb_sql_container" "containers" {
        id                  = "/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.DocumentDB/databaseAccounts/nl-dev-convolens-cosmos/sqlDatabases/convolens/containers/chats"
        name                = "chats"
        # (5 unchanged attributes hidden)

      ~ indexing_policy {
            # (1 unchanged attribute hidden)

          + excluded_path {
              + path = "/\"_etag\"/?"
            }

            # (1 unchanged block hidden)
        }

        # (1 unchanged block hidden)
    }

  # azurerm_cosmosdb_sql_container.containers["summaries"] will be updated in-place
  ~ resource "azurerm_cosmosdb_sql_container" "containers" {
        id                  = "/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.DocumentDB/databaseAccounts/nl-dev-convolens-cosmos/sqlDatabases/convolens/containers/summaries"
        name                = "summaries"
        # (5 unchanged attributes hidden)

      ~ indexing_policy {
            # (1 unchanged attribute hidden)

          + excluded_path {
              + path = "/\"_etag\"/?"
            }

            # (1 unchanged block hidden)
        }

        # (1 unchanged block hidden)
    }

  # azurerm_cosmosdb_sql_container.containers["users"] will be updated in-place
  ~ resource "azurerm_cosmosdb_sql_container" "containers" {
        id                  = "/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.DocumentDB/databaseAccounts/nl-dev-convolens-cosmos/sqlDatabases/convolens/containers/users"
        name                = "users"
        # (5 unchanged attributes hidden)

      ~ indexing_policy {
            # (1 unchanged attribute hidden)

          + excluded_path {
              + path = "/\"_etag\"/?"
            }

            # (1 unchanged block hidden)
        }

        # (1 unchanged block hidden)
    }

  # azurerm_key_vault_access_policy.ci_deployers["d487629d-0758-4192-bf00-dfd4f214a738"] will be created
  + resource "azurerm_key_vault_access_policy" "ci_deployers" {
      + id                 = (known after apply)
      + key_vault_id       = "/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.KeyVault/vaults/nl-dev-convolens-kv"
      + object_id          = "d487629d-0758-4192-bf00-dfd4f214a738"
      + secret_permissions = [
          + "Get",
          + "List",
          + "Set",
          + "Delete",
          + "Purge",
          + "Recover",
        ]
      + tenant_id          = "9530cd32-9e33-47f0-9247-ed964730b580"
    }

  # azurerm_key_vault_access_policy.deployer must be replaced
-/+ resource "azurerm_key_vault_access_policy" "deployer" {
      - certificate_permissions = [] -> null
      ~ id                      = "/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.KeyVault/vaults/nl-dev-convolens-kv/objectId/99b63adb-8f1a-4d7a-a98c-5bfe9c7fcd96" -> (known after apply)
      - key_permissions         = [] -> null
      ~ object_id               = "99b63adb-8f1a-4d7a-a98c-5bfe9c7fcd96" -> "d487629d-0758-4192-bf00-dfd4f214a738" # forces replacement
      - storage_permissions     = [] -> null
        # (4 unchanged attributes hidden)
    }

  # azurerm_storage_account.st will be updated in-place
  ~ resource "azurerm_storage_account" "st" {
        id                                 = "/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/nl-dev-convolens-rg/providers/Microsoft.Storage/storageAccounts/nldevconvolensst"
        name                               = "nldevconvolensst"
        tags                               = {
            "costCenter"  = "development"
            "environment" = "dev"
            "managedBy"   = "terraform"
            "org"         = "nl"
            "project"     = "convolens"
        }
        # (97 unchanged attributes hidden)

      + network_rules {
          + bypass                     = [
              + "AzureServices",
            ]
          + default_action             = "Allow"
          + ip_rules                   = (known after apply)
          + virtual_network_subnet_ids = (known after apply)
        }

        # (3 unchanged blocks hidden)
    }

Plan: 2 to add, 5 to change, 1 to destroy.
Releasing state lock. This may take a few moments...
::error::Terraform exited with code 1.

Run ID: 29608609957

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bded32ea96

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +227 to +230
az keyvault set-policy \
--name nl-dev-convolens-kv \
--object-id "$DEPLOYER_OBJECT_ID" \
--secret-permissions get list set delete purge recover

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Skip the bootstrap until the Key Vault exists

On the first dev deployment (and after the documented terraform destroy), nl-dev-convolens-kv does not yet exist; the dev Terraform configuration is what creates it. This unconditional az keyvault set-policy therefore exits nonzero before Terraform Init/Apply can create the vault, preventing CI from provisioning or recreating the environment. Guard the command for a missing vault, or perform this bootstrap only after the vault is known to exist.

Useful? React with 👍 / 👎.

@JustAGhosT
JustAGhosT merged commit 369b9ba into main Jul 17, 2026
4 checks passed
@JustAGhosT
JustAGhosT deleted the fix/dev-keyvault-bootstrap branch July 17, 2026 19:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant