What if I tell you that it’s possible to connect you AKS pods to an Azure Key Vault using identities but without having to use credentials in an explicit way?

Well with AAD Pod Identities you can enable your Kubernetes applications to access Azure cloud resources securely using Azure Active Directory (AAD) including Azure Key Vault.

Did you knoe that using POd Idenities is a best practice? Check the docs here

The following gist show a PowerShell script that will help you setup everything inside your RBAC enabled AKS cluster. You will also need to have Azure CLI installed on your box and an Azure Key Vault deployed in the same resource group where your AKS lives.

 1param(
 2  [string]
 3  [Parameter(Mandatory = $true)]
 4  $resourceGroupName,
 5  [string]
 6  [Parameter(Mandatory = $true)]
 7  $identityName,
 8  [string]
 9  [Parameter(Mandatory = $true)]
10  $identitySelector,
11  [string]
12  [Parameter(Mandatory = $true)]
13  $aksName,
14  [string]
15  [Parameter(Mandatory = $true)]
16  $keyVaultName 
17)
18
19# Get the current subscription
20$subscriptionId = (az account show | ConvertFrom-Json).id
21
22# Get aks so we can extract it's Service Princpal later
23$aks = az aks show `
24  -g $resourceGroupName `
25  -n $aksName | ConvertFrom-Json
26
27# Create Managed Identity
28$identity = az identity create `
29  -g $resourceGroupName `
30  -n $identityName `
31  -o json | ConvertFrom-Json
32
33# Assign the Reader role to the Managed Identity
34az role assignment create `
35  --role "Reader" `
36  --assignee $identity.principalId `
37  --scope /subscriptions/$subscriptionId/resourcegroups/$resourceGroupName
38
39# Assign the Managed Identity Operator role to the AKS Service Principal
40az role assignment create `
41  --role "Managed Identity Operator" `
42  --assignee $aks.servicePrincipalProfile.clientId `
43  --scope $identity.id
44
45# Add policy to the Key Vault so the Managed Identity can read secrets
46az keyvault set-policy `
47  --name $keyVaultName `
48  --spn $identity.clientId `
49  --secret-permissions get list
50
51# Enable AAD Pod Identity on AKS
52kubectl apply -f https://raw.githubusercontent.com/Azure/aad-pod-identity/master/deploy/infra/deployment-rbac.yaml
53
54# Create the Azure Identity and AzureIdentityBinding yaml on the fly
55$k8sAzureIdentityandBinding = @"
56apiVersion: "aadpodidentity.k8s.io/v1"
57kind: AzureIdentity
58metadata:
59  name: $($identityName)
60spec:
61  type: 0
62  ResourceID: $($identity.id)
63  ClientID: $($identity.clientId)
64---
65apiVersion: "aadpodidentity.k8s.io/v1"
66kind: AzureIdentityBinding
67metadata:
68  name: $($identityName)-identity-binding
69spec:
70  AzureIdentity: $($identityName)
71  Selector: $($identitySelector)
72"@
73
74# Deploy the yamls 
75$k8sAzureIdentityandBinding | kubectl apply -f -

The script creates a Manged Identity, assigns some permissions to it and creates a policy inside the Key Vault enabling the Identity to list and get secrets.

Then the Managed Identity Controller (MIC) deployment and the Node Managed Identity (NMI) daemon set are deployed inside the cluster.

In the last step, two resources are deployed. The first one is an AzureIdentity that will be used to identify the Managed Identity inside your cluster and the second one is an AzureIdentityBinding that binds the azure Identity with a Selector.

Let’s run the PowerShell command with the following parameters:

  • Resource Group: myResourceGroup
  • Managed Identity Name: myId
  • Identity Selector: requires-vault
  • AKS Name: myAKS
  • Key Vault Name: myKeyVault
1.\SetupPodIdentityKeyVaultIntegration.ps1 myResourceGroup myId requires-vault myAKS myKeyVault

Once the command is done, any pod marked with the aadpodidbinding: requires-vault label will get an Identity assigned.

To check that everything is working as expected you can create a deployment.yaml with the following contents:

 1---
 2apiVersion: apps/v1beta1
 3kind: Deployment
 4metadata:
 5  name: az-keyvault-reader-test
 6spec:
 7  replicas: 1
 8  template:
 9    metadata:
10      labels:
11        app: az-keyvault-reader-test
12        aadpodidbinding: requires-vault
13    spec:
14      containers:
15        - name: busybox
16          image: busybox
17          command:
18            [
19              "sh",
20              "-c",
21              "wget --tries=70 -qO- http://127.0.0.1:8333/secrets/<SECRET_NAME>/",
22            ]
23          imagePullPolicy: Always
24          resources:
25            requests:
26              memory: "4Mi"
27              cpu: "100m"
28            limits:
29              memory: "8Mi"
30              cpu: "200m"
31        - name: az-keyvault-reader-sidecar
32          image: cmendibl3/az-keyvault-reader:0.2
33          imagePullPolicy: Always
34          env:
35            - name: AZURE_KEYVAULT_NAME
36              value: <AZURE_KEYVAULT_NAME>
37          resources:
38            requests:
39              memory: "8Mi"
40              cpu: "100m"
41            limits:
42              memory: "16Mi"
43              cpu: "200m"
44      restartPolicy: Always

Note: Replace the values for <AZURE_KEYVAULT_NAME> with the name of your Key Vault and <SECRET_NAME> with the name of an existing secret stored in your Key Vault:

Now deploy to Kubernetes:

1kubectl apply -f ./deployment.yaml

and check the logs for the busybox pod:

1kubectl logs -f $(kubectl get po --selector=app=az-keyvault-reader-test -o jsonpath='{.items[*].metadata.name}') -c busybox -w

If everything is OK you should see the value of your secret dumped in the logs (Bad security practice here)!!! And yes you did all this without knowing any credentials!

Please find the code used to connect to the Azure KeyVault here: az-keyvault-reader.go and check AAD Pod Identity for more information on how this “magic” works.

Hope it helps!