Configure managed workload identity authentication for GKE

This document explains how to configure managed workload identities for Google Kubernetes Engine (GKE) in your GKE fleets-managed clusters. It also explains how to deploy a workload and verify the workload's identity and certificate.

Setting up and using managed workload identities for GKE involves the following steps:

  1. Configure Certificate Authority Service to issue certificates for managed workload identities.

  2. Bind the CAs to the workload identity pool.

  3. Authorize managed workload identities to request certificates from the CA pool.

  4. Deploy workloads with managed workload identities.

Google-managed workload identity pool

When you add your clusters to GKE fleets, fleets automatically creates a Google-managed workload identity pool that serves as the root of your trust domain. The Google-managed workload identity pool has the following constraints:

  • Google fully manages the pool, so you cannot create any sub-resources, like namespaces, identities, or identity providers.

  • The pool can only be used for GKE workloads. You cannot add other types of workloads, like Compute Engine VMs, to the pool.

  • All clusters in the pool are subject to the standard Kubernetes namespace sameness model. This means that all clusters in the pool are equivalently privileged. Workloads that run on any of the clusters in the pool can use any identity that is in the pool.

Multi-project configuration

Google Cloud resources that you use in this document, such as GKE clusters, the root CA, and subordinate CAs, can exist in separate projects. When referring to these resources, use the --project flag to specify the correct project for each resource.

Before you begin

  1. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  2. Understand managed workload identities.

  3. Ensure that you have created a GKE cluster.

  4. Add your clusters to GKE fleets. If your cluster is an Autopilot cluster, omit --enable-workload-identity. Fleets automatically creates a Google-managed workload identity pool that serves as a trust domain.

    Enable GKE fleets by running the following command:

    gcloud container clusters update CLUSTER_NAME \
        --enable-workload-identity \
        --enable-fleet \
        --fleet-project=PROJECT_ID
    

    Replace the following:

    • CLUSTER_NAME: the name of the GKE cluster that you want to register with the GKE fleet
    • PROJECT_ID: the GKE fleet host project ID
  5. Enable the IAM and Certificate Authority Service APIs:

    gcloud services enable cloudresourcemanager.googleapis.com iam.googleapis.com privateca.googleapis.com

  6. Configure the Google Cloud CLI to use the billing and quota project.

    gcloud config set billing/quota_project PROJECT_ID
    

    Replace PROJECT_ID with the ID of the fleet project.

Required roles

To get the permissions that you need to create managed workload identities and provision managed workload identity certificates, ask your administrator to grant you the following IAM roles on the project:

For more information about granting roles, see Manage access to projects, folders, and organizations.

You might also be able to get the required permissions through custom roles or other predefined roles.

Configure CA Service to issue certificates for managed workload identities

To configure managed workload identities for GKE, you first need to configure a certificate authority (CA) and one or more subordinate CAs. This configuration is known as a CA hierarchy.

You can use CA Service pools to set up this hierarchy. With this hierarchy, the subordinate CA pool issues the X.509 workload identity certificates to your workloads.

Configure your root CA pool

To create the root CA pool, do the following:

Create the root CA pool in the Enterprise tier using gcloud privateca pools create. This tier is meant for long-lived, low-volume certificate issuance.

gcloud privateca pools create ROOT_CA_POOL_ID \
    --location=REGION \
    --project=CA_PROJECT_ID \
    --tier=enterprise

Replace the following:

  • ROOT_CA_POOL_ID: a unique ID for the root CA pool. The ID can be up to 64 characters in length and must contain only lower and uppercase alphanumeric characters, underscores, or hyphens. The pool ID must be unique within the region.

  • REGION: the region where the root CA pool is located.

  • CA_PROJECT_ID: the project ID that you want to create the root CA in.

To learn more about CA pools, tiers, and regions, see Creating CA pools.

Configure your root CA

Create a root CA in the root CA pool using gcloud privateca roots create. You might be prompted to enable the root CA if this is the only CA in the root CA Pool.

