Enabling Workload Identity with apigeectl

You are currently viewing version 1.11 of the Apigee hybrid documentation.This version is end of life. You should upgrade to a newer version. For more information, seeSupported versions.

This topic explains how to enable Workload Identity for Apigee hybrid usingapigeectl.

If you are using Helm charts to install and manage Apigee hybrid, seeEnabling Workload Identity with Helm charts.

Note: Apigee hybrid v.1.11 only supports Workload Identity federation on GKE.

Overview

Workload Identity is a way for applications running within GKE (Google Kubernetes Engine) to access Google Cloud services. For overviews of Workload Identity, see:

A Google Cloud IAM service account is an identity that an application can use to make requests to Google APIs. These service accounts are referred to as GSA (Google Service Accounts) in the document. For more information about GSAs, seeService accounts.

Separately, Kubernetes also has the concept of service accounts. A service account provides an identity for processes that run in a Pod. Kubernetes service accounts are Kubernetes resources, while Google service accounts are specific to Google Cloud. For information on Kubernetes service accounts, see Configure Service Accounts for Pods in the Kubernetes documentation.

With Apigee hybrid 1.4 and later, Apigee creates and uses a Kubernetes service account for each type of component. Enabling Workload Identity allows the hybrid components to interact with the Kubernetes service accounts.

Google service accounts in Apigee hybrid without Workload Identity

Without using Workload Identity, you must link the Google service accounts to each component in your overrides.yaml file with either a reference to a cert file or a Kubernetes secret. For example:

Environment variables used in these procedures

These procedures make use of the following environment variables. Either set these in your command shell or replace them in the code samples with the actual values:

  • APIGEECTL_HOME: The directory where you have installedapigeectl.
  • CLUSTER_LOCATION: The region or zone of your cluster, for example:us-west1.
  • ENV_NAME: Then name of the Apigee environment.
  • HYBRID_FILES: Your hybrid files directory, for examplehybrid-base-directory/hybrid-files.
  • ORG_NAME: The name of your Apigee organization.
  • PROJECT_ID: The ID of your Google Cloud project.
  • NAMESPACE: Your Apigee namespace (usually "apigee").

Verify the environment variables:

echo $PROJECT_IDecho $ORG_NAMEecho $ENV_NAMEecho $NAMESPACEecho $CLUSTER_LOCATIONecho $APIGEECTL_HOMEecho $HYBRID_FILES

Initialize any of the variables you need:

export PROJECT_ID=my-project-idexport ORG_NAME=$PROJECT_IDexport ENV_NAME=my-environment-nameexport NAMESPACE=apigeeexport CLUSTER_LOCATION=my-cluster-locationexport APIGEECTL_HOME=hybrid-base-directory/apigeectlexport HYBRID_FILES=hybrid-base-directory/hybrid-files

Workload Identity and service account key files

When running Apigee hybrid on GKE, the standard practice is to create and download private keys (.json files) for each of the service accounts. When using Workload Identity, you do not need to download service account private keys and add them to GKE clusters.

If you have downloaded service account key files as part of your Apigee hybrid installation, you can delete them after enabling Workload Identity. In most installations, they reside in thehybrid-base-directory/hybrid-files/service-accounts/ directory.

Enable Workload Identity for Apigee hybrid

To begin, follow the instructions inPrepare to enable Workload Identity to update node pools and initialize variables prior to enabling Workload Identity.

Then, follow the instructions inSetworkloadIdentityEnabled: true and create service accounts to enable Workload Identity on your Apigee hybrid installation.

Prepare to enable Workload Identity

