sigs.k8s.io/cluster-api-provider-azure@v1.17.0/docs/book/src/topics/workload-identity.md (about) 1 # Workload Identity 2 3 Azure AD Workload identity is the next iteration of Azure AD Pod identity 4 that enables Kubernetes applications such as CAPZ to access Azure cloud 5 resources securely with Azure Active Directory. 6 7 Let's help you get started using workload identity. We assume 8 you have access to Azure cloud services. 9 10 ## Quick start 11 12 ### Set up a management cluster with kind 13 14 - Create a private and public key pair. For example, using OpenSSL: 15 16 ```bash 17 openssl genrsa -out sa.key 2048 18 openssl rsa -in sa.key -pubout -out sa.pub 19 ``` 20 21 Set the environment variable `SERVICE_ACCOUNT_SIGNING_KEY_FILE` to the full path 22 of the `sa.key` private key file you just generated, and set `SERVICE_ACCOUNT_KEY_FILE` 23 to the generated `sa.pub` public key file. 24 25 ```bash 26 export SERVICE_ACCOUNT_SIGNING_KEY_FILE=$(realpath sa.key) 27 export SERVICE_ACCOUNT_KEY_FILE=$(realpath sa.pub) 28 ``` 29 30 These environment variables will be used later, when creating the kind cluster. 31 32 - Create and upload a discovery document 33 34 Create and upload a JWKS discovery document by following [these instructions](https://azure.github.io/azure-workload-identity/docs/installation/self-managed-clusters/oidc-issuer.html). 35 36 - Create two federated identity credentials 37 38 Export environment variables used for creating a federated identity credential: 39 40 - `SERVICE_ACCOUNT_NAMESPACE`: Namespace where the capz-manager and 41 azureserviceoperator-controller-manager pods will run. Default is `capz-system`. 42 - `SERVICE_ACCOUNT_NAME`: Name of the capz-manager or azureserviceoperator-default k8s service account. Default is `capz-manager` for CAPZ and `azureserviceoperator-default` for ASO. 43 - `SERVICE_ACCOUNT_ISSUER`: Path of the Azure storage container created in the previous step, specifically: 44 - `"https://${AZURE_STORAGE_ACCOUNT}.blob.core.windows.net/${AZURE_STORAGE_CONTAINER}/"` 45 46 Create two federated identity credentials, one for CAPZ and one for ASO, by following [these instructions](https://azure.github.io/azure-workload-identity/docs/topics/federated-identity-credential.html). You'll need to set `SERVICE_ACCOUNT_NAME` and `SERVICE_ACCOUNT_NAMESPACE` to different values for each credential. 47 Use either `user-assigned-identity` or `AD application` when creating the credentials, and add the `contributor` role to each. 48 49 - Create a kind cluster with the following command: 50 51 ```bash 52 cat <<EOF | kind create cluster --name azure-workload-identity --config=- 53 kind: Cluster 54 apiVersion: kind.x-k8s.io/v1alpha4 55 nodes: 56 - role: control-plane 57 extraMounts: 58 - hostPath: ${SERVICE_ACCOUNT_KEY_FILE} 59 containerPath: /etc/kubernetes/pki/sa.pub 60 - hostPath: ${SERVICE_ACCOUNT_SIGNING_KEY_FILE} 61 containerPath: /etc/kubernetes/pki/sa.key 62 kubeadmConfigPatches: 63 - | 64 kind: ClusterConfiguration 65 apiServer: 66 extraArgs: 67 service-account-issuer: ${SERVICE_ACCOUNT_ISSUER} 68 service-account-key-file: /etc/kubernetes/pki/sa.pub 69 service-account-signing-key-file: /etc/kubernetes/pki/sa.key 70 controllerManager: 71 extraArgs: 72 service-account-private-key-file: /etc/kubernetes/pki/sa.key 73 EOF 74 ``` 75 76 - Initialize the kind cluster as a CAPZ management cluster using `clusterctl`: 77 78 ```bash 79 clusterctl init --infrastructure azure 80 ``` 81 82 If you don't have `clusterctl` installed, follow [these instructions](https://cluster-api.sigs.k8s.io/user/quick-start.html#install-clusterctl) 83 to install it. 84 85 ### Creating a Workload Cluster 86 87 - Create a user-assigned identity using the below steps: 88 - [Create](https://learn.microsoft.com/en-gb/azure/active-directory/managed-identities-azure-resources/how-manage-user-assigned-managed-identities?pivots=identity-mi-methods-azp#create-a-user-assigned-managed-identity) 89 a user-assigned managed identity in Azure. Save its name which will be used later. 90 - [Create a role assignment](https://learn.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal-managed-identity) 91 to give the identity Contributor access to the Azure subscription where the workload cluster will be created. 92 93 - Before generating a workload cluster YAML configuration, set the 94 following environment variables. 95 96 ```bash 97 export AZURE_SUBSCRIPTION_ID=<your-azure-subscription-id> 98 # This is the client ID of the AAD app or user-assigned identity that you used to created the federated identity. 99 export AZURE_CLIENT_ID=<your-azure-client-id> 100 export AZURE_TENANT_ID=<your-azure-tenant-id> 101 export AZURE_CONTROL_PLANE_MACHINE_TYPE="Standard_B2s" 102 export AZURE_NODE_MACHINE_TYPE="Standard_B2s" 103 export AZURE_LOCATION="eastus" 104 105 # Identity secret. Though these are not used in workload identity, we still 106 # need to set them for the sake of generating the workload cluster YAML configuration 107 export AZURE_CLUSTER_IDENTITY_SECRET_NAME="cluster-identity-secret" 108 export CLUSTER_IDENTITY_NAME="cluster-identity" 109 export AZURE_CLUSTER_IDENTITY_SECRET_NAMESPACE="default" 110 ``` 111 112 - Generate a workload cluster template using the following command. 113 114 ```bash 115 clusterctl generate cluster azwi-quickstart --kubernetes-version v1.27.3 --worker-machine-count=3 > azwi-quickstart.yaml 116 ``` 117 118 - Edit the generated `azwi-quickstart.yaml` to make the following changes for 119 workload identity to the `AzureClusterIdentity` object: 120 121 - Change the type to `WorkloadIdentity`. 122 - Remove the `clientSecret` spec. 123 124 The AzureClusterIdentity specification should look like the following. 125 ```yaml 126 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 127 kind: AzureClusterIdentity 128 metadata: 129 name: cluster-identity 130 spec: 131 type: WorkloadIdentity 132 allowedNamespaces: 133 list: 134 - <cluster-namespace> 135 tenantID: <your-tenant-id> 136 clientID: <your-client-id> 137 ``` 138 139 - Change the `AzureMachineTemplate` for both control plane and worker to include user-assigned-identity by 140 adding the following in its `spec`. 141 142 ```yaml 143 identity: UserAssigned 144 userAssignedIdentities: 145 - providerID: /subscriptions/${AZURE_SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/${USER_ASSIGNED_IDENTITY_NAME} 146 ``` 147 148 A sample `AzureMachineTemplate` after the edit should look like the below: 149 150 ```yaml 151 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 152 kind: AzureMachineTemplate 153 metadata: 154 name: ${CLUSTER_NAME}-md-0 155 namespace: default 156 spec: 157 template: 158 spec: 159 osDisk: 160 diskSizeGB: 128 161 osType: Linux 162 sshPublicKey: ${AZURE_SSH_PUBLIC_KEY_B64:=""} 163 identity: UserAssigned 164 userAssignedIdentities: 165 - providerID: /subscriptions/${AZURE_SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/${USER_ASSIGNED_IDENTITY_NAME} 166 vmSize: ${AZURE_NODE_MACHINE_TYPE} 167 ``` 168 169 - At this stage, you can apply this yaml to create a workload cluster. 170 171 Notes: 172 - Please follow this [link](https://github.com/kubernetes-sigs/cluster-api-provider-azure/blob/main/templates/test/ci/cluster-template-prow.yaml) 173 to see a workload cluster yaml configuration that uses workload identity. 174 - Creating a workload cluster via workload identity will be 175 simplified after [this](https://github.com/kubernetes-sigs/cluster-api-provider-azure/issues/3589) issue is resolved. 176 177 ## Debugging 178 179 ### No matching federated identity record found 180 181 If you see logs like below, double check if the service account URL is exactly same on apiserver as 182 that in the federated credential. 183 ```bash 184 "error": "invalid_request", 185 "error_description": "AADSTS70021: No matching federated identity record found for presented assertion. Assertion 186 ``` 187 188 ### Authorization failed when using user-assigned identity 189 190 If you see error message similar to the following in the `AzureCluster` object, 191 this can be because the user-assigned identity does not have required permission. 192 193 ```bash 194 Message: group failed to create or update. err: failed to get existing resource 195 demo/demo(service: group): resources.GroupsClient#Get: Failure 196 responding to request: StatusCode=403 -- Original Error: autorest/azure: 197 Service returned an error. Status=403 Code="AuthorizationFailed" 198 Message="The client '<id-redacted>' with object id '<id-redacted>' does not have 199 authorization to perform action 'Microsoft.Resources/subscriptions/resourcegroups/read' 200 over scope '/subscriptions/<sub-id-redacted>/resourcegroups/ashu-test' or the 201 scope is invalid. If access was recently granted, please refresh your 202 credentials.". Object will be requeued after 15s 203 ``` 204 205 Add `contributor` role to the user-assigned identity and this should fix it.