Retrieve secrets and credentials from Azure Key Vault in AKS
This guide requires version 1.10.2 or later of the Helm chart.
In this guide, we'll walk through how to retrieve secrets and credentials from Azure Key Vault in an Azure Kubernetes Service (AKS) cluster.
This guide assumes you completed the first step of Deploy a Dagster+ agent on an Azure Kubernetes Service cluster.
Prerequisites
To complete the steps in this guide, you'll need:
- The Azure CLI installed on your machine. You can download it here.
- kubectlinstalled on your machine. You can download it here.
- helminstalled on your machine. You can download it here.
- A functional AKS cluster and Dagster+ agent running on it. If you have not yet set up an AKS agent, you can look up Deploy an Azure Kubernetes Service (AKS) agent guide.
Step 1: Enable the Azure Key Vault provider for the AKS cluster
To deploy the AKS Secrets store CSI drivers and providers, run the following command:
az aks enable-addons --resource-group <resource-group> --name <cluster-name> --addons azure-keyvault-secrets-provider
You can validate that both components are running by checking the pods in the kube-system namespace:
kubectl get pods -n kube-system -l 'app in (secrets-store-csi-driver,secrets-store-provider-azure)' -o wide
Each node should have a pod of aks-secrets-store-csi-driver and secrets-store-provider-azure running.
Step 2: Create an Azure Key Vault
Create the Azure Key Vault with RBAC authorization enabled:
az keyvault create -n <vault-name> -g <resource-group> --enable-rbac-authorization
Add yourself with the role to manage the keys in the secret vault:
az role assignment create --role 'Key Vault Administrator' --assignee '<your identity>' --scope '/subscriptions/<subscription_id>/resourceGroups/<resource_group>'
Step 3: Store the Dagster Cloud Agent Token in the Key Vault
Grant the AKS cluster access to the Key Vault:
export CLIENT_ID=$(az identity show -g <resource-group> -n <agent-identity> --query 'clientId' -otsv)
export KEYVAULT_SCOPE=$(az keyvault show --name <vault-name> --query id -o tsv)
az role assignment create --role "Key Vault Secrets User" --assignee $CLIENT_ID --scope $KEYVAULT_SCOPE
See the Azure built-in roles for Key Vault.
Step 4: Create and access the Dagster Cloud Agent Token from your Key Vault
Create a secret in the Azure Key Vault to store the Dagster Cloud Agent Token:
az keyvault secret set --name dagsterAgentToken --vault-name <vault-name> --value <dagster-token>
Create the secret provider class to retrieve the secret from the Key Vault:
export CLIENT_ID=$(az identity show -g <resource-group> -n <agent-identity> --query 'clientId' -otsv)
export KEYVAULT_NAME=<vault-name>
export IDENTITY_TENANT=$(az aks show --name <aks-cluster> --resource-group <resource-group> --query identity.tenantId -o tsv)
# write the secret provider manifest to a file
cat <<EOF > dagster-token-secret-provider.yaml
# This is a SecretProviderClass example using workload identity to access your key vault
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: azure-kv-dagster-agent-token # needs to be unique per namespace
spec:
  provider: azure
  parameters:
    usePodIdentity: "false"
    clientID: "${CLIENT_ID}" # Setting this to use workload identity
    keyvaultName: ${KEYVAULT_NAME}       # Set to the name of your key vault
    cloudName: ""                         # [OPTIONAL for Azure] if not provided, the Azure environment defaults to AzurePublicCloud
    objects:  |
      array:
        - |
          objectName: dagsterAgentToken   # Set to the name of your secret
          objectType: secret              # object types: secret, key, or cert
          objectVersion: ""               # [OPTIONAL] object versions, default to latest if empty
    tenantId: "${IDENTITY_TENANT}"        # The tenant ID of the key vault
  # (optional) Allows mounting the secret as an environment variable in a pod
  secretObjects:
  - data:
    - key: dagsterAgentToken
      objectName: dagsterAgentToken
    secretName: dagster
    type: Opaque
EOF
# apply the secret provider manifest
kubectl apply -f dagster-token-secret-provider.yaml
You can verify that the secret provider is working by creating a pod that uses the secret provider.
This example provides three ways of exposing a secret in a pod.
cat <<EOF > pod-test-akv-secret-mount.yaml
kind: Pod
apiVersion: v1
metadata:
  name: test-akv-secret-mount
  labels:
    azure.workload.identity/use: "true"
