Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating the value of an azurerm_key_vault_secret does not update its ID when used as a dependency #13337

Open
kensykora opened this issue Sep 13, 2021 · 8 comments
Labels
bug service/key-vault Key Vault upstream/terraform This issue is blocked on an upstream issue within Terraform (Terraform Core/CLI, The Plugin SDK etc) v/2.x (legacy)

Comments

@kensykora
Copy link

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request

Terraform (and AzureRM Provider) Version

  • Terraform Core version: 1.0.6
  • AzureRM Provider version: 2.73.0

Terraform Configuration Files

resource "azurerm_key_vault_secret" "service_bus_connection_string" {
  name = "service-bus-connection-string"

  value        = azurerm_servicebus_topic_authorization_rule.mysb.primary_connection_string
  key_vault_id = azurerm_key_vault.main.id
}

resource "azurerm_function_app" "main" {
  name                = "myfn"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name

  app_service_plan_id = azurerm_app_service_plan.main.id

  enable_builtin_logging = true
  https_only             = true
  os_type                = "linux"

  storage_account_name       = azurerm_storage_account.main.name
  storage_account_access_key = azurerm_storage_account.main.primary_access_key

  version = "~3"

  app_settings = {
    AzureWebJobsServiceBus      = "@Microsoft.KeyVault(SecretUri=${azurerm_key_vault_secret.service_bus_connection_string.id})"
  }
}

Description / Feedback

