Azure Kubernetes Service KeyVault access via Workload Identity
When accessing Azure Key Vault from Azure Kubernetes Service, one of the ways available to do so is through the use of a Workload Identity. A Workload Identity in Azure works by allowing the pods in your Azure Kubernetes cluster assume an existing Managed Identity so that they can gain access to other resources such Azure KeyVault. More so, it allows your application in AKS to authenticate with Azure EntraId (AAD) successfully for resources that require it.
Here is what we will do with our app on Azure Kubernetes Service to read and write values to KeyVault:
- Enable OpenID Connect and Workload Identity on the AKS cluster. These 2 are essentially addons available on the AKS cluster (Your AKS cluster MUST have Kubernetes version 1.25 or higher to use Workload Identity)
- Create a new Managed Identity and Federate this identity
- Assign Get and Set permissions on the Azure KeyVault for the Managed Identity by using an Access Policy. Note that using an RBAC Role of 'KeyVault Secrets Officer' for the Managed Identity can also be correct although this gives further permissions beyond the scope of this blog post (expand higher for your needs where needed)
- Associate the Managed Identity to the Pod(s) via the Service Account YAML
- Deploy the Service Account and Deployment YAML in our deployment process
- Access KeyVault via application code (.NET 6 Web App) using the DefaultAzureCredential class
Enable OpenID Connect and Workload Identity on AKS cluster
Using the Azure CLI, run the following commands:
What you should get after running the update to the cluster is a large json response confirming the update. Crucially this json will show us that Workload Identity has been enabled:
And that OpenIdConnect is enabled too:
Create a new Managed Identity in Azure
Now we can create a managed identity via the Azure CLI as follows:
After creating the Managed Identity, keep a note of the ClientId seen in the response json here as we will need it in the next sections. (If not, you can always view it in you Azure EntraId (AAD) by searching the name you made for it in Azure EntraId where this ClientId is shown as the ApplicationId there)
Next, assign the rights of being able to read and write secrets of a known KeyVault to this Managed Identity by assigning an Access Policy for Get and Set permissions on Secrets:
After you get a json response back, you can confirm in KeyVault itself in the portal under Access Policies:
Now you need to set a Federated Credential for your Managed Identity. The Federated Identity will make sure that a Federated Token is provided by the time it is required by the Workload Identity.
Let's create a Federated Credential for the Managed Identity in the Portal:
From the Portal Home, Search Managed Identity, [Your_ManagedIdentityFor_AKS]>Settings>Federated credentials> Add Credential. Set the scenario to 'Kubernetes accessing Azure Resources':
Here, you will need your Cluster Issuer URL. Use the following command to see this Issuer URL:
Then add this Issuer URL (including the "/" at the end!!) as the Cluster Issuer URL:
The Service Account will be a Name of our AKS Service Account which we will set in the following section
Then choose a Name for your Federated Credential Name, leave the Audience unchanged, then click Add.
We will now associate this Managed Identity to our Service Account YAML next so our pods know which Identity to use when application code requiring KeyVault runs.
AKS Service Account YAML Configuration for Workload Identity
We can have a YAML of the kind 'ServiceAccount', that contains an annotation of our Managed Identity:
Then, we can write our deployment YAML and Service YAML bundled together as follows:
You can deploy to Azure Kubernetes Service via the following:
You can also run your YAML scripts through your CI/CD pipeline, but regardless, you should end up seeing the External IP address of the LoadBalancer under Services in your AKS instance.
Your application running in Azure Kubernetes should be able to access KeyVault using its application code as normal where your app code uses it.
The next section is optional and provides sample reference code for demonstration purposes.
Application Code Reference
Here is some quick example C# code that can be containerised in the context of an ASP.NET web app we would then use to write and read from our KeyVault using the DefaultAzureCredential class:
Where the View code is simple as:
Example Docker File:
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["AKSVaultConnect/AKSVaultConnect.csproj", "AKSVaultConnect/"]
RUN dotnet restore "./AKSVaultConnect/AKSVaultConnect.csproj"
COPY . .
WORKDIR "/src/AKSVaultConnect"
RUN dotnet build "./AKSVaultConnect.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./AKSVaultConnect.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "AKSVaultConnect.dll"]
The Expected result would be as follows after deploying the service as a LoadBalancer on an Azure Kubernetes Service instance, and behold, the application is setting and getting a secret in Azure KeyVault:
REMEMBER TO DELETE THE AKS RESOURCE AFTER USING!!