Your AKS pods can directly access secrets stored in Azure Key Vault, avoiding the need to bake them into container images or manage them as Kubernetes Secrets.

Let’s see it in action. Imagine you have a database connection string stored in Key Vault.

Here’s a secret in Key Vault:

Secret Name: MyDbConnectionString
Value: Server=tcp:mydbserver.database.windows.net,1433;Initial Catalog=mydb;Persist Security Info=False;User ID=myuser;Password=mypassword;

Now, let’s deploy a pod that uses this secret. We’ll need a few things:

  1. An Azure Key Vault: With the secret already created.
  2. An Azure Kubernetes Service (AKS) cluster: And your kubectl configured to point to it.
  3. A Managed Identity for your AKS cluster: This identity will be granted permission to read secrets from your Key Vault.

First, create a Managed Identity for your AKS cluster if you haven’t already. You can do this during cluster creation or add it to an existing cluster. For an existing cluster, you’ll use the Azure CLI:

az aks update --resource-group <your-aks-resource-group> --name <your-aks-cluster-name> --enable-managed-identity

This command associates a system-assigned managed identity with your AKS cluster. You can find its object ID with:

az aks show --resource-group <your-aks-resource-group> --name <your-aks-cluster-name> --query "identity.principalId" -o tsv

Next, grant this managed identity permission to access your Key Vault. Navigate to your Key Vault in the Azure portal, go to "Access policies," and click "Create." Select "Get" and "List" under "Secret permissions," and then choose the managed identity of your AKS cluster.

Now, we need to install the Azure Key Vault CSI driver on your AKS cluster. This driver allows Kubernetes to mount Key Vault secrets as volumes.

az aks addon enable --resource-group <your-aks-resource-group> --name <your-aks-cluster-name> --addons azure-keyvault-secrets-provider

This command installs the CSI driver and its associated components.

Once the CSI driver is installed, you can define a SecretProviderClass Kubernetes resource. This object tells the CSI driver which secrets to fetch from Key Vault and how to expose them to your pods.

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: akv-secrets-provider
spec:
  provider: azure
  parameters:
    usePodIdentity: "true" # Use the pod's identity (which is the AKS cluster's managed identity)
    keyvaultName: <your-keyvault-name>
    objects: |
      array:
        - |
          objectName: MyDbConnectionString
          objectType: secret
          objectAlias: db-connection-string # This is the name it will have inside the pod
    secretRotation:
      enabled: true
      rotationPollInterval: "2h"

Apply this manifest to your cluster:

kubectl apply -f secretproviderclass.yaml

Finally, create your pod manifest. You’ll add a volume definition that references your SecretProviderClass and a volume mount to make the secret available inside the container.

apiVersion: v1
kind: Pod
metadata:
  name: my-app-with-secret
spec:
  containers:
  - name: my-container
    image: nginx # Replace with your actual application image
    ports:
    - containerPort: 80
    volumeMounts:
    - name: secrets-store-inline
      mountPath: "/mnt/secrets-store"
      readOnly: true
  volumes:
  - name: secrets-store-inline
    csi:
      driver: secrets-store.csi.k8s.io
      readOnly: true
      volumeAttributes:
        secretProviderClass: "akv-secrets-provider"

Apply this pod manifest:

kubectl apply -f pod.yaml

When the pod starts, the Key Vault CSI driver will detect the volumeAttributes.secretProviderClass and, using the AKS cluster’s managed identity, fetch the MyDbConnectionString secret from Key Vault. It will then create a temporary file at /mnt/secrets-store/db-connection-string inside your container, containing the secret’s value.

The truly surprising part is that the secret isn’t exposed as a Kubernetes Secret object at all. Instead, the CSI driver directly mounts the secret’s value as a file into the pod’s filesystem. This means Kubernetes RBAC never has to manage permissions for the secret itself, only for the SecretProviderClass which is a much simpler, less sensitive object.

Your application can then read the connection string from the file /mnt/secrets-store/db-connection-string.

The next step is to explore how to manage secret rotation and how to handle multiple secrets from a single Key Vault.

Want structured learning?

Take the full Aks course →