Before starting the install process, follow the steps in this section.

  1. Set the project to the project you're modifying:
    gcloud config set project $PROJECT_ID
  2. Get thegcloud credentials of the cluster on which you are enabling Workload Identity with the following command:
    gcloud container clusters get-credentials ${CLUSTER_NAME} \  --region${CLUSTER_LOCATION} \  --project${PROJECT_ID}
    Note: If you created a zonal cluster instead of a regional cluster, get the credentials with the following command:
    gcloud container clusters get-credentials${CLUSTER_NAME} \  --zone${CLUSTER_LOCATION} \  --project${PROJECT_ID}
  3. Verify that Workload Identity is enabled for the GKE cluster running Apigee with the following command:
    gcloud container clusters describe $CLUSTER_NAME --region $CLUSTER_LOCATION --project $PROJECT_ID
    Note: For zonal clusters use:
    gcloud container clusters describe $CLUSTER_NAME --zone $CLUSTER_LOCATION --project $PROJECT_ID

    The output should include something like the following:

    status:RUNNINGsubnetwork:defaultworkloadIdentityConfig:workloadPool:my-project-id.svc.id.goog

    If needed, enable workload identity on the cluster. This operation can take up to 30 minutes:

      gcloud container clusters update$CLUSTER_NAME \  --workload-pool=$PROJECT_ID.svc.id.goog \  --project$PROJECT_ID \  --region$CLUSTER_LOCATION
    Note: If you created a zonal cluster instead of a regional cluster, use the--zone argument instead of--region as in the following command:
      gcloud container clusters update$CLUSTER_NAME \  --workload-pool=$PROJECT_ID.svc.id.goog \  --zone$CLUSTER_LOCATION \  --project$PROJECT_ID

    For more information, seeEnable Workload Identity.

  4. Ensure Workload Identity is enabled on each node pool.
    1. List your node pools with the following command:
      gcloud container node-pools list \  --cluster $CLUSTER_NAME \  --region $CLUSTER_LOCATION \  --project $PROJECT_ID

      Your output should look something like:

        NAME            MACHINE_TYPE   DISK_SIZE_GB  NODE_VERSION  apigee-runtime  e2-standard-4  100           1.23.12-gke.100  apigee-data     e2-standard-4  100           1.23.12-gke.100
    2. Ensure Workload Identity is enabled per node pool using the following command for each node pool:
      gcloud container node-pools updateNODE_POOL_NAME \  --cluster=$CLUSTER_NAME \  --region $CLUSTER_LOCATION \  --project $PROJECT_ID \  --workload-metadata=GKE_METADATA

      WhereNODE_POOL_NAME is the name of each node pool.

Verify or create Google service accounts

