Secrets Store CSI with Azure Kubernetes and Azure KeyVault

Overview

This repo is a walkthrough of using the Kubernetes Secrets Store CSI Driver as a mechanism to get secret contents stored in Azure Key Vault instance and use the Secret Store CSI driver interface to mount them into Kubernetes pods.

In this repo you can find a containerized Go sample app (deployed with Helm) running in an AKS cluster (provisioned with ARM templates), all setup with a Github Actions workflow. The workflow includes steps to:

The Azure Key Vault provider of the CSI driver offers 4 modes for accessing a KeyVault instance (Service Principal, Pod Identity, User-assigned Managed Identity, and System-assigned Managed Identity), this sample focused on using the User-assigned Managed Identity.

Here is the folder structure:

  • .github\workflows
    • devops-workflow.yml - Github Actions Pipelines yaml file
  • Application
    • charts
      • sampleapp - Helm chart for sample app
      • secret-provider-class - Helm chart for Secrets Store Provider Class
    • app.go - Go sample app
    • Dockerfile - Dockerfile for the sample app
  • ArmTemplates - Arm Templates for provisioning aks, acr and application insights

Accessing the Key vault

Azure Key vault provider for Secrets Store CSI driver allows you to access secrets stored in an Azure Key vault instance. The Secrets Store CSI driver secrets-store.csi.k8s.io allows the cluster to mount secrets stored in Azure Key vault into the pods as a volume.

A SecretProviderClass custom resource is created in the defined namespace to provide Azure-specific parameters for the Secrets Store CSI driver.

To ensure the sample app is able to access the secrets stored in the provisioned Azure Key vault, the deployment.yaml is updated to use secrets-store.csi.k8s.io driver and the SecretProviderClass created is referenced as shown in the snippet below.

spec:
  volumes:
    - name: secrets-mount
      csi:
        driver: secrets-store.csi.k8s.io
        readOnly: true
        volumeAttributes:
          secretProviderClass: "azure-keyvault"

While the infrastructure deployments and using Secrets Store CSI with Azure Kubernetes and Azure KeyVault steps are all automated in the devops-workflow.yml, here is an Azure documentation Secrets Store CSI with Azure Kubernetes and Azure KeyVault that describes a manual walkthrough.

Getting Started

Prerequisites

  • Azure CLI: Create and manage Azure resources.
  • Kubectl: Kubernetes command-line tool which allows you to run commands against Kubernetes clusters.
  • GitHub account

Set up

  1. Fork the repo to your github account and git clone.

  2. Create a resource group that will hold all the provisioned resources and a service principal to manage and access those resources

    # Set your variables
    RESOURCEGROUPNAME="MyResourceGroup"
    LOCATION="MyLocation"
    SUBSCRIPTIONID="MySubscriptionId"
    SERVICEPRINCIPALNAME="MyServicePrincipalName"
    
    # Create resource group
    az group create --name $RESOURCEGROUPNAME --location $LOCATION
    
    # Create a service principal with Contributor role to the resource group
    az ad sp create-for-rbac --name $SERVICEPRINCIPALNAME --role Contributor --scopes /subscriptions/$SUBSCRIPTIONID/resourceGroups/$RESOURCEGROUPNAME --sdk-auth
    
  3. Use the json output of the last command as a secret named AZURE_CREDENTIALS in the repository settings (Settings -> Secrets -> Add New Secret).

    Also add a secret named AZURE_SUBSCRIPTIONID for the subscription id and a secret named AZURE_TENANTID for the tenant id.

    action-secrets

    For more details on generating the deployment credentials please see this guide.

  4. Github Actions will be used to automate the workflow and deploy all the necessary resources to Azure. Open the .github\workflows\devops-workflow.yml and change the environment variables accordingly. Update the RESOURCEGROUPNAME variable and set the value that you created above.

  5. Commit your changes. The commit will trigger the build and deploy jobs within the workflow and will provision all the resources to run the sample application.

Validate the Secrets

To validate that the secrets are mounted to the sampleapp pod in the AKS cluster from Azure KeyVault as specified in the deployment yaml.

- mountPath: "mnt/secrets-store"
  name: secrets-mount
  readOnly: true

Note: The expected secrets should be test-secret-value.

# Define variables
RESOURCEGROUPNAME="<insert-resource-group-name-here>"
CLUSTERNAME="<insert-cluster-name-here>"
NAMESPACE="<insert-sampleapp-namespace-name-here>"

# Connect to Cluster
az aks get-credentials --resource-group $RESOURCEGROUPNAME --name $CLUSTERNAME

# Get a pod name the app is running on
PODNAME=$(kubectl get pod -l app=sampleapp -o jsonpath="{.items[0].metadata.name}" -n $NAMESPACE)

# Exec into the pod
kubectl exec -it $PODNAME -n $NAMESPACE -- bash

# Verify the secrets
cd /mnt/secrets-store/
cat test-secret; echo