To create a root CA, run the following command:

gcloud privateca roots create ROOT_CA_ID \
    --pool=ROOT_CA_POOL_ID \
    --subject="CN=ROOT_CA_CN, O=ROOT_CA_ORGANIZATION" \
    --key-algorithm="KEY_ALGORITHM" \
    --max-chain-length=1 \
    --location=REGION \
    --project=CA_PROJECT_ID \
    --auto-enable

Replace the following:

  • ROOT_CA_ID: a unique name for the root CA. The CA name can be up to 64 characters in length and must contain only lower and uppercase alphanumeric characters, underscores, or hyphens. The CA name must be unique within the region.
  • ROOT_CA_POOL_ID: the ID of the root CA pool.
  • ROOT_CA_CN: the common name of the root CA.
  • ROOT_CA_ORGANIZATION: the organization of the root CA.
  • KEY_ALGORITHM: the key algorithm—for example, ec-p256-sha256
  • REGION: the region where the root CA pool is located.
  • CA_PROJECT_ID: the project ID that you created the root CA in.

For more information about the subject fields for the CA, see Subject.

Optionally, you create additional root CAs in your root CA pool. Doing so can be useful for root CA rotation.

Configure subordinate CAs

Optionally, you can configure subordinate CAs. Configuring subordinate CAs can help with the following:

  • Multiple certificate issuance scenarios: If you have multiple certificate issuance scenarios, then you can create a subordinate CA for each scenario.

  • Better load balancing: Adding multiple subordinate CAs in a CA pool helps you achieve better load balancing of certificate requests.

To create a subordinate CA pool and subordinate CA, do the following:

  1. Create the subordinate CA pool in the DevOps tier, which is meant for high volume, short-lived certificate issuance.

    gcloud privateca pools create SUBORDINATE_CA_POOL_ID \
        --location=REGION \
        --project=CA_PROJECT_ID \
        --tier=devops
    

    Replace the following:

    • SUBORDINATE_CA_POOL_ID: a unique ID for the subordinate CA pool. The ID can be up to 64 characters in length and must contain only lowercase and uppercase alphanumeric characters, underscores, or hyphens. The pool ID must be unique within the region.
    • REGION: the region in which to create the subordinate CA pool.
    • CA_PROJECT_ID: the ID of the project that you created the subordinate CA in.

    For more information, see Creating CA pools.

  2. Create a subordinate CA in the subordinate CA pool. Don't change the default config-based issuance mode.

    gcloud privateca subordinates create SUBORDINATE_CA_ID \
        --pool=SUBORDINATE_CA_POOL_ID \
        --location=REGION \
        --issuer-pool=ROOT_CA_POOL_ID \
        --issuer-location=REGION \
        --subject="CN=SUBORDINATE_CA_CN, O=SUBORDINATE_CA_ORGANIZATION" \
        --key-algorithm="KEY_ALGORITHM" \
        --use-preset-profile=subordinate_mtls_pathlen_0 \
        --project=CA_PROJECT_ID \
        --auto-enable
    

    Replace the following:

    • SUBORDINATE_CA_ID: a unique name for the subordinate CA. The name can be up to 64 characters in length and must contain only lowercase and uppercase alphanumeric characters, underscores, or hyphens. The pool name must be unique within the region.
    • SUBORDINATE_CA_POOL_ID: the name of the subordinate CA pool.
    • REGION: the region where the subordinate CA pool is located.
    • ROOT_CA_POOL_ID: the ID of the root CA pool.
    • REGION: the region of the root CA pool.
    • SUBORDINATE_CA_CN: the common name of the subordinate CA.
    • SUBORDINATE_CA_ORGANIZATION: the name of the subordinate CA issuing organization.
    • KEY_ALGORITHM: the key algorithm—for example, ec-p256-sha256
    • CA_PROJECT_ID: the ID of the project that you created the subordinate CA in.

    For more information about the subject fields for the CA, see Subject.

