I'm deploying an Azure Application Gateway in Terraform and I want to store my SSL private certificate for the https between Internet and my App-gtw in an Azure Key Vault. The code, omitting useless information in the application gateway module, is:
module "agw_user_assigned_identity" {
source = "../modules/resources-blocks/user_assigned_identity"
user_assigned_identity_name = "agw-user-signed-id"
resource_group_name = module.resource_group.name
resource_group_location = module.resource_group.location
}
module "key_vault" {
source = "../modules/resources/key_vault"
key_vault_name = local.key_vault_name
resource_group_location = module.resource_group.location
resource_group_name = module.resource_group.name
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = module.agw_user_assigned_identity.id
soft_delete_retention_days = 90
log_analytics_workspace_id = module.log_analytics_workspace.id
enable_diagnostic_setting = true
}
module "key_vault_private_certificate" {
source = "../modules/resources-blocks/key_vault_certificate"
key_vault_id = module.key_vault.id
certificate_name = local.agw_certificate_name
certificate_path = "./certificates/xxxxx.pfx"
certificate_password = var.SSL_CERTIFICATE_PASSWORD
}
resource "null_resource" "previous" {}
module "agw_time_sleep" {
source = "../modules/resources-blocks/time_sleep"
select_module = module.key_vault
seconds = "200s"
}
module "application_gateway" {
source = "../modules/resources-hub/application_gateway"
resource_group_name = module.resource_group.name
resource_group_location = module.resource_group.location
application_gateway_name = local.agw_name
key_vault_private_certificate_id = module.key_vault_private_certificate.certificate_id
key_vault_private_certificate_id = azurerm_key_vault_certificate.kv_certificate.secret_id
ssl_certificate_name = local.agw_certificate_name
agw_time_sleep = module.agw_time_sleep.id
frontend_ports = [
{
name = "myFrontendPort"
port = 443
}
]
http_listeners = [
{
name = "devListener"
frontend_ip_configuration = local.frontend_ip_configuration_name
frontend_port_name = "myFrontendPort"
protocol = "Https"
hostname = "xxxxxxxxxxxxx.be"
ssl_certificate_name = local.agw_certificate_name
}
]
}
The key_vault resource is:
resource "azurerm_key_vault" "kv" {
name = var.key_vault_name
location = var.resource_group_location
resource_group_name = var.resource_group_name
enabled_for_disk_encryption = true
tenant_id = var.tenant_id
soft_delete_retention_days = var.soft_delete_retention_days
purge_protection_enabled = false
sku_name = "standard"
access_policy {
tenant_id = var.tenant_id
object_id = var.object_id
key_permissions = ["Get", "List", "Update", "Create", "Import", "Delete", "Recover", ]
secret_permissions = ["Get", "List", "Set", "Delete", "Recover", "Backup", "Restore", "Purge"]
storage_permissions = ["Get", "Set", "Delete", "Recover", "Backup", "Restore"]
certificate_permissions = ["Get", "List", "Update", "Create", "Import", "Delete", "Recover", "Backup", "Restore", "Purge"]
}
lifecycle {
ignore_changes = [access_policy]
}
}
The key_vault_certificate resource is:
resource "azurerm_key_vault_certificate" "kv_certificate" {
name = var.certificate_name
key_vault_id = var.key_vault_id
certificate {
contents = filebase64(var.certificate_path)
password = var.certificate_password
}
certificate_policy {
issuer_parameters {
name = "Self"
}
key_properties {
exportable = true
key_size = 2048
key_type = "RSA"
reuse_key = false
}
secret_properties {
content_type = "application/x-pkcs12"
}
}
}
The application gateway resource is (omitting useless information):
resource "azurerm_application_gateway" "app_gw" {
name = var.application_gateway_name
resource_group_name = var.resource_group_name
location = var.resource_group_location
identity {
type = "UserAssigned"
identity_ids = [var.user_assigned_identity_id]
}
ssl_certificate {
name = var.ssl_certificate_name
key_vault_secret_id = var.key_vault_private_certificate_id
}
dynamic "http_listener" {
for_each = var.http_listeners
content {
name = http_listener.value.name
frontend_ip_configuration_name = http_listener.value.frontend_ip_configuration
frontend_port_name = http_listener.value.frontend_port_name
protocol = http_listener.value.protocol
host_name = http_listener.value.hostname
firewall_policy_id = var.firewall_policy_id
ssl_certificate_name = http_listener.value.ssl_certificate_name
}
}
depends_on = [var.agw_time_sleep]
}
The error that I get when I use the command terraform plan -var-file="variables.tfvars" is:
Error: expected "access_policy.0.object_id" to be a valid UUID, got /subscriptions/xxxxxxxx/resourceGroups/xxxxxxxxx/providers/Microsoft.ManagedIdentity/userAssignedIdentities/agw-user-signed-id
│
│ with azurerm_key_vault.kv,
│ on main.tf line 344, in resource "azurerm_key_vault" "kv":
│ 344: object_id = module.agw_user_assigned_identity.id
Apparently seems that the problem is related to the object_id that I specify in the key_vault, but I don't know how to solve it.
Error: expected "access_policy.0.object_id" to be a valid UUID .......
with azurerm_key_vault.kv,
│ on main.tf line 344, in resource "azurerm_key_vault" "kv":
│ 344: object_id = module.agw_user_assigned_identity.id
This means that in your resource azurerm_key_vault
in the access_policy
block the object_id
attribute is getting the incorrect value more simply the incorrect value that azure API accepts for it.
It expects the principal_id
output from the azurerm_user_assigned_identity
resource in spite of id
.
in azure id
would be the URI of the resource itself in azure namespaces /subscriptions/<sub-id>/resourceGroups/<resource-group-name>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<resource-name>
So you need principal_id
output in your module module.agw_user_assigned_identity
and then use it in your key_vault module as follows
## inside module.agw_user_assigned_identity add an output , ignore if already exists
output "principal_id" {
value = azurerm_user_assigned_identity.base.principal_id
description = "Set accordingly or from terraform documentation"
}
## then use the above the output in key_vault module
module "key_vault" {
source = "../modules/resources/key_vault"
key_vault_name = local.key_vault_name
resource_group_location = module.resource_group.location
resource_group_name = module.resource_group.name
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = module.agw_user_assigned_identity.principal_id
soft_delete_retention_days = 90
log_analytics_workspace_id = module.log_analytics_workspace.id
enable_diagnostic_setting = true
}
That will solve the above error message.