Skip to content
Assign Azure Active Directory Identities to kubernetes applications.
Branch: master
Clone or download
cpuguy83 and khenidak Fix vm type parsing (#176)
* Use go modules

This fixes issues with CI just using `go get` or having to fetch
external tools (such as `dep`).
The issue with ci using `go get` (without using go modules) is it
fetches the master/HEAD from the upstream repo which can easily (and
currently is) break.

* Fix vm type parsing

Before if the cluster config was vmss but the machine type was a vm, it
would still use a vmss.
Latest commit 59768ac Mar 19, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci Use go modules (#179) Mar 19, 2019
charts/aad-pod-identity Keep binary arg in helm charts (#155) Feb 8, 2019
cmd namespaced identities (#140) Jan 29, 2019
deploy Keep binary arg in helm charts (#155) Feb 8, 2019
docs Removed duplicate words and fixed typos (#92) Sep 24, 2018
images/identityvalidator Make Jenkinsfile more versatile (#150) Jan 30, 2019
pkg Fix vm type parsing (#176) Mar 19, 2019
scripts Make Jenkinsfile more versatile (#150) Jan 30, 2019
test Assert AzureAssignedIdentity properties Oct 29, 2018
Dockerfile Use go modules (#179) Mar 19, 2019
Makefile Use go modules (#179) Mar 19, 2019 fix a typo: reponse -> response (#171) Mar 8, 2019
azure-pipeline.yml Change the build to run 'make build' for azure pipeline (#158) Feb 6, 2019
go.mod Use go modules (#179) Mar 19, 2019
go.sum Use go modules (#179) Mar 19, 2019


Applications running on the POD on Azure Container Service (AKS/ACS Engine) require access to identities in Azure Active Directory (AAD)to access resources that use an identity provider. AAD provides a construct called a Service Principal that allows applications to assume identities with limited permissions, and Managed Service Identity (MSI) - automatically generated and rotated credentials that easily retrieved by an application at run-time to authenticate as a service principal. An cluster admin configures the Azure Identity Binding to the Pod. Without any change of auth code the application running on the pod works on the cluster.


The detailed design of the project can be found in the following docs:

Managed Identity Controller (MIC)

This controller watches for pod changes through the api server and caches pod to admin configured azure identity map.

Node Managed Identity (NMI)

The authorization request of fetching Service Principal Token from MSI endpoint is sent to a standard Instance Metadata endpoint which is redirected to the NMI pod by adding ruled to redirect POD CIDR traffic with metadata endpoint IP on port 80 to be sent to the NMI endpoint. The NMI server identifies the pod based on the remote address of the request and then queries the k8s (through MIC) for a matching azure identity. It then make a adal request to get the token for the client id and returns as a response to the request. If the request had client id as part of the query it validates it againsts the admin configured client id.

Similarly a host can make an authorization request to fetch Service Principal Token for a resource directly from the NMI host endpoint ( The request must include the pod namespace podns and the pod name podname in the request header and the resource endpoint of the resource requesting the token. The NMI server identifies the pod based on the podns and podname in the request header and then queries k8s (through MIC) for a matching azure identity. Then nmi makes a adal request to get a token for the resource in the request, returns the token and the clientid as a response to the request.

An example curl command:

curl -H "podname: nginx-flex-kv-int" -H "podns: default"

Demo Pod

Pod fetching Service Principal Token from MSI endpoint

spt, err := adal.NewServicePrincipalTokenFromMSI(msiEndpoint, resource)

Pod using identity to Azure Resource Manager (ARM) operation by doing seamless authorization

import ""

authorizer, err := auth.NewAuthorizerFromEnvironment()
if err != nil {
	logger.Errorf("failed NewAuthorizerFromEnvironment  %+v", authorizer)
vmClient := compute.NewVirtualMachinesClient(subscriptionID)
vmClient.Authorizer = authorizer
vmlist, err := vmClient.List(context.Background(), resourceGroup)

Get Started


A running k8s cluster on Azure using AKS or ACS Engine

Deploy the azure-aad-identity infra

Deploy the infrastructure with the following command to deploy MIC, NMI, and the MIC CRDs.

kubectl create -f

Pod Identity requires two components:

  1. Managed Identity Controller (MIC). A pod that binds Azure Ids to other pods - creates azureAssignedIdentity CRD.
  2. Node Managed Identity (NMI). Identifies the pod based on the remote address of the incoming request, and then queries k8s (through MIC) for a matching Azure Id. It then makes an adal request to get the token for the client id and returns as a reponse to the request. Implemented as a DaemonSet.

If you have RBAC enabled, use the following deployment instead:

kubectl create -f

Create User Azure Identity

Get the client id and resource id for the identity

az identity create -g <resourcegroup> -n <managedidentity-resourcename>

Assign Reader Role to new Identity

Using the principalid from the last step, assign reader role to new identity for this resource group

az role assignment create --role Reader --assignee <principalid> --scope /subscriptions/<subscriptionid>/resourcegroups/<resourcegroup>

Providing required permissions for MIC

This step is only required if you are using User assigned MSI.

MIC uses the service principal credentials stored within the the AKS cluster to access azure resources. This service principal needs to have Microsoft.ManagedIdentity/userAssignedIdentities/*/assign/action permission on the identity for usage with User assigned MSI. If your identity is created in the same resource group as that of the AKS nodes (typically this resource group is prefixed with 'MC_' string and is automatically generated when you create the cluster), you can skip the next steps.

  1. Find the service principal used by your cluster - please refer the AKS docs to figure out the service principle app Id. For example, if your cluster uses automatically generated service principal, the ~/.azure/aksServicePrincipal.json file in the machine from which you created the AKS cluster has the required information.

  2. Assign the required permissions - the following command can be used to assign the required permission:

az role assignment create --role "Managed Identity Operator" --assignee <sp id> --scope <full id of the managed identity>

Install User Azure Identity on k8s cluster

Edit and save this as aadpodidentity.yaml

Set type: 0 for User Assigned MSI; type: 1 for Service Principal

apiVersion: ""
kind: AzureIdentity
 name: <a-idname>
 type: 0
 ResourceID: /subscriptions/<subid>/resourcegroups/<resourcegroup>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<managedidentity-resourcename>
 ClientID: <clientid>
kubectl create -f aadpodidentity.yaml

Understanding Namespaced identities

The system will match pod to identity across namespaces by default. This behavior can be modified to match to pods within the namespace that holds AzureIdentity by

  1. On Azure Identity bases, by addinging namespaced annotation (You have to add the annotation on each AzureIdentity you want to apply this behavior on).
  2. Default namespaced behavior on all identities by adding --forceNamespaced=true argument on the command line or declare FORCENAMESPACED=true environment variable (for both nmi and mic).

Install Pod to Identity Binding on k8s cluster

Edit and save this as aadpodidentitybinding.yaml. Note the AzureIdentity name must match the one chosen in aadpodidentity.yaml.

apiVersion: ""
kind: AzureIdentityBinding
 name: demo1-azure-identity-binding
 AzureIdentity: <a-idname>
 Selector: <label value to match>
kubectl create -f aadpodidentitybinding.yaml

The name of the identity which we created earlier needs to be filled in AzureIdentity. For a pod to match a binding, it should have a label with the key 'aadpodidbinding' whose value matches the Selector field in the binding above.

Here an example pod with the label specified:

$ kubectl get po busybox0 --show-labels
busybox0   1/1       Running   10         10h       aadpodidbinding=select_it,app=busybox0

This pod will match the binding below:

apiVersion: ""
kind: AzureIdentityBinding
  name: test-azure-id-binding
  AzureIdentity: "test-azure-identity"
  Selector: "select_it"

Demo app

To deploy the demo app, ensure you have completed the above prerequisite steps!

Update the deploy/demo/deployment.yaml arguments with your subscription, clientID and resource group. Make sure your identity with the client ID has reader permission to the resource group provided in the input.

kubectl create -f deploy/demo/deployment.yaml

There's also a detailed tutorial here.


This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit

When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact with any additional questions or comments.

You can’t perform that action at this time.