Create a certificate issuance configuration file

To bind CAs to workload identity pools, they need to have a certificate issuance config. Optionally, if you need your workloads to authenticate across multiple trust domains, you can also update the pool with trust configuration configs.

To configure the certificate issuance config, you create a certificate issuance config file. The format of the file is similar to the following:

{
  "inlineCertificateIssuanceConfig": {
      "caPools": {
        "REGION1": "projects/CA_PROJECT_NUMBER1/locations/REGION1/caPools/SUBORDINATE_CA_POOL_ID1",
        "REGION2": "projects/CA_PROJECT_NUMBER2/locations/REGION2/caPools/SUBORDINATE_CA_POOL_ID2"
      },
      "lifetime": "DURATION",
      "rotationWindowPercentage": ROTATION_WINDOW_PERCENTAGE,
      "keyAlgorithm": "ALGORITHM"
  }
}

Replace the following:

  • REGION: The regions whether the CAs are located.

  • CA_PROJECT_NUMBER: The project number of the project that in which you created the subordinate CA pool. To get the project number from CA_PROJECT_ID project, run the following command:

    gcloud projects describe CA_PROJECT_ID --format="value(projectNumber)"
    
  • SUBORDINATE_CA_POOL_ID: The name of the subordinate CA pool.

  • ALGORITHM: Optional. The encryption algorithm used to generate the private key. Valid values are ECDSA_P256 (default), ECDSA_P384, RSA_2048, RSA_3072, RSA_4096.

  • DURATION: Optional. The leaf certificate validity duration, in seconds. The value must be between 86400 (1 day) and 2592000 (30 days). If not specified, the default value of 86400 (1 day) is used. The actually validity of the issued certificate also depends on the issuing CA, because it can restrict the lifetime of the issued certificate.

  • ROTATION_WINDOW_PERCENTAGE: Optional: The percentage of the certificate's lifetime at which a renewal triggers. The value must be between 50 and 80. The default is 50.

Create the trust configuration file

By default, your workloads within the same trust domain can mutually authenticate using managed workload identities. If you want workloads that are in different trust domains to mutually authenticate, then you need to explicitly declare the trust relationship in the workload identity pool. You do this by creating a trust config file that contains an inlineTrustConfig that provides certificates for each domain.

The trust config file contains a set of trust anchors that managed workload identity uses to validate peer certificates. The trust config file maps the SPIFFE trust domain to CA certificates.

To create the trust config file, do the following:

  1. Download the certificates.

    gcloud privateca pools get-ca-certs ROOT_CA_POOL_ID \
        --output-file=CERTIFICATE_PATH \
        --location=REGION
    

    Replace the following:

    • ROOT_CA_POOL_ID: the ID of the root CA pool
    • CERTIFICATE_PATH: the path to which to output the PEM-encoded certificate
    • REGION: the region of the root CA pool

  2. Create a file called that contains your inline trust configuration, with PEM-formatted certificates. The file looks similar to the following:
    {
      "inlineTrustConfig": {
        "additionalTrustBundles": {
          "TRUST_DOMAIN_NAME1": {
            "trustAnchors": [
              {
                  "pemCertificate": "-----BEGIN CERTIFICATE-----\nCERTIFICATE_MATERIAL1\n-----END CERTIFICATE-----"
              },
              {
                  "pemCertificate": "-----BEGIN CERTIFICATE-----\nCERTIFICATE_MATERIAL2\n-----END CERTIFICATE-----"
              }
            ]
          },
          "TRUSTED_DOMAIN_NAME2": {
            "trustAnchors": [
              {
                  "pemCertificate": "-----BEGIN CERTIFICATE-----\nCERTIFICATE_MATERIAL3\n-----END CERTIFICATE-----"
              },
              {
                  "pemCertificate": "-----BEGIN CERTIFICATE-----\nCERTIFICATE_MATERIAL4\n-----END CERTIFICATE-----"
              }
            ]
          }
        }
      }
    }
    

    Replace the following:

    • TRUST_DOMAIN_NAME: The trust domain name, formatted as follows:
      PROJECT_ID.svc.id.goog
      
    • CERTIFICATE_MATERIAL: A set of PEM-formatted CA certificates trusted to issue certificates in the trust domain.

