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.