Google service accounts are created for many Apigee hybrid components during installation. Use this procedure to verify the Google service accounts and create any that are needed.

  1. Check the names of the Google service accounts for your project with the following command:
    gcloud iam service-accounts list --project $PROJECT_ID

    Your output should look something like:

    Prod

    For non-production environments:

    DISPLAY NAME         EMAIL                                                      DISABLEDapigee-cassandra     apigee-cassandra@my_project_id.iam.gserviceaccount.com     Falseapigee-logger        apigee-logger@my_project_id.iam.gserviceaccount.com        Falseapigee-mart          apigee-mart@my_project_id.iam.gserviceaccount.com          Falseapigee-metrics       apigee-metrics@my_project_id.iam.gserviceaccount.com       Falseapigee-runtime       apigee-runtime@my_project_id.iam.gserviceaccount.com       Falseapigee-synchronizer  apigee-synchronizer@my_project_id.iam.gserviceaccount.com  Falseapigee-udca          apigee-udca@my_project_id.iam.gserviceaccount.com          Falseapigee-watcher       apigee-watcher@my_project_id.iam.gserviceaccount.com       False

    Non-prod

    For non-production environments:

    DISPLAY NAME         EMAIL                                                      DISABLEDapigee-non-prod      apigee-non-prod@my_project_id.iam.gserviceaccount.com      False
    Tip: If you have custom names for your service accounts that do not correspond easily with the names of the Apigee components, you can determine the role of each service account by checking the roles assigned to it and comparing the roles with the roles recommended inAbout service accounts.

    Use the following command to check the roles assigned to a service account:

    gcloud projects get-iam-policy ${PROJECT_ID}  \  --flatten="bindings[].members" \  --format='table(bindings.role)' \  --filter="SERVICE_ACCOUNT_NAME"

    If you need to create the Google service accounts for your project, there are two methods you can use:

    create-service-account

    Use the following command to create a Google service account per component:

    Prod

    For non-production environments:

    $APIGEECTL_HOME/tools/create-service-account --env prod --dir $APIGEECTL_HOME/../service-accounts

    This command will create the following service accounts:

    • apigee-cassandra
    • apigee-logger
    • apigee-mart
    • apigee-metrics
    • apigee-runtime
    • apigee-synchronizer
    • apigee-udca
    • apigee-watcher

    Non-prod

    For non-production environments:

    $APIGEECTL_HOME/tools/create-service-account --env non-prod --dir $APIGEECTL_HOME/../service-accounts

    This command will create a single service accounts,apigee-non-prod, with all the roles assigned needed to manage all Apigee components.

    gcloud

    Create the following service accounts and assign roles to them.

    Tip: If you want to use custom names, change the red service account name in the code sample to the name you want to use.
    1. Service account:apigee-cassandra,role:roles/storage.objectAdmin

      Create the account:

      gcloud iam service-accounts createapigee-cassandra \  --display-name="apigee-cassandra" \  --project $PROJECT_ID

      Assign the role:

      gcloud projects add-iam-policy-binding $PROJECT_ID \  --member="serviceAccount:apigee-cassandra@$PROJECT_ID.iam.gserviceaccount.com" \  --role="roles/storage.objectAdmin"
    2. Service account:apigee-logger,role:roles/logging.logWriter

      Create the account:

      gcloud iam service-accounts createapigee-logger \  --display-name="apigee-logger" \  --project $PROJECT_ID

      Assign the role:

      gcloud projects add-iam-policy-binding $PROJECT_ID \  --member="serviceAccount:apigee-logger@$PROJECT_ID.iam.gserviceaccount.com" \  --role="roles/logging.logWriter"
    3. Service account:apigee-mart,role:roles/apigeeconnect.Agent

      Create the account:

      gcloud iam service-accounts createapigee-mart \  --display-name="apigee-mart" \  --project $PROJECT_ID

      Assign the role:

      gcloud projects add-iam-policy-binding $PROJECT_ID \  --member="serviceAccount:apigee-mart@$PROJECT_ID.iam.gserviceaccount.com" \  --role="roles/apigeeconnect.Agent"
    4. Service account:apigee-metrics,role:roles/monitoring.metricWriter

      Create the account:

      gcloud iam service-accounts createapigee-metrics \  --display-name="apigee-metrics" \  --project $PROJECT_ID

      Assign the role:

      gcloud projects add-iam-policy-binding $PROJECT_ID \  --member="serviceAccount:apigee-metrics@$PROJECT_ID.iam.gserviceaccount.com" \  --role="roles/monitoring.metricWriter"
    5. Service account:apigee-runtime,role:No role assigned.

      Create the account:

      gcloud iam service-accounts createapigee-runtime \  --display-name="apigee-runtime" \  --project $PROJECT_ID
    6. Service account:apigee-synchronizer,role:roles/apigee.synchronizerManager

      Create the account:

      gcloud iam service-accounts createapigee-synchronizer \  --display-name="apigee-synchronizer" \  --project $PROJECT_ID

      Assign the role:

      gcloud projects add-iam-policy-binding $PROJECT_ID \  --member="serviceAccount:apigee-synchronizer@$PROJECT_ID.iam.gserviceaccount.com" \  --role="roles/apigee.synchronizerManager"
    7. Service account:apigee-udca,role:roles/apigee.analyticsAgent

      Create the account:

      gcloud iam service-accounts createapigee-udca \  --display-name="apigee-udca" \  --project $PROJECT_ID

      Assign the role:

      gcloud projects add-iam-policy-binding $PROJECT_ID \  --member="serviceAccount:apigee-udca@$PROJECT_ID.iam.gserviceaccount.com" \  --role="roles/apigee.analyticsAgent"
    8. Service account:apigee-watcher,role:roles/apigee.runtimeAgent

      Create the account:

      gcloud iam service-accounts createapigee-watcher \  --display-name="apigee-watcher" \  --project $PROJECT_ID

      Assign the role:

      gcloud projects add-iam-policy-binding $PROJECT_ID \  --member="serviceAccount:apigee-watcher@$PROJECT_ID.iam.gserviceaccount.com" \  --role="roles/apigee.runtimeAgent"