Bind the CAs to the workload identity pool

After you create your CA hierarchy and create certificate issuance configs for each CA, you bind the CAs to the workload identity pool. To bind a CA to the workload identity pool, you update the workload identity pool with the CA's certificate issuance config. Then, you can verify that the pool was updated.

Update the workload identity pool

To update the pool, run the following command:

gcloud iam workload-identity-pools update TRUST_DOMAIN_NAME \
    --location="global" \
    --inline-certificate-issuance-config-file=CIC_JSON_FILE_PATH \
    --inline-trust-config-file=TC_JSON_FILE_PATH \
    --project=PROJECT_ID

Replace the following:

  • TRUST_DOMAIN_NAME: The name of the trust domain, formatted as follows:

    PROJECT_ID.svc.id.goog
    
  • CIC_JSON_FILE_PATH: The path to the JSON-formatted certificate issuance config file (cic.json) that you created earlier.

  • TC_JSON_FILE_PATH: Optional. The path to the JSON-formatted trust config file (tc.json) that you created earlier. If your workloads authenticate across different trust domains, you must specify this file. Otherwise you can omit --inline-trust-config.

Verify that the workload identity pool was updated

To verify that your workload identity pool was updated along with the certificate issuance config and trust config, run the following command:

gcloud iam workload-identity-pools describe TRUST_DOMAIN_NAME \
    --location="global" \
    --project=PROJECT_ID

Replace TRUST_DOMAIN_NAME with the trust domain name that you used to update the workload identity pool earlier in this document.

The command output looks similar to the following:

inlineCertificateIssuanceConfig:
    caPools:
      REGION1: projects/PROJECT_NUMBER1/locations/REGION1/caPools/SUBORDINATE_CA_POOL_ID1,
      REGION2: projects/PROJECT_NUMBER2/locations/REGION2/caPools/SUBORDINATE_CA_POOL_ID2
    keyAlgorithm: ALGORITHM
    lifetime: DURATION
    rotationWindowPercentage: ROTATION_WINDOW_PERCENTAGE
inlineTrustConfig:
    additionalTrustBundles:
      example.com:
          trustAnchors:
          - pemCertificate: |-
            -----BEGIN CERTIFICATE-----
            CERTIFICATE_MATERIAL1
            -----END CERTIFICATE-----
          - pemCertificate: |-
            -----BEGIN CERTIFICATE-----
            CERTIFICATE_MATERIAL2
            -----END CERTIFICATE-----
      myorg.com:
          trustAnchors:
          - pemCertificate: |-
            -----BEGIN CERTIFICATE-----
            CERTIFICATE_MATERIAL3
            -----END CERTIFICATE-----
          - pemCertificate: |-
            -----BEGIN CERTIFICATE-----
            CERTIFICATE_MATERIAL4
            -----END CERTIFICATE-----
name: PROJECT_ID.svc.id.goog
state: ACTIVE

If inlineCertificateIssuanceConfig or inlineTrustConfig isn't present in the command output, verify that you've correctly configured your gcloud CLI to use the correct project for billing and quota. You might need to update to a newer version of the gcloud CLI.

Authorize managed workload identities to request certificates from the CA pool