spec:
  serviceAccountName: "user-cloud-dagster-cloud-agent"
  containers:
    - name: busybox
      image: registry.k8s.io/e2e-test-images/busybox:1.29-4
      command:
        - "/bin/sleep"
        - "10000"
      # This will mount the secret as /mnt/secrets-store/dagsterAgentToken
      volumeMounts:
      - name: secrets-store01-inline
        mountPath: "/mnt/secrets-store"
        readOnly: true
      # This will expose the secret as an environment variable named DAGSTER_CLOUD_AGENT_TOKEN
      env:
      - name: DAGSTER_CLOUD_AGENT_TOKEN
        valueFrom:
          secretKeyRef:
            name: dagster
            key: dagsterAgentToken
      # This will expose all the secrets from the secret provider as environment variables name as the secret names
      envFrom:
      - secretRef:
          name: dagster
  volumes:
    - name: secrets-store01-inline
      csi:
        driver: secrets-store.csi.k8s.io
        readOnly: true
        volumeAttributes:
          secretProviderClass: "azure-kv-dagster-agent-token"
EOF
# Create the test pod
kubectl apply -f pod-test-akv-secret-mount.yaml
# Each of these commands should print value of the secret
kubectl exec -it test-akv-secret-mount -- cat /mnt/secrets-store/dagsterAgentToken
kubectl exec -it test-akv-secret-mount -- echo $DAGSTER_CLOUD_AGENT_TOKEN
kubectl exec -it test-akv-secret-mount -- echo $dagsterAgentToken
# clean up
kubectl delete pod test-akv-secret-mount
Step 5: Modify your AKS deployment to use the Dagster+ token from the Key Vault
Modify the following sections of your values.yaml file.
a) update the dagsterCloud section:
This will ensure the agent token is provided and expected as the environment variable dagsterAgentToken.
# values.yaml
dagsterCloud:
  agentTokenSecretName: dagster
  agentTokenEnvVarName: dagsterAgentToken
  # ...
b) add these entries to the dagsterCloudAgent section:
Required for the csi driver to mount the secret into the agent pod.
# values.yaml
dagsterCloudAgent:
  volumeMounts:
    - name: dagster-token
      mountPath: /mnt/dagster-token
      readOnly: true
  volumes:
    - name: dagster-token
      csi:
        driver: secrets-store.csi.k8s.io
        readOnly: true
        volumeAttributes:
          secretProviderClass: 'azure-kv-dagster-agent-token'
c) add these entries to the workspace:
This ensures the secret is also made available to the pods the agent will create to run your code.
# values.yaml
envSecrets:
  - name: dagster
    optional: false
volumeMounts:
  - name: dagster-token
    mountPath: /mnt/dagster-token
    readOnly: true
volumes:
  - name: dagster-token
    csi:
      driver: secrets-store.csi.k8s.io
      readOnly: true
      volumeAttributes:
        secretProviderClass: 'azure-kv-dagster-agent-token'
d) optionally, you could manage the secret provider within your helm values file by providing it as an extra manifest, instead of provisioning it separately:
# values.yaml
extraManifests:
  # This is a SecretProviderClass example using workload identity to access your key vault
  - apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: azure-kv-dagster-agent-token # needs to be unique per namespace
    spec:
      provider: azure
      parameters:
        usePodIdentity: 'false'
        clientID: '${CLIENT_ID}' # Setting this to use workload identity
        keyvaultName: ${KEYVAULT_NAME} # Set to the name of your key vault
        cloudName: '' # [OPTIONAL for Azure] if not provided, the Azure environment defaults to AzurePublicCloud
        objects: |
          array:
            - |
              objectName: dagsterAgentToken   # Set to the name of your secret
              objectType: secret              # object types: secret, key, or cert
              objectVersion: ""               # [OPTIONAL] object versions, default to latest if empty
        tenantId: '${IDENTITY_TENANT}' # The tenant ID of the key vault
      # (optional) Allows mounting the secret as an environment variable in a pod
      secretObjects:
        - data:
            - key: dagsterAgentToken
              objectName: dagsterAgentToken
          secretName: dagster
          type: Opaque
Finally, update your deployment with the new values:
helm upgrade -n <dagster-namespace> user-cloud dagster-cloud/dagster-cloud-agent -f ./values.yaml
You can verify that the agent is running by looking at its status in the Dagster+ UI at this address:
https://<org_name>.dagster.plus/<deployment>/deployment/health
By re-using the same steps to create other secret provider, volume mounts, and optionally environment variables configuration, you can also load other secrets and credentials from the Azure Key Vault to use in your Dagster+ code projects.