hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.6k stars 4.64k forks source link

Cannot add new access policy when key_vault_secret resources are active but not permitted #17495

Open kalzun opened 2 years ago

kalzun commented 2 years ago

Is there an existing issue for this?

Community Note

Terraform Version

1.2.4

AzureRM Provider Version

3.12.0

Affected Resource(s)/Data Source(s)

azurerm_key_vault, azurerm_key_vault_access_policy, azurerm_key_vault_secret

Terraform Configuration Files

resource "azurerm_key_vault" "kv" {
  name                       = "kvexample"
  resource_group_name        = azurerm_resource_group.rg.name
  tenant_id                  = data.azurerm_client_config.current.tenant_id
  soft_delete_retention_days = 90
  purge_protection_enabled   = false

  sku_name = "standard"
}

resource "azurerm_key_vault_access_policy" "user" {
  key_vault_id = azurerm_key_vault.kv.id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = data.azurerm_client_config.current.object_id

  secret_permissions = [
    "Get",
    "Set",
    "List",
  ]
}

resource "azurerm_key_vault_secret" "secret" {
  name         = "secretname"
  value        = "secretvalue"
  key_vault_id = azurerm_key_vault.kv.id

  depends_on = [azurerm_key_vault_access_policy.user]
}

Debug Output/Panic Output

Error: making Read request on Azure KeyVault Secret secret: keyvault.BaseClient#GetSecret: Failure responding to request: StatusCo
de=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="Forbidden" Message="The user, group or applicat
ion 'appid=(appid);oid=(aad user oid);numgroups=xx;iss=https://sts.windows.net/1aa
sa4/' does not have secrets get permission on key vault 'kvexample'. For help resol
ving this issue, please see https://go.microsoft.com/fwlink/?linkid=2125287" InnerError={"code":"AccessDenied"}

Expected Behaviour

When updating azurerm_key_vault_access_policy (or access policy in azurerm_key_vault) for a new object_id, and using: depends_on = [ azurerm_key_vault_access_policy ], it should set access policy for this object_id before checking whether it has permission to read existing azurerm_key_vault_secret.

Actual Behaviour

Failing due to not having read permissions on existing azurerm_key_vault_secrets.

Steps to Reproduce

I have written this test to reproduce it. See new object_id in azurerm_key_vault_access_policy in withExternalAccessPolicyUpdateDifferentObjectId, which is the reason for failing.

Add the following to key_vault_secret_resource_test.go.

func TestAccKeyVaultSecret_withExternalAccessPolicyDependsOnFail(t *testing.T) {
    data := acceptance.BuildTestData(t, "azurerm_key_vault_secret", "test")
    r := KeyVaultSecretResource{}

    data.ResourceTest(t, r, []acceptance.TestStep{
        {
            Config: r.withExternalAccessPolicy(data),
            Check: acceptance.ComposeTestCheckFunc(
                check.That(data.ResourceName).ExistsInAzure(r),
            ),
        },
        data.ImportStep(),
        {
            Config: r.withExternalAccessPolicyUpdateDifferentObjectId(data),
            Check: acceptance.ComposeTestCheckFunc(
                check.That(data.ResourceName).ExistsInAzure(r),
            ),
        },
        data.ImportStep(),
    })
}

func (KeyVaultSecretResource) withExternalAccessPolicyUpdate(data acceptance.TestData) string {
    return fmt.Sprintf(`
provider "azurerm" {
  features {}
}

data "azurerm_client_config" "current" {
}

resource "azurerm_resource_group" "test" {
  name     = "acctestRG-%d"
  location = "%s"
}

resource "azurerm_key_vault" "test" {
  name                       = "acctestkv-%s"
  location                   = azurerm_resource_group.test.location
  resource_group_name        = azurerm_resource_group.test.name
  tenant_id                  = data.azurerm_client_config.current.tenant_id
  sku_name                   = "standard"
  soft_delete_retention_days = 7

  tags = {
    environment = "Production"
  }
}

resource "azurerm_key_vault_access_policy" "test" {
  key_vault_id = azurerm_key_vault.test.id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = data.azurerm_client_config.current.object_id
  key_permissions = [
    "Create",
    "Get",
  ]
  secret_permissions = [
    "Set",
    "Get",
    "Delete",
    "Purge",
    "Recover"
  ]
}

resource "azurerm_key_vault_secret" "test" {
  name         = "secret-%s"
  value        = "rick-and-morty"
  key_vault_id = azurerm_key_vault.test.id
  depends_on   = [azurerm_key_vault_access_policy.test]
}
`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString)
}

func (KeyVaultSecretResource) withExternalAccessPolicyUpdateDifferentObjectId(data acceptance.TestData) string {
    return fmt.Sprintf(`
provider "azurerm" {
  features {}
}

data "azurerm_client_config" "current" {
}

resource "azurerm_resource_group" "test" {
  name     = "acctestRG-%d"
  location = "%s"
}

resource "azurerm_key_vault" "test" {
  name                       = "acctestkv-%s"
  location                   = azurerm_resource_group.test.location
  resource_group_name        = azurerm_resource_group.test.name
  tenant_id                  = data.azurerm_client_config.current.tenant_id
  sku_name                   = "standard"
  soft_delete_retention_days = 7

  tags = {
    environment = "Production"
  }
}

resource "azurerm_key_vault_access_policy" "test" {
  key_vault_id = azurerm_key_vault.test.id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = "different-uuid"
  key_permissions = [
    "Create",
    "Get",
  ]
  secret_permissions = [
    "Set",
    "Get",
    "Delete",
    "Purge",
    "Recover"
  ]
}

resource "azurerm_key_vault_secret" "test" {
  name         = "secret-%s"
  value        = "rick-and-morty"
  key_vault_id = azurerm_key_vault.test.id
  depends_on   = [azurerm_key_vault_access_policy.test]
}
`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString)
}

Important Factoids

I discovered this when sharing the project to another developer, who of course gets their object_id, and not the one I had set when creating the resource initially.

References

No response

sinbai commented 2 years ago

@kalzun thanks for opening this issue. Could you add the create_before_destroy = true in azurerm_key_vault_access_policy block like below to see if the error goes away?

resource "azurerm_key_vault_access_policy" "test" {
  key_vault_id = azurerm_key_vault.test.id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = "different-uuid"
  key_permissions = [
    "Create",
    "Get",
  ]
  secret_permissions = [
    "Set",
    "Get",
    "Delete",
    "Purge",
    "Recover"
  ]

  lifecycle {
    create_before_destroy = true
  }
}
kalzun commented 2 years ago

Thank you for the suggestion. I tried adding the block as mentioned -- it still fails, with same error message as before.

keyvault.BaseClient#GetSecret: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: 
Service returned an error. Status=403 Code="Forbidden" Message="The user, group or application 'appid=000;oid=000;
iss=https://sts.windows.net/000/' does not have secrets get permission on key vault 'acctestkv;location=eastus'. 
For help resolving this ssue, please see https://go.microsoft.com/fwlink/?linkid=2125287" 
InnerError={"code":"AccessDenied"}