After you bind the CAs to the workload identity pool, you need to authorize managed workload identities to request certificates from the CA pool. To authorize these identities, do the following:

  1. Grant the CA Service Workload Certificate Requester (roles/privateca.workloadCertificateRequester) IAM role on each subordinate CA pool to the trust domain. The following gcloud privateca pools add-iam-policy-binding command authorizes the trust domain to request certificates from the CA Service certificate chains.

    gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_ID \
        --location=REGION \
        --role=roles/privateca.workloadCertificateRequester \
        --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/name/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog" \
        --project=CA_PROJECT_ID
    

    Replace the following:

    • SUBORDINATE_CA_POOL_ID: the ID for the subordinate CA pool.
    • REGION: the region of the subordinate CA pool.
    • PROJECT_NUMBER: the project number of the project that contains the GKE workload identity pool.

      To get PROJECT_NUMBER from PROJECT_ID, run the following command:

      gcloud projects describe PROJECT_ID --format="value(projectNumber)"
      
    • PROJECT_ID: The project ID of the GKE fleet host project.

    • CA_PROJECT_ID: the ID of the project that you created the subordinate CA in.

  2. Grant the CA Service Pool Reader (roles/privateca.poolReader) role on the subordinate CA pools to the managed workload identity. Doing so authorizes the managed workload identity to get the signed X.509 certificates from the CA's certificate chains.

    gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_ID \
        --location=REGION \
        --role=roles/privateca.poolReader \
        --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/name/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog" \
        --project=CA_PROJECT_ID
    

    Replace the following:

    • SUBORDINATE_CA_POOL_ID: the ID of the subordinate CA pool.
    • REGION: the region of the subordinate CA pool.
    • PROJECT_NUMBER: the project number of the project that contains the GKE workload identity pool.
    • PROJECT_ID: The project ID of the GKE fleet host project.
    • CA_PROJECT_ID: the ID of the project that you created the subordinate CA in.

Deploy workloads with managed workload identities

After you configure your CA pools to issue certificates for managed workload identities, you can deploy workloads that have managed workload identities.

This section shows you how to deploy a test workload that has a managed workload identity. To do this, you deploy a Pod, check that credentials were generated, and view the certificate and the SPIFFE ID.

Deploy a Pod

To deploy a test Pod in your cluster, do the following:

  1. Get the cluster credentials.

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=CLUSTER_ZONE \
        --project=CLUSTER_PROJECT_ID
    
  2. Create the Kubernetes namespace.

    kubectl create namespace KUBERNETES_NAMESPACE
    
  3. Deploy a test PodSpec.

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Pod
    metadata:
      namespace: KUBERNETES_NAMESPACE
      name: example-pod
    spec:
      containers:
      - name: main
        image: debian
        command: ['sleep', 'infinity']
        volumeMounts:
        - name: fleet-spiffe-credentials
          mountPath: /var/run/secrets/workload-spiffe-credentials
          readOnly: true
      nodeSelector:
        iam.gke.io/gke-metadata-server-enabled: "true"
      volumes:
      - name: fleet-spiffe-credentials
        csi:
          driver: podcertificate.gke.io
          volumeAttributes:
            signerName: spiffe.gke.io/fleet-svid
            trustDomain: fleet-project/svc.id.goog
    EOF
    

List the workload credentials

To list the workload credentials, run the following command. It can take a few minutes to create the credentials.

kubectl exec -it example-pod -n KUBERNETES_NAMESPACE -- ls  /var/run/secrets/workload-spiffe-credentials

You should see the following output:

ca_certificates.pem
certificates.pem
private_key.pem
trust_bundles.json

View the certificate

To view the certificate, do the following:

  1. Export the certificate to a certificate file.

    kubectl exec -it example-pod --namespace=KUBERNETES_NAMESPACE -- cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -noout -text > certfile
    
  2. View the certificate file.

    cat certfile
    

    In the certificate, in the X509v3 Subject Alternative Name attribute, you see the SPIFFE ID, with the following format: spiffe://PROJECT_ID.svc.id.goog/ns/KUBERNETES_NAMESPACE/sa/default

    default refers to the default Kubernetes ServiceAccount.

Test workload-to-workload authentication

To test workload-to-workload authentication, see Test mTLS authentication using Go.

The sample code in the repository creates client and server workloads. You can test mutual authentication between the workloads using the certificates that you generated earlier in this document.

What's next

Try it for yourself

If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.

Get started for free