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