2
votes

I'm building a terraform template to create Azure resources including Keyvault Secrets. The customer Subscription policy doesn't allow anyone to update/delete/view keyvault secrets.

If I run terraform apply for the first time, it will work perfectly. However, running the same template again will give you the following error: Error:

Error updating Key Vault "####" (Resource Group "####"): keyvault.VaultsClient#Update: Failure responding to request: StatusCode=403 --
Original Error: autorest/azure: Service returned an error. Status=403 Code="RequestDisallowedByPolicy" Message="Resource '###' was disallowed by policy. Policy identifiers: '[{\"policyAssignment\":{\"name\":\"###nis-deny-keyvault-acl\", ...

on ..\..\modules\azure\keyvault\main.tf line 15, in resource "azurerm_key_vault" "keyvault": 
15: resource "azurerm_key_vault" "keyvault" { 
  • How can I get my CI/CD working while that means terraform apply will be continuously running?
  • Is there a way to pass this policy in terraform?
  • Is there a way to prevent terraform from updating KV once it created (other than locking the resource)?

Here is the Keyvault module:

variable "keyvault_id" { 
  type        = string
} 
variable "secrets" { 
  type        = map(string) 
} 


locals { 
  secret_names = keys(var.secrets) 
} 

resource "azurerm_key_vault_secret" "secret" { 
  count        = length(var.secrets) 
  name         = local.secret_names[count.index] 
  value        = var.secrets[local.secret_names[count.index]] 
  key_vault_id = var.keyvault_id 
} 

data "azurerm_key_vault_secret" "secrets" { 
  count        = length(var.secrets) 
  depends_on   = [azurerm_key_vault_secret.secret] 
  name         = local.secret_names[count.index] 
  key_vault_id = var.keyvault_id 
} 

output "keyvault_secret_attributes" { 
  value = [for i in range(length(azurerm_key_vault_secret.secret.*.id)) : data.azurerm_key_vault_secret.secrets[i]] 
} 

And here is the module from my template:

locals { 
  secrets_map = { 
    appinsights-key     = module.app_insights.app_insights_instrumentation_key 
    storage-account-key  = module.storage_account.primary_access_key 
  }
  output_secret_map = { 
    for secret in module.keyvault_secrets.keyvault_secret_attributes : 
    secret.name => secret.id 
  } 
} 

module "keyvault" { 
  source              = "../../modules/azure/keyvault" 
  keyvault_name       = local.kv_name 
  resource_group_name = azurerm_resource_group.app_rg.name 
} 


module "keyvault_secrets" { 
  source      = "../../modules/azure/keyvault-secret" 
  keyvault_id = module.keyvault.keyvault_id 
  secrets     = local.secrets_map 
} 

module "app_service_keyvault_access_policy" { 
  source                  = "../../modules/azure/keyvault-policy" 
  vault_id                = module.keyvault.keyvault_id 
  tenant_id               = module.app_service.app_service_identity_tenant_id 
  object_ids              = module.app_service.app_service_identity_object_ids 
  key_permissions         = ["get", "list"] 
  secret_permissions      = ["get", "list"] 
  certificate_permissions = ["get", "list"] 
} 
2
You need to provide the whole Terraform template code so that we can figure out what is the issue.Charles Xu
@CharlesXu Code for the KV secret module added as well as the module call in the template.Helay
I think your questions do not show what is the real purpose with the Terraform code. The error means your key vault does not set the access policy.Charles Xu

2 Answers

1
votes

Using Terraform for provisioning and managing a keyvault with that kind of limitations sounds like a bad idea. Terraforms main idea is to monitor the state of your resources - if it is not allowed to read the resource it becomes pretty useless. Your problem is not even that Terraform is trying to update something, it fails because it wants to check the current state of your resource and fails.

If your goal is just to create secrets in a keyvault, I would just us the az keyvault commands like this:

az login
az keyvault secret set --name mySecret --vault-name myKeyvault --value mySecretValue

An optimal solution would of course be that your service principal that you use for executing Terrafom commands has the sufficient rights to perform the actions it was created for.

1
votes

I know this is a late answer, but for future visitors:

The pipeline running the Terraform Plan and Apply will need to have proper access to the key vault.

So, if you are running your CI/CD from Azure Pipelines, you would typically have a service connection that your pipeline uses for authentication. The service connection you use for Terraform is most likely based on a service principal that has contributor rights (at least at resource group level) for it to provisioning anything at all.

If that is the case, then you must add a policy giving that same service principal (Use the Service Principals Enterprise Object Id) to have at least list, get and set permissions for secrets.