SetworkloadIdentityEnabled: true and create service accounts

apigeectl creates Kubernetes service accounts for each Apigee hybrid component when you setworkloadIdentityEnabled: true in your overrides file and apply the changes.

  1. Add the bolded line below to youroverrides.yaml file under thegcp stanza. This enables Workload Identity for your installation and triggersapigeectl to create the Kubernetes service accounts when you apply the configuration:
    gcp:  projectID: "my-project-id"  name: "my-project-id"  region: "analytics-region"workloadIdentityEnabled: true
  2. Add the bolded lines below to youroverrides.yaml file under thecassandra stanza. This triggers the creation of theapigee-cassandra-backup Kubernetes service account:
    cassandra:  ...backup:    enabled: true
  3. Apply the changes withapigeectl with the--restore flag:
    $APIGEECTL_HOME/apigeectl apply -f overrides/overrides.yaml --restore
    Note: The--restore flag triggers creation of theapigee-cassandra-restore Kubernetes service account.
  4. Verify the service accounts with the following command:
    kubectl get sa -n $NAMESPACE

    Your output should look something like the following. The Kubernetes service accounts inbold are the ones you will need to annotate with your Google service accounts:

    NAME                                                         SECRETS   AGEapigee-cassandra-backup                                      1         11mapigee-cassandra-restore                                     1         11mapigee-cassandra-schema-setup-my-project-id-123abcd-sa       1         11mapigee-cassandra-schema-val-my-project-id-123abcd            1         11mapigee-cassandra-user-setup-my-project-id-123abcd-sa         1         11mapigee-connect-agent-my-project-id-123abcd-sa                1         11mapigee-datastore-default-sa                                  1         11mapigee-ingressgateway                                        1         11mapigee-ingressgateway-my-project-id-123abcd                  1         11mapigee-ingressgateway-manager                                1         11mapigee-init                                                  1         11mapigee-mart-my-project-id-123abcd-sa                         1         11mapigee-metrics-sa                                            1         11mapigee-mint-task-scheduler-my-project-id-123abcd-sa          1         11mapigee-redis-default-sa                                      1         11mapigee-redis-envoy-default-sa                                1         11mapigee-runtime-my-project-id-env-name-234bcde-sa             1         11mapigee-synchronizer-my-project-id-env-name-234bcde-sa        1         11mapigee-udca-my-project-id-123abcd-sa                         1         11mapigee-udca-my-project-id-env-name-234bcde-sa                1         11mapigee-watcher-my-project-id-123abcd-sa                      1         11mdefault                                                      1         11m

Annotate the Kubernetes service accounts with the Google service accounts

For each Apigee component annotate the corresponding Kubernetes service accounts with the Google service account for the component.

Org-level components

You will have only one instance of each Kubernetes service account for your Apigee org.

ComponentKubernetes Service AccountGoogle Service Account
Cassandraapigee-cassandra-backupapigee-cassandra
apigee-cassandra-restoreapigee-cassandra
apigee-cassandra-schema-setup-my-project-id-num-id1-saapigee-cassandra
apigee-cassandra-schema-val-my-project-id-num-id1apigee-cassandra
apigee-cassandra-user-setup-my-project-id-num-id1-saapigee-cassandra
apigee-datastore-default-saapigee-cassandra
Apigee Connectapigee-connect-agent-my-project-id-num-id1-saapigee-mart
MARTapigee-mart-my-project-id-num-id1-saapigee-mart
Metricsapigee-metrics-saapigee-metrics
UDCA (org-level)apigee-udca-my-project-id-num-id1-saapigee-udca
Watcherapigee-watcher-my-project-id-num-id1-saapigee-watcher

Env-level components

You will have one instance of each Kubernetes service account for each Apigee environment.

