Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
The Azure Key Vault Secret Store extension for Kubernetes (SSE) automatically synchronizes secrets from an Azure Key Vault to an Azure Arc-enabled Kubernetes cluster for offline access. This means you can use Azure Key Vault to store, maintain, and rotate your secrets, even when running your Kubernetes cluster in a semi-disconnected state. Synchronized secrets are stored in the cluster secret store, making them available as Kubernetes secrets to be used in all the usual ways: mounted as data volumes, or exposed as environment variables to a container in a pod.
Synchronized secrets are critical business assets, so the SSE secures them through isolated namespaces, role-based access control (RBAC) policies, and limited permissions for the synchronization controller. For extra protection, encrypt the Kubernetes secret store on your cluster.
This article shows you how to install and configure the SSE as an Azure Arc-enabled Kubernetes extension.
Tip
The SSE is recommended for clusters outside of Azure cloud where connectivity to Azure Key Vault may not be perfect. SSE by its nature creates copies of your secrets in the Kubernetes secrets store. If you prefer to avoid creating local copies of secrets and your cluster has perfect connectivity to Azure Key Vault, then you can use the online-only Azure Key Vault Secrets Provider extension for secret access in your Arc-enabled Kubernetes clusters. It is not recommended to run both the online Azure Key Vault Secrets Provider extension and the offline SSE side-by-side in the same cluster.
Prerequisites
- An Arc-enabled cluster. This can be one that you connected to yourself (this guide assumes a K3s cluster, and provides guidance on how to Arc-enable it.) or a Microsoft-managed AKS enabled by Azure Arc cluster. The cluster must be running Kubernetes version 1.27 or higher.
- Ensure you meet the general prerequisites for cluster extensions, including the latest version of the
k8s-extensionAzure CLI extension. - cert-manager is required to support TLS for intracluster log communication. The examples later in this guide direct you though installation. For more information about cert-manager, see cert-manager.io
Install the Azure CLI and sign in, if you haven't already:
az login
Before you begin, set environment variables to be used for configuring Azure and cluster resources. If you already have a managed identity, Azure Key Vault, or other resource listed here, update the names in the environment variables to reflect those resources. Note that the KEYVAULT_NAME must be globally unique; keyvault creation will fail later if this name is already in use within Azure.
export RESOURCE_GROUP="AzureArcTest"
export CLUSTER_NAME="AzureArcTest1"
export LOCATION="EastUS"
export SUBSCRIPTION="$(az account show --query id --output tsv)"
export AZURE_TENANT_ID="$(az account show -s $SUBSCRIPTION --query tenantId --output tsv)"
export CURRENT_USER="$(az ad signed-in-user show --query userPrincipalName --output tsv)"
export KEYVAULT_NAME="my-UNIQUE-kv-name"
export KEYVAULT_SECRET_NAME="my-secret"
export USER_ASSIGNED_IDENTITY_NAME="my-identity"
export FEDERATED_IDENTITY_CREDENTIAL_NAME="my-credential"
export KUBERNETES_NAMESPACE="my-namespace"
export SERVICE_ACCOUNT_NAME="my-service-account"
Create the resource group if necessary:
az group create --name ${RESOURCE_GROUP} --___location ${LOCATION}
Activate workload identity federation in your cluster
The SSE uses a feature called workload identity federation to access and synchronize Azure Key Vault secrets. This section describes how to set the feature up. The following sections will explain how it's used in detail.
Tip
The following steps are based on the How-to guide for configuring Arc-enabled Kubernetes with workload identity federation. Refer to that documentation for any additional assistance.
If your cluster isn't yet connected to Azure Arc, follow these steps. During these steps, enable workload identity federation as part of the connect command:
az connectedk8s connect --name ${CLUSTER_NAME} --resource-group ${RESOURCE_GROUP} --enable-oidc-issuer
If your cluster is already connected to Azure Arc, enable workload identity using the update command:
az connectedk8s update --name ${CLUSTER_NAME} --resource-group ${RESOURCE_GROUP} --enable-oidc-issuer
Now configure your cluster to issue service account tokens with a new issuer URL (service-account-issuer) that enables Microsoft Entra ID to find the public keys necessary for it to validate these tokens. These public keys are for the cluster's own service account token issuer, and they were obtained and cloud-hosted at this URL as a result of the --enable-oidc-issuer option that you set earlier.
Optionally, you can also configure limits on the SSE's own permissions as a privileged resource running in the control plane by configuring OwnerReferencesPermissionEnforcement admission controller. This admission controller constrains how much the SSE can change other objects in the cluster.
Configure your kube-apiserver with the issuer URL field and permissions enforcement. The following example is for a k3s cluster. Your cluster may have different means for changing API server arguments:
--kube-apiserver-arg="--service-account-issuer=${SERVICE_ACCOUNT_ISSUER}",--kube-apiserver-arg=service-account-max-token-expiration=24hand--kube-apiserver-arg="--enable-admission-plugins=OwnerReferencesPermissionEnforcement".Get the service account issuer URL.
export SERVICE_ACCOUNT_ISSUER="$(az connectedk8s show --name ${CLUSTER_NAME} --resource-group ${RESOURCE_GROUP} --query "oidcIssuerProfile.issuerUrl" --output tsv)" echo $SERVICE_ACCOUNT_ISSUERUpdate the API server arguments in the K3s cluster's config file.
cat <<EOF > /tmp/k3s-config.yaml kube-apiserver-arg: - 'service-account-issuer=${SERVICE_ACCOUNT_ISSUER}' - 'service-account-max-token-expiration=24h' - 'enable-admission-plugins=OwnerReferencesPermissionEnforcement' EOF sudo mv /tmp/k3s-config.yaml /etc/rancher/k3s/config.yaml
Restart your kube-apiserver.
sudo systemctl restart k3s(optional) Verify the service account issuer has been configured correctly:
kubectl cluster-info dump | grep service-account-issuer
Create a secret and configure an identity to access it
To access and synchronize a given Azure Key Vault secret, the SSE requires access to an Azure managed identity with appropriate Azure permissions to access that secret. The managed identity must be linked to a Kubernetes service account using the workload identity feature that you activated earlier. The SSE uses the associated federated Azure managed identity to pull secrets from Azure Key Vault to your Kubernetes secret store. The following sections describe how to set this up.
Create an Azure Key Vault
Create an Azure Key Vault and add a secret. If you already have an Azure Key Vault and secret, you can skip this section.
Create an Azure Key Vault:
az keyvault create --resource-group "${RESOURCE_GROUP}" --___location "${LOCATION}" --name "${KEYVAULT_NAME}" --enable-rbac-authorizationGive yourself 'Secrets Officer' permissions on the vault, so you can create a secret:
az role assignment create --role "Key Vault Secrets Officer" --assignee ${CURRENT_USER} --scope /subscriptions/${SUBSCRIPTION}/resourcegroups/${RESOURCE_GROUP}/providers/Microsoft.KeyVault/vaults/${KEYVAULT_NAME}Create a secret and update it so you have two versions:
az keyvault secret set --vault-name "${KEYVAULT_NAME}" --name "${KEYVAULT_SECRET_NAME}" --value 'Hello!' az keyvault secret set --vault-name "${KEYVAULT_NAME}" --name "${KEYVAULT_SECRET_NAME}" --value 'Hello2'
Create a user-assigned managed identity
Next, create a user-assigned managed identity and give it permissions to access the Azure Key Vault. If you already have a managed identity with Key Vault Reader and Key Vault Secrets User permissions to the Azure Key Vault, you can skip this section. For more information, see Create a user-assigned managed identity and Using Azure RBAC secret, key, and certificate permissions with Key Vault.
Create the user-assigned managed identity:
az identity create --name "${USER_ASSIGNED_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}" --___location "${LOCATION}" --subscription "${SUBSCRIPTION}"Give the identity Key Vault Reader and Key Vault Secrets User permissions. You may need to wait a moment for replication of the identity creation before these commands succeed:
export USER_ASSIGNED_CLIENT_ID="$(az identity show --resource-group "${RESOURCE_GROUP}" --name "${USER_ASSIGNED_IDENTITY_NAME}" --query 'clientId' -otsv)" az role assignment create --role "Key Vault Reader" --assignee "${USER_ASSIGNED_CLIENT_ID}" --scope /subscriptions/${SUBSCRIPTION}/resourcegroups/${RESOURCE_GROUP}/providers/Microsoft.KeyVault/vaults/${KEYVAULT_NAME} az role assignment create --role "Key Vault Secrets User" --assignee "${USER_ASSIGNED_CLIENT_ID}" --scope /subscriptions/${SUBSCRIPTION}/resourcegroups/${RESOURCE_GROUP}/providers/Microsoft.KeyVault/vaults/${KEYVAULT_NAME}
Create a federated identity credential
Create a Kubernetes service account for the workload that needs access to secrets. Then, create a federated identity credential to link between the managed identity, the OIDC service account issuer, and the Kubernetes service account.
Create a Kubernetes service account that will be federated to the managed identity. Annotate it with details of the associated user-assigned managed identity.
kubectl create ns ${KUBERNETES_NAMESPACE}cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: name: ${SERVICE_ACCOUNT_NAME} namespace: ${KUBERNETES_NAMESPACE} EOFCreate a federated identity credential:
az identity federated-credential create --name ${FEDERATED_IDENTITY_CREDENTIAL_NAME} --identity-name ${USER_ASSIGNED_IDENTITY_NAME} --resource-group ${RESOURCE_GROUP} --issuer ${SERVICE_ACCOUNT_ISSUER} --subject system:serviceaccount:${KUBERNETES_NAMESPACE}:${SERVICE_ACCOUNT_NAME} --audience api://AzureADTokenExchange
Install the SSE
The SSE is available as an Azure Arc extension. An Azure Arc-enabled Kubernetes cluster can be extended with Azure Arc-enabled Kubernetes extensions. Extensions enable Azure capabilities on your connected cluster and provide an Azure Resource Manager-driven experience for the extension installation and lifecycle management.
cert-manager and trust-manager are also required for secure communication of logs between cluster services and must be installed before the Arc extension.
Install cert-manager.
helm repo add jetstack https://charts.jetstack.io/ --force-update helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set crds.enabled=trueInstall trust-manager.
helm upgrade trust-manager jetstack/trust-manager --install --namespace cert-manager --waitInstall the SSE to your Arc-enabled cluster using the following command:
az k8s-extension create \ --cluster-name ${CLUSTER_NAME} \ --cluster-type connectedClusters \ --extension-type microsoft.azure.secretstore \ --resource-group ${RESOURCE_GROUP} \ --name ssarcextension \ --scope clusterIf desired, you can optionally modify the default rotation poll interval by adding
--configuration-settings rotationPollIntervalInSeconds=<time_in_seconds>(see configuration reference).
Configure the SSE
Configure the installed extension with information about your Azure Key Vault and which secrets to synchronize to your cluster by defining instances of Kubernetes custom resources.
SSE can be configured with a single simplified resource designed to suit most use cases, or the SSE internal components can be configured directly via two resources. The simplified configuration is a preview feature and may benefit from minor changes in upcoming versions. The direct configuration style will remain available for all deployments.
The easiest way to configure SSE is to create an AKVSync custom resource. This resource captures details about your AKV instance, which secrets to fetch, and where to put them in Kubernetes' secret store.
cat <<EOF > akvsync.yaml
kind: AKVSync
apiVersion: secret-sync.x-k8s.io/v1alpha1
metadata:
name: my-akv-secrets
namespace: ${KUBERNETES_NAMESPACE}
spec:
keyvaultName: ${KEYVAULT_NAME}
clientID: "${USER_ASSIGNED_CLIENT_ID}"
tenantID: "${AZURE_TENANT_ID}"
serviceAccountName: ${SERVICE_ACCOUNT_NAME}
objects:
- secretInAKV: ${KEYVAULT_SECRET_NAME}
EOF
See AKVSync reference for additional configuration guidance.
Apply the configuration
Apply the configuration custom resource (CR) using the kubectl apply command:
kubectl apply -f ./akvsync.yaml
When an AKVSync configuration is applied SSE automatically generates equivalent direct configuration resources. Do not modify the autogenerated SecretSync and SecretProviderClass resources, they will be updated as needed automatically.
The SSE automatically looks for the secrets and begins syncing them to the cluster.
Observe secrets synchronizing to the cluster
Once the configuration is applied, secrets begin syncing to the cluster automatically at the cadence specified when installing the SSE.
View synchronized secrets
View the secrets synchronized to the cluster by running the following command:
# View a list of all secrets in the namespace
kubectl get secrets -n ${KUBERNETES_NAMESPACE}
Tip
Add -o yaml or -o json to change the output format of kubectl get and kubectl describe commands.
View secret value
To view the synchronized secret value, now stored in the Kubernetes secret store, use the following command:
kubectl get secret <NAME> -n ${KUBERNETES_NAMESPACE} -o jsonpath="{.data.v0}" | base64 -d && echo
<NAME> is ${KEYVAULT_SECRET_NAME} if using the simplified configuration example, or secret-sync-name if using the direct configuration example.
Troubleshooting
See the troubleshooting guide for assistance diagnosing and resolving issues.
Remove the SSE
To remove the SSE and stop synchronizing secrets, uninstall it with the az k8s-extension delete command:
az k8s-extension delete --name ssarcextension --cluster-name $CLUSTER_NAME --resource-group $RESOURCE_GROUP --cluster-type connectedClusters
Uninstalling the extension doesn't remove secrets or CRDs (AKVSync, SecretSync, or SecretProviderClass) from the cluster. These objects must be removed directly with kubectl.
By default, deleting SecretSync or AKVSync resource removes all secrets defined within them, but secrets may persist if:
- You modified ownership of any of the secrets.
- You changed the garbage collection settings in your cluster, including setting different finalizers.
In these cases, secrets must be deleted directly using kubectl.
Next steps
- Learn more about Azure Arc extensions.
- Learn more about Azure Key Vault.
- Help to protect your cluster in other ways by following the guidance in the security book for Azure Arc-enabled Kubernetes.