Use workload identity with AWS

Workload identity enables you to assign distinct, fine-grained identities and authorization for each application in your cluster. Workload identity is the recommended way for applications running within GKE on AWS to access AWS and Google Cloud services. For more information, see Workload identity.

This topic explains how to create an OIDC provider, provision service accounts, and test a sample workload using workload identity.

Create an AWS IAM OIDC provider for your cluster

To use workload identity with your cluster, you first create an AWS IAM OIDC provider that references your cluster. If you already have an IAM OIDC provider for your cluster, you can skip this section.

To create the provider, follow these steps:

  1. Determine the OIDC issuer URI for your cluster:

    gcloud container aws clusters describe CLUSTER_NAME \
         --location=GOOGLE_CLOUD_LOCATION \
         --format='value(workloadIdentityConfig.issuerUri)'
    

    Replace the following:

    • CLUSTER_NAME: the name of your cluster
    • GOOGLE_CLOUD_LOCATION: the name of the Google Cloud location from which this node pool will be managed, as defined in Google Cloud management regions

    The output includes your cluster's OIDC issuer URI. Save this value for the following step.

  2. Next, create an AWS IAM OIDC provider that references your cluster with the following command:

    aws iam create-open-id-connect-provider \
        --url ISSUER_URI \
        --client-id-list sts.amazonaws.com \
        --thumbprint-list 08745487e891c19e3078c1f2a07e452950ef36f6
    

    Replace ISSUER_URI with your issuer URI from the previous step.

    The thumbprint of the Google Cloud service that serves the issuer URI is always 08745487e891c19e3078c1f2a07e452950ef36f6.

Configure an AWS IAM role with an attached IAM policy

To configure an AWS IAM role and attach a policy to it, follow these steps:

  1. Determine the issuer host by removing the https:// prefix from the issuer URI. For example, if your URI is https://oidc-provider.com/v1/projects/pid/locations/us-west1/awsClusters/awscluster, the host is oidc-provider.com/v1/projects/pid/locations/us-west1/awsClusters/awscluster. Save this value. You'll need it later.

  2. Determine the provider's Amazon Resource Name (ARN) by running:

    aws iam list-open-id-connect-providers --output=text \
        --query 'OpenIDConnectProviderList[?ends_with(Arn, `ISSUER_HOST`) == `true`].Arn'
    

    Replace ISSUER_HOST with the hostname from the issuer URI for the cluster.

  3. Next, create a trust policy to provide OIDC credentials to the Kubernetes service account. Create a file named trust-policy.json with the following contents:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Federated": "PROVIDER_ARN"
          },
          "Action": "sts:AssumeRoleWithWebIdentity",
          "Condition": {
            "StringEquals": {
              "ISSUER_HOST:sub": "system:serviceaccount:NAMESPACE:KSA_NAME"
            }
          }
        }
      ]
    }
    

    Replace the following:

    • PROVIDER_ARN: the ARN of the cluster's IAM OIDC provider
    • ISSUER_HOST: the hostname from the issuer URI for the cluster.
    • NAMESPACE: the Kubernetes namespace where the application runs
    • KSA_NAME: the Kubernetes service account (KSA) to use for the application
  4. Create an AWS IAM role:

    aws iam create-role --role-name=AWS_ROLE_NAME \
        --assume-role-policy-document file://trust-policy.json
    

    Replace AWS_ROLE_NAME with the AWS IAM role name for the application.

  5. Attach an AWS IAM policy to the role:

    aws iam attach-role-policy --role-name=AWS_ROLE_NAME \
        --policy-arn=AWS_POLICY_ARN
    

    Replace the following:

    • AWS_ROLE_NAME: the AWS IAM role name for the application

    For example, to create a role named ec2-readonly, with the arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess policy, run the following command:

    aws iam attach-role-policy --role-name=ec2-readonly \
        --policy-arn=arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess
    

Deploy a sample application

