Example for using Microsoft Entra Workload ID in OpenShift Container Platform

Solution Verified - Updated -

Environment

  • Red Hat OpenShift Container Platform (OCP) 4.14 and later
    • Important Note: Azure Red Hat OpenShift clusters do not currently support Microsoft Entra (formerly Azure Active Directory) Workload ID.
  • Microsoft Azure

Issue

  • How can Microsoft Entra (formerly Azure Active Directory) Workload ID be used with workload running on OpenShift Container Platform?
  • Is there an example for using Microsoft Entra Workload ID?

Resolution

  • Prerequisites: Microsoft Entra (formerly Azure Active Directory) Workload ID is only available with OpenShift Container Platform 4.14 and later. For more information about the short-term credentials implementation for OpenShift Container Platform clusters on Azure, see the OpenShift documentation.
  • Important Note: Azure Red Hat OpenShift clusters do not currently support Microsoft Entra (formerly Azure Active Directory) Workload ID.

Example

This example deploys an application that will access a Microsoft Azure Key Vault by using Microsoft Entra Workload ID.

  1. Verify that the annotation target.workload.openshift.io/management is set on the pod-identity-webhook Deployment in the `` namespace:

    $ oc describe deployment pod-identity-webhook -n openshift-cloud-credential-operator | grep 'target.workload.openshift.io/management'
    Annotations:      target.workload.openshift.io/management: {"effect": "PreferredDuringScheduling"}
    
  2. Begin by setting environment variables matching your Azure environment. Make sure to set the correct RESOURCE_GROUP, LOCATION and correct namespaces and desired identity names:

    export KEYVAULT_NAME="azwi-kv-$(openssl rand -hex 2)"
    export KEYVAULT_SECRET_NAME="my-secret"
    export RESOURCE_GROUP="<AZURE_RESOURCE_GROUP>"
    export LOCATION="northeurope"
    export USER_ASSIGNED_IDENTITY_NAME="example-webhook-identity"
    export SERVICE_ACCOUNT_NAMESPACE="example-project"
    export SERVICE_ACCOUNT_NAME="example-workload-identity-sa"
    
  3. Obtain the clusters serviceAccountIssuer OIDC Issuer URL and set the environment variable:

    export SERVICE_ACCOUNT_ISSUER=`oc get authentication cluster -o jsonpath --template='{ .spec.serviceAccountIssuer }'`
    

    Verify that the correct URL has been set:

    echo $SERVICE_ACCOUNT_ISSUER
    https://exampleinfra.blob.core.windows.net/exampleinfra
    
  4. In this example, a new Microsoft Azure Key Vault with a new secret is created that is later accessed via Microsoft Entra Workload ID. Use the Azure az command line tool to create the key vault that is later accessed:

    # If necessary, create the Resource Group (this may not be necessary) 
    az group create --name "${RESOURCE_GROUP}" --location "${LOCATION}"
    # Create the Keyvault and set a secret value
    az keyvault create --resource-group "${RESOURCE_GROUP}" --location "${LOCATION}" --name "${KEYVAULT_NAME}"
    az keyvault secret set --vault-name "${KEYVAULT_NAME}" --name "${KEYVAULT_SECRET_NAME}" --value "Hello world"
    
  5. In these next steps, an Azure user-assigned managed identity and the corresponding policy access is created:

    # Create the identity
    az identity create --name "${USER_ASSIGNED_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}" 
    
    # Set policy access for user-assigned managed identity
    export USER_ASSIGNED_IDENTITY_CLIENT_ID="$(az identity show --name "${USER_ASSIGNED_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}" --query 'clientId' -otsv)"
    export USER_ASSIGNED_IDENTITY_OBJECT_ID="$(az identity show --name "${USER_ASSIGNED_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}" --query 'principalId' -otsv)"
    az keyvault set-policy --name "${KEYVAULT_NAME}" --secret-permissions get --object-id "${USER_ASSIGNED_IDENTITY_OBJECT_ID}" 
    
  6. In OpenShift Container Platform, create the Service Account with the azure.workload.identity/client-id set to the USER_ASSIGNED_IDENTITY_CLIENT_ID above:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
     annotations:
       azure.workload.identity/client-id: ${APPLICATION_CLIENT_ID:-$USER_ASSIGNED_IDENTITY_CLIENT_ID}
     name: ${SERVICE_ACCOUNT_NAME}
     namespace: ${SERVICE_ACCOUNT_NAMESPACE}
    
  7. As the last step, create an Azure federated identity credential linking the service account in OpenShift Container Platform to the Azure user-assigned managed identity:

    az identity federated-credential create \
    --name "kubernetes-federated-credential" \
    --identity-name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --resource-group "${RESOURCE_GROUP}" \
    --issuer "${SERVICE_ACCOUNT_ISSUER}" \
    --subject "system:serviceaccount:${SERVICE_ACCOUNT_NAMESPACE}:${SERVICE_ACCOUNT_NAME}"
    
  8. The OpenShift Container Platform Service Account is now configured as expected. Note that both the .spec.serviceAccountName is set and also the label azure.workload.identity/use: "true" is used:

    export KEYVAULT_URL="$(az keyvault show -g ${RESOURCE_GROUP} -n ${KEYVAULT_NAME} --query properties.vaultUri -o tsv)"
    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Pod           
    metadata:
     name: quick-start
     namespace: ${SERVICE_ACCOUNT_NAMESPACE}                                                         
     labels:                      
       azure.workload.identity/use: "true"  
    spec:
     serviceAccountName: ${SERVICE_ACCOUNT_NAME}
     securityContext:
       runAsNonRoot: true
       seccompProfile:
         type: RuntimeDefault
     containers:
       - image: ghcr.io/azure/azure-workload-identity/msal-go
         name: oidc
         securityContext:
           allowPrivilegeEscalation: false
           capabilities:
             drop: [ "ALL" ]
         env:
           - name: KEYVAULT_URL
             value: ${KEYVAULT_URL}
           - name: SECRET_NAME
             value: ${KEYVAULT_SECRET_NAME}
    EOF
    
  9. In the newly deployed workload, verify that there are both the environment variables and also a projected volume set:

    oc describe pod quick-start
    [..]
     Environment:
       KEYVAULT_URL:                https://azwi-kv-45ff.vault.azure.net/
       SECRET_NAME:                 my-secret
       AZURE_CLIENT_ID:             13698e96-e041-417e-9a7d-EXAMPLE
       AZURE_TENANT_ID:             6047c7e9-b2ad-488d-a54e-EXAMPLE
       AZURE_FEDERATED_TOKEN_FILE:  /var/run/secrets/azure/tokens/azure-identity-token
       AZURE_AUTHORITY_HOST:        https://login.microsoftonline.com/
    [..]
    Volumes:
    [..]
     azure-identity-token:
       Type:                    Projected (a volume that contains injected data from multiple sources)
       TokenExpirationSeconds:  3600
    
  10. Verify in the logs that the workload was able to access the Microsoft Azure Key Vault using the injected keys:

    $ oc logs quick-start  
    I0816 09:43:37.961113       1 main.go:63] "successfully got secret" secret="Hello world"
    

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.

Comments