ComponentKubernetes Service AccountGoogle Service Account
Apigee Runtimeapigee-runtime-my-project-id-env-name-num-id2-saapigee-runtime
Synchronizerapigee-synchronizer-my-project-id-env-name-num-id2-saapigee-synchronizer
UDCA (env-level)apigee-udca-my-project-id-env-name-num-id2-saapigee-udca
IMPORTANT: If your service account names do not match the default names created bycreate-service-account, in the following commands replace the red service account name with the correct service account name for the component. For example, if your Cassandra service account is namedmy-cassandra-accnt-1, then replaceapigee-cassandra with that name in the command.

In the following commands use the Kubernetes service account names returned by thekubectl get sa -n $NAMESPACE command, for example:apigee-cassandra-schema-val-hybrid-example-project-123abcd.

In this procedure, for each Kubernetes service account, you will:

  • Bind the Kubernetes service account and the principal Google service account to theroles/iam.workloadIdentityUser IAM role.
  • Annotate the Kubernetes service account with the Google service account.
  1. Bind the roles and annotate the service accounts.

    Org-level components

    Annotate Kubernetes service accounts for the org-level components. You will need to do this once for each component in your Apigee organization.

    • Cassandra

      The Cassandra component has six associated Kubernetes service accounts:

      • apigee-cassandra-backup
      • apigee-cassandra-restore
      • apigee-cassandra-schema-setup
      • apigee-cassandra-schema-val(val = validation)
      • apigee-cassandra-user-setup
      • apigee-datastore-default

      Prod

      apigee-cassandra-backup

      1. Define theKSA_NAME andGSA_NAME environment variables:
        GSA_NAME="apigee-cassandra"KSA_NAME="apigee-cassandra-backup"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      apigee-cassandra-restore

      1. Redefine theKSA_NAME environment variable:

        KSA_NAME="apigee-cassandra-restore"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      apigee-cassandra-schema-setup-service-account-name

      1. Redefine theKSA_NAMEenvironment variable:

        KSA_NAME="apigee-cassandra-schema-setup-service-account-name"

        Bind the IAM role:

        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      2. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      apigee-cassandra-schema-val-service-account-name

      1. Redefine theKSA_NAMEenvironment variable:

        KSA_NAME="apigee-cassandra-schema-val-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      apigee-cassandra-user-setup-service-account-name

      1. Redefine theKSA_NAMEenvironment variable:

        KSA_NAME="apigee-cassandra-user-setup-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      apigee-datastore-default-sa

      1. Redefine theKSA_NAMEenvironment variable:

        KSA_NAME="apigee-datastore-default-sa"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      Non-prod

      apigee-cassandra-backup

      1. Define theKSA_NAME andGSA_NAME environment variables:
        GSA_NAME="apigee-non-prod"KSA_NAME="apigee-connect-agent-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com

      apigee-cassandra-restore

      1. Redefine theKSA_NAMEenvironment variable:

        KSA_NAME="apigee-cassandra-restore"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com

      apigee-cassandra-schema-setup-service-account-name

      1. Redefine theKSA_NAMEenvironment variable:

        KSA_NAME="apigee-cassandra-schema-setup-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com

      apigee-cassandra-schema-val-service-account-name

      1. Redefine theKSA_NAMEenvironment variable:

        KSA_NAME="apigee-cassandra-schema-val-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com

      apigee-cassandra-user-setup-service-account-name

      1. Redefine theKSA_NAMEenvironment variable:

        KSA_NAME="apigee-cassandra-user-setup-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com

      apigee-datastore-default-sa

      1. Redefine theKSA_NAMEenvironment variable:

        KSA_NAME="apigee-datastore-default-sa"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com
    • Apigee Connect

      Prod

      1. Define theKSA_NAME andGSA_NAME environment variables:
        GSA_NAME="apigee-mart"KSA_NAME="apigee-connect-agent-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      Non-prod

      1. Define theKSA_NAME environment variable:

        KSA_NAME="apigee-connect-agent-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com
    • MART

      Prod

      1. Define theKSA_NAME andGSA_NAME environment variables:

        GSA_NAME="apigee-mart"KSA_NAME="apigee-mart-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      Non-prod

      1. Define theKSA_NAME environment variable:

        KSA_NAME="apigee-mart-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com
    • Apigee metrics

      Prod

      1. Define theKSA_NAME andGSA_NAME environment variables:

        GSA_NAME="apigee-metrics"KSA_NAME="apigee-metrics-sa"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      Non-prod

      1. Define theKSA_NAME environment variable:

        KSA_NAME="apigee-metrics-sa"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com
    • UDCA (org-level)

      Prod

      1. Define theKSA_NAME andGSA_NAME environment variables:

        GSA_NAME="apigee-udca"KSA_NAME="apigee-udca-org-level-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      Non-prod

      1. Define theKSA_NAMEenvironment variables:

        KSA_NAME="apigee-udca-org-level-service-account-name"
      2. Bind the IAM role:
          gcloud iam service-accounts add-iam-policy-binding \    --role roles/iam.workloadIdentityUser \    --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \    $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
          kubectl annotate serviceaccount \    --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com
    • Apigee Watcher

      Prod

      1. Define theKSA_NAME andGSA_NAME environment variables:

        GSA_NAME="apigee-watcher"KSA_NAME="apigee-watcher-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      Non-prod

      1. Define theKSA_NAME environment variable:

        KSA_NAME="apigee-watcher-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com

    For each environment:

    • Runtime

      Prod

      1. Define theKSA_NAME andGSA_NAME environment variables:

        GSA_NAME="apigee-runtime"KSA_NAME="apigee-runtime-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      Non-prod

      1. Define theKSA_NAME environment variable:

        KSA_NAME="apigee-runtime-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com
    • Synchronizer

      Prod

      1. Define theKSA_NAME andGSA_NAME environment variables:

        GSA_NAME="apigee-synchronizer"KSA_NAME="apigee-synchronizer-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      Non-prod

      1. Define theKSA_NAME environment variable:

        KSA_NAME="apigee-synchronizer-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com
    • UDCA (env-level)

      Prod

      1. Define theKSA_NAME andGSA_NAME environment variables:

        GSA_NAME="apigee-udca"KSA_NAME="apigee-udca-env-level-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com

      Non-prod

      1. Define theKSA_NAME environment variable:

        KSA_NAME="apigee-udca-env-level-service-account-name"
      2. Bind the IAM role:
        gcloud iam service-accounts add-iam-policy-binding \  --role roles/iam.workloadIdentityUser \  --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]" \  $GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
      3. Annotate the service account:
        kubectl annotate serviceaccount \  --namespace $NAMESPACE $KSA_NAME iam.gke.io/gcp-service-account=apigee-non-prod@$PROJECT_ID.iam.gserviceaccount.com
  2. Validate if the steps worked:
    gcloud config set project $PROJECT_ID
    kubectl run --rm -it --image google/cloud-sdk:slim \  --namespace $NAMESPACE workload-identity-test\  -- gcloud auth list

    If you don't see a command prompt, try pressingEnter.

    If the steps were correctly run, you should see a response like the following:

    CredentialedAccountsACTIVEACCOUNT*GSA@PROJECT_ID.iam.gserviceaccount.com
  3. If upgrading from a previous install, clean up secrets that contained service account private keys:
    kubectl delete secrets -n $NAMESPACE $(k get secrets -n $NAMESPACE | grep svc-account | awk '{print $1}')
  4. Check logs:
    kubectl logs -n $NAMESPACE -l app=apigee=synchronizer,env=$ENV_NAME,org=$ORG_NAME apigee-synchronizer
  5. (Optional) You can see the status of your Kubernetes service accounts in theKubernetes: Workloads Overview page in the Google Cloud console.

    Go to Workloads

    Note: You may see an error status for theapigee-cassandra-backup andapigee-cassandra-restore service accounts. This is because you are not currently running backup or restore, and these processes have not been fully configured yet. For more information on Cassandra backup and restore, seefeedbackCassandra backup overview.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-17 UTC.