To test workload identity, follow these steps to deploy a sample application:

  1. Determine the role's ARN:

    aws iam get-role --role-name=AWS_ROLE_NAME --query 'Role.Arn'
    

    Replace AWS_ROLE_NAME.

  2. Create a manifest for a Kubernetes Namespace, KSA, and Pod. Copy the following manifest into a file named workload-identity-test.yaml:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: NAMESPACE
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: KSA_NAME
      namespace: NAMESPACE
    automountServiceAccountToken: false
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: aws-cli-example
      namespace: NAMESPACE
    spec:
      serviceAccount: KSA_NAME
      containers:
      - name: aws-cli
        image: amazon/aws-cli:latest
        command:
        - /bin/bash
        - -c
        - "set -eu -o pipefail; while true; do aws ec2 describe-availability-zones; sleep 5; done"
        env:
        - name: AWS_ROLE_ARN
          value: AWS_ROLE_ARN
        - name: AWS_WEB_IDENTITY_TOKEN_FILE
          value: /var/run/secrets/aws-iam-token/serviceaccount/token
        - name: AWS_REGION
          value: AWS_REGION
        volumeMounts:
        - mountPath: /var/run/secrets/aws-iam-token/serviceaccount
          name: aws-iam-token
          readOnly: true
      volumes:
      - name: aws-iam-token
        projected:
          defaultMode: 420
          sources:
          - serviceAccountToken:
              audience: sts.amazonaws.com
              expirationSeconds: 86400
              path: token
    

    Replace the following:

    • NAMESPACE
    • KSA_NAME
    • AWS_ROLE_ARN: the ARN of the AWS IAM role for the application
    • AWS_REGION: the AWS region of the cluster
  3. Apply the manifest:

    kubectl apply -f workload-identity-test.yaml
    

    Wait several minutes for the Pod to start, and proceed to the following section.

Verify the sample application is working

To verify the sample application can access the EC2 API, look at the pod's logs:

kubectl logs -f aws-cli-example -n NAMESPACE

If the Pod can access the EC2 API, the output includes information on EC2 availability zones and looks similar to the following:

-------------------------------------------------
|           DescribeAvailabilityZones           |
+-----------------------------------------------+
||              AvailabilityZones              ||
|+---------------------+-----------------------+|
||  GroupName          |  us-west-2            ||
||  NetworkBorderGroup |  us-west-2            ||
||  OptInStatus        |  opt-in-not-required  ||
||  RegionName         |  us-west-2            ||
||  State              |  available            ||
||  ZoneId             |  usw2-az1             ||
||  ZoneName           |  us-west-2a           ||
|+---------------------+-----------------------+|
||              AvailabilityZones              ||
|+---------------------+-----------------------+|
||  GroupName          |  us-west-2            ||
||  NetworkBorderGroup |  us-west-2            ||
||  OptInStatus        |  opt-in-not-required  ||
||  RegionName         |  us-west-2            ||
||  State              |  available            ||
||  ZoneId             |  usw2-az2             ||
||  ZoneName           |  us-west-2b           ||
|+---------------------+-----------------------+|
||              AvailabilityZones              ||
|+---------------------+-----------------------+|
||  GroupName          |  us-west-2            ||
||  NetworkBorderGroup |  us-west-2            ||
||  OptInStatus        |  opt-in-not-required  ||
||  RegionName         |  us-west-2            ||
||  State              |  available            ||
||  ZoneId             |  usw2-az3             ||
||  ZoneName           |  us-west-2c           ||
|+---------------------+-----------------------+|
||              AvailabilityZones              ||
|+---------------------+-----------------------+|
||  GroupName          |  us-west-2            ||
||  NetworkBorderGroup |  us-west-2            ||
||  OptInStatus        |  opt-in-not-required  ||
||  RegionName         |  us-west-2            ||
||  State              |  available            ||
||  ZoneId             |  usw2-az4             ||
||  ZoneName           |  us-west-2d           ||
|+---------------------+-----------------------+|

Clean up

To remove this sample application, follow these steps:

  1. Delete the sample application's manifest from your cluster:

    kubectl delete -f workload-identity-test.yaml
    
  2. Detach the AWS IAM policy from the role:

    aws iam detach-role-policy --role-name AWS_ROLE_NAME \
        --policy-arn arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess
    

    Replace AWS_ROLE_NAME with the AWS IAM role name for the application.

  3. Delete the AWS IAM role:

    aws iam delete-role --role-name AWS_ROLE_NAME
    

    Replace AWS_ROLE_NAME with the AWS IAM role name for the application.

  4. Delete the AWS IAM OIDC provider:

    aws iam delete-open-id-connect-provider --open-id-connect-provider-arn PROVIDER_ARN
    

    Replace PROVIDER_ARN with the ARN of the IAM OIDC provider for the cluster.

What's next