8.2. Solution #2
flowchart LR
user --> |insert|keyvault
subgraph azure
keyvault
end
keyvault <--> |access|external-secrets
subgraph aks
external-secrets --> |create|secret
endPreparation
Use the existing directory from chapter 6.1
cd $LAB_ROOT/azure
Step 8.2.1: keyvault.tf
Hints
resource "random_integer" "keyvault" {
min = 10000
max = 99999
}
resource "azurerm_key_vault" "aks" {
name = "kv${replace(local.infix, "-", "")}${random_integer.acr.result}"
location = var.location
resource_group_name = azurerm_resource_group.default.name
tenant_id = "79b79954-f1b6-4d8b-868d-7c22edee3e00"
sku_name = "standard"
network_acls {
bypass = "AzureServices"
default_action = "Allow"
}
purge_protection_enabled = true
soft_delete_retention_days = 7
rbac_authorization_enabled = true
}
resource "azurerm_role_assignment" "ourself" {
scope = azurerm_key_vault.aks.id
role_definition_name = "Key Vault Secrets Officer"
principal_id = data.azuread_group.aks_admins.object_id
}
resource "azurerm_user_assigned_identity" "podid" {
name = "aks-podid"
resource_group_name = azurerm_resource_group.default.name
location = var.location
}
resource "azurerm_role_assignment" "podid_access" {
scope = azurerm_key_vault.aks.id
role_definition_name = "Key Vault Secrets User"
principal_id = azurerm_user_assigned_identity.podid.principal_id
}
resource "azurerm_federated_identity_credential" "federated" {
name = "aks-federated-credential"
resource_group_name = azurerm_resource_group.default.name
audience = ["api://AzureADTokenExchange"]
issuer = azurerm_kubernetes_cluster.aks.oidc_issuer_url
parent_id = azurerm_user_assigned_identity.podid.id
subject = "system:serviceaccount:workload:keyvault"
}
output "vault_uri" {
value = azurerm_key_vault.aks.vault_uri
}
output "identity" {
value = azurerm_user_assigned_identity.podid.client_id
}
Step 8.2.2: external-secrets.tf
Hints
resource "kubernetes_namespace" "external-secrets" {
metadata {
name = "external-secrets"
}
}
resource "helm_release" "external-secrets" {
name = "external-secrets"
namespace = kubernetes_namespace.external-secrets.id
repository = "https://charts.external-secrets.io"
chart = "external-secrets"
version = "1.3.1"
atomic = true
reset_values = true
timeout = 900
depends_on = [ azurerm_kubernetes_cluster.aks ]
}
Step 8.2.3: secret.yaml
Hints
---
apiVersion: v1
kind: Namespace
metadata:
name: workload
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: keyvault
namespace: workload
annotations:
azure.workload.identity/client-id: # azurerm_user_assigned_identity.podid.client_id ^^
azure.workload.identity/tenant-id: 79b79954-f1b6-4d8b-868d-7c22edee3e00
---
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
name: azure-store
namespace: workload
spec:
provider:
azurekv:
authType: WorkloadIdentity
vaultUrl: # azurerm_key_vault.aks.vault_uri ^^ (no slash in the end!)
serviceAccountRef:
name: keyvault
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: demo
namespace: workload
spec:
refreshInterval: 1h
secretStoreRef:
name: azure-store
kind: SecretStore
target:
name: supersecret
creationPolicy: Owner
data:
- secretKey: supersecret
remoteRef:
key: supersecret