Python on AKS¶
This guide walks through containerizing a Python FastAPI application and deploying it to Azure Kubernetes Service (AKS). You'll implement a production-ready pattern using Microsoft Entra Workload Identity and the Azure Key Vault Secrets Store CSI Driver.
Prerequisites¶
- An existing AKS cluster with the following features enabled:
- OIDC Issuer and Workload Identity
- Azure Key Vault Secrets Store CSI Driver add-on
- Azure Container Registry (ACR) for hosting your container images.
- Local tools: Azure CLI, Docker (or similar), and
kubectl. - Environment variables set from previous labs:
$RG,$CLUSTER_NAME,$LOCATION,$ACR_NAME,$KEYVAULT_NAME.
What You'll Build¶
You will deploy the Python Reference App, a minimal FastAPI service that:
- Retrieves a secret from Azure Key Vault without using connection strings.
- Uses a non-root container image for improved security.
- Scales automatically based on CPU utilization.
- Exposes an endpoint via a Kubernetes Service and Ingress.
Build and Deployment Flow¶
flowchart TD
START[Local Python Code] --> DOCKER[Build Docker Image]
DOCKER --> PUSH[Push to ACR]
PUSH --> AUTH[Configure Workload Identity]
AUTH --> MANIFEST[Apply K8s Manifests]
MANIFEST --> RUN[Pod Mounts Secret via CSI]
RUN --> VERIFY[Verify Endpoint] Steps¶
1. Explore the Application¶
The reference app is located in apps/python/. It uses FastAPI to expose a /secret endpoint that checks for a mounted secret file.
- Source: apps/python/src/main.py
- Container: apps/python/Dockerfile
- Manifests: apps/python/manifests/
2. Build and Push the Image¶
Navigate to the application directory and use Azure Container Registry to build your image. This avoids the need for a local Docker installation if you use az acr build.
# Set image variables
export IMAGE_NAME="aks-keyvault-csi-sample"
export IMAGE_TAG="0.1.0"
# Build and push using ACR Task
az acr build \
--registry "$ACR_NAME" \
--image "$IMAGE_NAME:$IMAGE_TAG" \
../../apps/python/
| Command | Purpose |
|---|---|
az acr build | Build and push the container image using an ACR Task. |
--registry | Azure Container Registry that runs the build. |
--image | Image name and tag to produce. |
3. Configure Workload Identity¶
The application needs a User-Assigned Managed Identity (UAMI) to access Key Vault.
export IDENTITY_NAME="keyvault-reader-uami"
# Create the identity
az identity create \
--resource-group "$RG" \
--name "$IDENTITY_NAME" \
--location "$LOCATION"
# Get identity metadata
export UAMI_CLIENT_ID="$(az identity show --resource-group "$RG" --name "$IDENTITY_NAME" --query "clientId" --output tsv)"
export IDENTITY_PRINCIPAL_ID="$(az identity show --resource-group "$RG" --name "$IDENTITY_NAME" --query "principalId" --output tsv)"
export TENANT_ID="$(az account show --query "tenantId" --output tsv)"
# Establish federation with the Kubernetes ServiceAccount
export OIDC_ISSUER="$(az aks show --resource-group "$RG" --name "$CLUSTER_NAME" --query "oidcIssuerProfile.issuerUrl" --output tsv)"
az identity federated-credential create \
--resource-group "$RG" \
--identity-name "$IDENTITY_NAME" \
--name aks-python-federation \
--issuer "$OIDC_ISSUER" \
--subject system:serviceaccount:workload:keyvault-reader \
--audience api://AzureADTokenExchange
| Command | Purpose |
|---|---|
az identity create | Create the user-assigned managed identity. |
--resource-group | Resource group that contains the identity. |
--name | Name of the managed identity. |
--location | Azure region for the identity. |
az identity show | Read the identity client and principal IDs. |
--resource-group | Resource group that contains the identity. |
--name | Name of the managed identity. |
--query | Selects the client ID or principal ID. |
--output | Output format for the result. |
az account show | Read the current subscription tenant ID. |
--query | Selects the tenant ID. |
--output | Output format for the result. |
az aks show | Read the cluster OIDC issuer URL. |
--resource-group | Resource group that contains the AKS cluster. |
--name | Name of the AKS cluster. |
--query | Selects the OIDC issuer URL. |
--output | Output format for the result. |
az identity federated-credential create | Federate the identity with the Kubernetes service account. |
--resource-group | Resource group that contains the identity. |
--identity-name | Managed identity to federate. |
--name | Name of the federated credential. |
--issuer | OIDC issuer URL of the cluster. |
--subject | Kubernetes service account subject to trust. |
--audience | Token audience for the federation. |
4. Grant Key Vault Permissions¶
Authorize the identity to read secrets from your Key Vault.
export KEYVAULT_ID="$(az keyvault show --name "$KEYVAULT_NAME" --query "id" --output tsv)"
az role assignment create \
--assignee-object-id "$IDENTITY_PRINCIPAL_ID" \
--assignee-principal-type ServicePrincipal \
--role "Key Vault Secrets User" \
--scope "$KEYVAULT_ID"
| Command | Purpose |
|---|---|
az keyvault show | Read the Key Vault resource ID for the role scope. |
--name | Name of the Key Vault. |
--query | Selects the Key Vault resource ID. |
--output | Output format for the result. |
az role assignment create | Grant the identity access to Key Vault secrets. |
--assignee-object-id | Object ID of the identity to grant. |
--assignee-principal-type | Principal type of the assignee. |
--role | Role to assign. |
--scope | Resource scope the role applies to. |
5. Deploy Manifests¶
Update the placeholders in the provided manifests and apply them to your cluster.
# Create the namespace first
kubectl apply \
--filename ../../apps/python/manifests/namespace.yaml
# Apply the remaining manifests
# Note: You must replace <UAMI_CLIENT_ID>, <KEYVAULT_NAME>, <TENANT_ID>, <ACR_NAME>, and <APP_HOSTNAME> in the files first.
kubectl apply \
--filename ../../apps/python/manifests/
Environment and Configuration¶
The sample keeps non-secret runtime settings in the pod spec and secret material in Azure Key Vault.
PYTHONUNBUFFERED=1is set through the Deploymentenv:block so Python writes logs directly to stdout and stderr.- Secret values stay out of the manifest and are mounted from Azure Key Vault through the Secrets Store CSI Driver.
- If you need non-secret application settings beyond simple environment variables, add a ConfigMap and mount or reference it from the Deployment.
Verification¶
1. Check Pod Status¶
Ensure the pods are running and the secret is mounted correctly.
2. Health Probes¶
The Deployment already defines HTTP probes against the FastAPI endpoints in apps/python/manifests/deployment.yaml:
- Readiness probe:
GET /readyzon porthttp,initialDelaySeconds: 5,periodSeconds: 10 - Liveness probe:
GET /healthzon porthttp,initialDelaySeconds: 10,periodSeconds: 10
Readiness determines when the pod is added to Service endpoints, while liveness tells the kubelet when the container should be restarted after it becomes unhealthy.
3. Review Logs and Metrics¶
Use pod logs for workload-level verification and Container Insights or Azure Monitor metrics for cluster-level behavior.
In Azure Monitor, confirm that Container Insights is collecting pod and node metrics so you can watch CPU usage, restart counts, and request health during rollout validation.
4. Test the Secret Endpoint¶
Use kubectl port-forward to access the application locally and verify it can see the secret mounted from Key Vault.
In a separate terminal:
Expected response:
Next Steps¶
- Scale the App: Check the HorizontalPodAutoscaler to see how the app scales under load.
- Implement Ingress: Configure your DNS to point to the Ingress controller to access the app via its hostname.
- Review Security: Explore Best Practices: Security for more on pod security standards.
See Also¶
Sources¶
- https://learn.microsoft.com/en-us/azure/aks/workload-identity-deploy-cluster
- https://learn.microsoft.com/en-us/azure/aks/csi-secrets-store-driver
- https://learn.microsoft.com/en-us/azure/aks/learn/quick-kubernetes-deploy-cli
- https://learn.microsoft.com/en-us/azure/aks/best-practices-app-cluster-reliability
- https://learn.microsoft.com/en-us/azure/aks/monitor-aks
- https://learn.microsoft.com/en-us/azure/azure-monitor/containers/container-insights-overview