When the underlying value for an azurerm_key_vault_secret changes, the ID for the secret is generated. In the above code sample, the first time terraform apply is run, the app_setting is seeded properly with the resulting ID from the key vault operation with the version of the secret created. The app_settings config value will look something like: @Microsoft.KeyVault(SecretUri=https://hmykv.vault.azure.net/secrets/service-bus-connection-string/809284ceae23484589eb0fa1a6c6e147)

Again, on the initial first apply, this works as expected.

After changing the value (in our use case, rotating the primary access key of the access policy for the service bus account) however, the ID does not change on the 2nd apply. On the 2nd terraform apply, the value of the secret will be updated, but the azurerm_key_vault_secret.service_bus_connection_string.id reference will remain at the old value.

On a 3rd terraform apply, the secret version value in the attribute output reference will be properly updated.

Steps to Reproduce:

  1. Create config similar to above.
  2. Run terraform apply - Observe that the use of the id attribute in azurerm_key_vault_secret is used correctly
  3. Change the value of the azurerm_key_vault_secret
  4. Run terraform apply

Expected: The dependency on the azurerm_key_vault_secret updates the usage of the .id property such that dependencies on the secret in terraform are propagated and updated in their usages
Actual: The value is updated in terraform, but the dependencies on the .id value of the azurerm_key_vault_secret do not reflect the new ID created in Azure.

Workaround: Run terraform apply a third time, and the ID will get updated.

@lonegunmanb
Copy link
Contributor

Hello @kensykora ,

It's hard to say that it is a Terraform or AzureRM Provider's bug. This behavior is by design and I think it's very hard for HashiCorp to change that. Terraform workflow have two different stages: Plan and Apply. If you change value of azurerm_key_vault_secret, it'll cause a re-creation and id will change, but in Plan stage Terraform cannot be aware that, so the execution plan it generated won't realize that the content in your azurerm_function_app will changed. As a rather easy sample as below:

data "azurerm_client_config" "current" {}

resource "azurerm_resource_group" "example" {
  name     = "example"
  location = "East Asia"
}

resource "azurerm_key_vault" "example" {
  name                       = "example"
  location                   = azurerm_resource_group.example.location
  resource_group_name        = azurerm_resource_group.example.name
  tenant_id                  = data.azurerm_client_config.current.tenant_id
  sku_name                   = "standard"
  soft_delete_retention_days = 7

  access_policy {
    tenant_id = data.azurerm_client_config.current.tenant_id
    object_id = data.azurerm_client_config.current.client_id

    key_permissions = [
      "create",
      "get",
    ]

    secret_permissions = [
      "set",
      "get",
      "delete",
      "purge",
      "recover"
    ]
  }
}

resource "azurerm_key_vault_secret" "example" {
  name         = "secret-sauce"
  value        = "szechuan"
  key_vault_id = azurerm_key_vault.example.id
}

resource "local_file" "output" {
  filename = "${path.module}/output.txt"
  content = azurerm_key_vault_secret.example.id
}

In this case, if you change value in azurerm_key_vault_secret, output file's content won't change until next time you run apply.

But, there's a walkaround:

data "azurerm_client_config" "current" {}

resource "azurerm_resource_group" "example" {
  name     = "example"
  location = "East Asia"
}

resource "azurerm_key_vault" "example" {
  name                       = "example"
  location                   = azurerm_resource_group.example.location
  resource_group_name        = azurerm_resource_group.example.name
  tenant_id                  = data.azurerm_client_config.current.tenant_id
  sku_name                   = "standard"
  soft_delete_retention_days = 7

  access_policy {
    tenant_id = data.azurerm_client_config.current.tenant_id
    object_id = data.azurerm_client_config.current.client_id

    key_permissions = [
      "create",
      "get",
    ]

    secret_permissions = [
      "set",
      "get",
      "delete",
      "purge",
      "recover"
    ]
  }
}

resource "azurerm_key_vault_secret" "example" {
  name         = "secret-sauce"
  value        = "szechuan"
  key_vault_id = azurerm_key_vault.example.id
}

resource "null_resource" "example" {
  triggers = {
    trigger = azurerm_key_vault_secret.example.value
  }
}

resource "local_file" "output" {
  filename = "${path.module}/output.txt"
  content = null_resource.example.id != "" ? azurerm_key_vault_secret.example.id : ""
}

We can leverage null_resource, especially triggers to "notify" downstream that the id as been changed. In this case, you will see an immediate forces replacement on local-file.

@kensykora
Copy link
Author

but in Plan stage Terraform cannot be aware that

@lonegunmanb Thanks for the reply -- I'm confused, why can't the azurerm_key_vault_secret resource type be aware that if the value changes that a new version id will be created? Seems like that is a rule that can be coded in.

@lonegunmanb
Copy link
Contributor

Hi @kensykora , I think that could be related to how Terraform calculate plan that involved a force new resource's attribute. For now we can use this workaround trick, but we can check if there's issue on Terraform core project. Actually, we can use local_file resource to easily reproduce this issue on our own machine, maybe we can submit an issue along with a minimum sample code there.

@kensykora
Copy link
Author

Hey @lonegunmanb -- I've seen other resources behave differently when they know their upstream dependencies are going to change. For example you see (known after apply) in the terraform output for resources with auto generated properties such as identifiers.

Are you saying it's not possible at all for the plugin to mark the version property of azurerm_key_vault_secret (not the resource id terraform uses!) to be marked as (known after apply) so downstream services that depend on the version to be correct can be correct when it's applied?

@lonegunmanb
Copy link
Contributor

Hi @kensykora , I think the problem we are facing here is, when you change azurerm_key_vault_secret.value, it actually changed the resource's id, that means it created a new resource instance, and I think the other resource which referenced this secret's attribute actually referenced the old instance and it saw nothing changed at all. I've added some extra log in provider's code, when you changed value, the id returned by api changed, it was a new id with new version. I think it's a Terraform core's issue and this plugin has nothing to do about that.

@rcskosir rcskosir added v/2.x (legacy) upstream/terraform This issue is blocked on an upstream issue within Terraform (Terraform Core/CLI, The Plugin SDK etc) labels Jul 28, 2023
@orgads
Copy link
Contributor

orgads commented Oct 24, 2023

Hi @lonegunmanb.

I also faced this issue, and in my case it also causes inconsistent plan issue, when importing a key and changing its value in a single apply.

Is there an issue to track on terraform core?

@orgads
Copy link
Contributor

orgads commented Oct 25, 2023

Reported hashicorp/terraform-plugin-sdk#1267

@restfulhead
Copy link

@orgads The issue was closed and it seems to be possible. Can this be fixed in the provider? I also noticed that adding a new secret version isn't detected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug service/key-vault Key Vault upstream/terraform This issue is blocked on an upstream issue within Terraform (Terraform Core/CLI, The Plugin SDK etc) v/2.x (legacy)
Projects
None yet
Development

No branches or pull requests

6 participants