Here's a Kubernetes manifest document for using Azure Key Vault in a deployment. It includes a SecretProviderClass that fetches secrets from Key Vault and makes them available to pods as environment variables. The values are templated using Helm, so you can dynamically substitute them based on your environment.

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: {{ .Values.env }}-secrets-provider
  namespace: {{ .Values.env }}-app
spec:
  provider: azure
  parameters:
    usePodIdentity: "false"
    useVMManagedIdentity: "true"  # Enable Managed Identity
    userAssignedIdentityID: {{ .Values.managedIdentityClientId }}
    keyvaultName: {{ .Values.keyVaultName }}  # Azure Key Vault name
    objects: |
      array:
        - |
          objectName: {{ .Values.env }}-database-url
          objectType: secret
          objectVersion: ""
        - |
          objectName: {{ .Values.env }}-api-key
          objectType: secret
          objectVersion: ""
        - |
          objectName: {{ .Values.env }}-storage-connection
          objectType: secret
          objectVersion: ""
    tenantId: {{ .Values.tenantId }}  # Azure Directory (Tenant) ID
  secretObjects:
    - secretName: {{ .Values.env }}-app-secrets
      type: Opaque
      data:
        - objectName: {{ .Values.env }}-database-url
          key: DATABASE_URL
        - objectName: {{ .Values.env }}-api-key
          key: API_KEY
        - objectName: {{ .Values.env }}-storage-connection
          key: STORAGE_CONNECTION_STRING

Usage in Deployment Manifest

Modify your deployment YAML to use the secrets via valueFrom:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.env }}-app
  namespace: {{ .Values.env }}-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: {{ .Values.env }}-app
  template:
    metadata:
      labels:
        app: {{ .Values.env }}-app
    spec:
      volumes:
        - name: secrets-store
          csi:
            driver: secrets-store.csi.k8s.io
            readOnly: true
            volumeAttributes:
              secretProviderClass: {{ .Values.env }}-secrets-provider
      containers:
        - name: app-container
          image: your-app-image:latest
          env:
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: {{ .Values.env }}-app-secrets
                  key: DATABASE_URL
            - name: API_KEY
              valueFrom:
                secretKeyRef:
                  name: {{ .Values.env }}-app-secrets
                  key: API_KEY
            - name: STORAGE_CONNECTION_STRING
              valueFrom:
                secretKeyRef:
                  name: {{ .Values.env }}-app-secrets
                  key: STORAGE_CONNECTION_STRING
          volumeMounts:
            - name: secrets-store
              mountPath: "/mnt/secrets"
              readOnly: true


How It Works

  1. Secrets are fetched from Azure Key Vault via the SecretProviderClass.

  2. CSI driver syncs them as Kubernetes secrets.

  3. Deployment references those secrets to inject them as environment variables.