Supported versions:
Unsupported versions:
This topic explains how to enable Workload Identity Federation for Apigee hybrid installations on AKS and EKS platforms.
For installations on GKE, follow the instructions in Enabling Workload Identity Federation for GKE on GKE.
Workload Identity Federation lets applications running outside Google Cloud impersonate a Google Cloud Platform service account by using credentials from an external identity provider.
Using Workload Identity Federation can help you improve security by letting applications use the authentication mechanisms that the external environment provides and can help replace service account keys.
For an overview, see Best practices for using Workload Identity Federation.
To use Workload Identity Federation with Apigee hybrid, first configure your cluster and then apply the feature to your Apigee hybrid installation.
These instructions assume you have already set up your Apigee hybrid installation. The IAM service accounts and Kubernetes service accounts are created during initial installation. See The Big Picture for an overview of installing Apigee hybrid.
For installations on AKS, Make sure you have enabled the OpenID Connect (OIDC) issuer. You must enable this feature so that Workload Identity Federation can access the OpenID Connect metadata and the JSON Web Key Set (JWKS) for the cluster.
gcloud configuration is set to your Google Cloud project ID with
the following command:
gcloud config get project
If needed, set the current gcloud configuration:
gcloud config set project PROJECT_ID
Check that the Security Token Service API is enabled with the following command:
gcloud services list --enabled --project PROJECT_ID | grep sts.googleapis.com
If the API is not enabled:
Enable the Security Token Service API.
Roles required to enable APIs
To enable APIs, you need the Service Usage Admin IAM
role (roles/serviceusage.serviceUsageAdmin), which
contains the serviceusage.services.enable permission. Learn how to grant
roles.
Enable the API with the following command:
gcloud services enable sts.googleapis.com --project PROJECT_ID
To get the permissions that you need to configure Workload Identity Federation, ask your administrator to grant you the following IAM roles on the project:
roles/iam.workloadIdentityPoolAdmin)roles/iam.serviceAccountAdmin)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.
Alternatively, the IAM Owner (roles/owner) basic role also
includes permissions to configure identity federation. You should not grant basic roles in a production environment, but you can grant them in a development or test environment.
To create a workload identity pool and provider, do the following:
az aks show -n NAME -g RESOURCE_GROUP --query "oidcIssuerProfile.issuerUrl" -otsv
Replace the following:
NAME: The name of the cluster.RESOURCE_GROUP: The resource group of the cluster.The command outputs the issuer URL. You will need the issuer URL in one of the following steps.
If the command doesn't return an issuer URL, verify that you've enabled the OIDC issuer feature.
aws eks describe-cluster --name NAME --query "cluster.identity.oidc.issuer" --output text
Replace NAME with the name of the cluster.
The command outputs the issuer URL. You need the issuer URL in one of the following steps.
Connect to your Kubernetes cluster and use `kubectl` to determine your cluster's issuer URL:
kubectl get --raw /.well-known/openid-configuration | jq -r .issuer
You need the issuer URL in one of the following steps.
kubectl get --raw /openid/v1/jwks > cluster-jwks.json
To check if your OIDC provider is publicly available, you should be able to access your provider URL with a CURL command and receive a 200 response.
gcloud iam workload-identity-pools create POOL_ID \
--location="global" \
--description="DESCRIPTION" \
--display-name="DISPLAY_NAME"
Replace the following:
POOL_ID: The unique ID for the pool.DISPLAY_NAME: (Optional) The name of the pool.DESCRIPTION: (Optional) A description of the pool that
you choose. This description appears when you grant access to pool
identities.For example:
gcloud iam workload-identity-pools create my-wi-pool --display-name="My workload pool" --description="My workload pool description"If your OIDC issuer is publicly accessible, create the provider with the following command:
gcloud iam workload-identity-pools providers create-oidc WORKLOAD_PROVIDER_ID \ --location="global" \ --workload-identity-pool="POOL_ID" \ --issuer-uri="ISSUER" \ --attribute-mapping="google.subject=assertion.sub"
If your OIDC issuer is not publicly accessible, create the provider with the following command:
gcloud iam workload-identity-pools providers create-oidc WORKLOAD_PROVIDER_ID \ --location="global" \ --workload-identity-pool="POOL_ID" \ --issuer-uri="ISSUER" \ --jwks-file="cluster-jwks.json" \ --attribute-mapping="google.subject=assertion.sub"
Replace the following:
WORKLOAD_PROVIDER_ID: A unique workload identity
pool provider ID of your choice.POOL_ID: The workload identity pool ID
that you created earlier.ISSUER: Use the issuer URL you determined earlier for the issuer URI .
attribute-mapping="google.subject=assertion.sub" maps the Kubernetes subject to the IAM subject.
To deploy a Kubernetes workload that can access Google Cloud resources, do the You first need to create a credential configuration file for each IAM service account:
gcloud iam service-accounts list --project PROJECT_ID
You will need to create the credential configuration files for the following IAM service accounts:
For production environments:
DISPLAY NAME EMAIL DISABLED apigee-cassandra apigee-cassandra@my_project_id.iam.gserviceaccount.com False apigee-mart apigee-mart@my_project_id.iam.gserviceaccount.com False apigee-metrics apigee-metrics@my_project_id.iam.gserviceaccount.com False apigee-runtime apigee-runtime@my_project_id.iam.gserviceaccount.com False apigee-synchronizer apigee-synchronizer@my_project_id.iam.gserviceaccount.com False apigee-udca apigee-udca@my_project_id.iam.gserviceaccount.com False apigee-watcher apigee-watcher@my_project_id.iam.gserviceaccount.com False
If you are using Monetization for Apigee hybrid on v1.15.1 and later, you will also need to create the credential configuration file for the apigee-mint-task-scheduler service account.
DISPLAY NAME EMAIL DISABLED ... apigee-mint-task-scheduler apigee-mint-task-scheduler@my_project_id.iam.gserviceaccount.com False ...
For non-production environments:
DISPLAY NAME EMAIL DISABLED apigee-non-prod apigee-non-prod@my-project.iam.gserviceaccount.com False
gcloud iam workload-identity-pools create-cred-config \ projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/WORKLOAD_PROVIDER_ID \ --service-account=SERVICE_ACCOUNT_EMAIL \ --credential-source-file=/var/run/service-account/token \ --credential-source-type=text \ --output-file=SERVICE_ACCOUNT_NAME-credential-configuration.json
gcloud iam workload-identity-pools create-cred-config \ projects/123123123123/locations/global/workloadIdentityPools/my-wi-pool/providers/my-wi-provider \ --service-account=apigee-cassandra@myhybridporg.iam.gserviceaccount.com \ --credential-source-file=/var/run/service-account/token \ --credential-source-type=text \ --output-file=apigee-cassandra-credential-configuration.json
Where:
PROJECT_NUMBER: The project number of the project containing the workload identity pool. This must be the project number instead of the project ID.
POOL_ID: The ID of the workload identity pool
WORKLOAD_PROVIDER_ID: The ID of the workload identity pool providerSERVICE_ACCOUNT_EMAIL: Email address of the service account, if you configured your Kubernetes ServiceAccount to use IAM service account impersonation.
The credential configuration file lets the [Cloud Client Libraries](/apis/docs/cloud-client-libraries), the gcloud CLI, and Terraform determine the following:
SERVICE_ACCOUNT_NAME-credential-configuration.json) into the following chart directories (or subdirectories thereof). These were the files you created in the Create the credential configuration files step.
| Service account | Apigee Helm chart directory |
|---|---|
apigee-cassandra |
apigee-datastore/ |
apigee-mart |
apigee-org/ |
apigee-metrics |
apigee-telemetry/ |
apigee-mint-task-scheduler(If using Monetization for Apigee hybrid) |
apigee-org/ |
apigee-runtime |
apigee-env/ |
apigee-synchronizer |
apigee-env/ |
apigee-udca |
apigee-org/apigee-env/ |
apigee-watcher |
apigee-org/ |
| Service account | Apigee Helm chart |
|---|---|
apigee-non-prod |
apigee-datastore/apigee-telemetry/apigee-org/apigee-env/ |
gcp:
workloadIdentity:
enabled: false # must be set to false to use Workload Identity Federation
federatedWorkloadIdentity:
enabled: true
audience: "AUDIENCE"
credentialSourceFile: "/var/run/service-account/token"
gcp:
workloadIdentity:
enabled: false
federatedWorkloadIdentity:
enabled: true
audience: "//iam.googleapis.com/projects/123123123123/locations/global/workloadIdentityPools/my-wi-pool/providers/my-wi-provider"
credentialSourceFile: "/var/run/service-account/token"
Where: AUDIENCE is the allowed audience of the Workload Identity Provider. You can find the value by searching any of the credential configuration files for the term audience: . The audience value is the same in each credential configuration file.
For example, in the following sample apigee-udca-credential-configuration.json file:
{
"universe_domain": "googleapis.com",
"type": "external_account:,"
"audience": "//iam.googleapis.com/projects/123123123123/locations/global/workloadIdentityPools/my-wi-pool/providers/my-wi-provider",
"subject_token_type": "urn:ietf:params:oauth: token-type:jwt",
"token_url": "https://sts.googleapis.com/v1/token",
"service
"impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/apigee-udca@my-project.iam.gserviceaccount.com:generateAccessToken",
"credential_source": {
"file": "/var/run/service-account/token",
"format": {
"type": "text"
}
}
}The audience value is //iam.googleapis.com/projects/123123123123/locations/global/workloadIdentityPools/my-wi-pool/providers/my-wi-provider.
Replace the value of serviceAccountPath with the credential source file for the corresponding IAM service account. This must be the path relative to the chart directory. For example:
envs:
- name: ENVIRONMENT_NAME
serviceAccountPaths:
synchronizer: apigee-synchronizer-credential-configuration.json
runtime: apigee-runtime-credential-configuration.json
udca: apigee-udca-credential-configuration.json
mart:
serviceAccountPath: apigee-mart-credential-configuration.json
connectAgent:
serviceAccountPath: apigee-mart-credential-configuration.json
metrics:
serviceAccountPath: apigee-metrics-credential-configuration.json
mintTaskScheduler: # Required for Monetization for Apigee hybrid (v1.15.1 and later)
serviceAccountPath: apigee-mint-task-scheduler-credential-configuration.json
udca:
serviceAccountPath: apigee-udca-credential-configuration.json
watcher:
serviceAccountPath: apigee-watcher-credential-configuration.json
kubectl create secret -n APIGEE_NAMESPACE generic SECRET_NAME --from-file="client_secret.json=CREDENTIAL_CONFIGURATION_FILE"
For example:
kubectl create secret -n apigee generic udca-workload-identity-secret --from-file="client_secret.json=./apigee-udca-credential-configuration.json"
serviceAccountRef with the new secret. For example:
udca: serviceAccountRef: udca-workload-identity-secret
Update the service account key, SAKEY for each service account in Vault with the corresponding credential source file. The procedure is similar for all components. For example, for UDCA:
SAKEY=$(cat .apigee-udca-credential-configuration.json); kubectl -n APIGEE_NAMESPACE exec vault-0 -- vault kv patch secret/apigee/orgsakeys udca="$SAKEY"
See Storing service account keys in Hashicorp Vault for more information.
helm upgrade command:
If you updated the Vault service account keys, update the apigee-operator chart.
helm upgrade operator apigee-operator/ \ --namespace APIGEE_NAMESPACE \ --atomic \ -f overrides.yaml
Update the rest of the affected charts in the following order:
helm upgrade datastore apigee-datastore/ \ --namespace APIGEE_NAMESPACE \ --atomic \ -f overrides.yaml
helm upgrade telemetry apigee-telemetry/ \ --namespace APIGEE_NAMESPACE \ --atomic \ -f overrides.yaml
helm upgrade $ORG_NAME apigee-org/ \ --namespace APIGEE_NAMESPACE \ --atomic \ -f overrides.yaml
Update the apigee-env chart for each env, replacing $ENV_RELEASE_NAME abdENV_NAME each time:
helm upgrade $ENV_RELEASE_NAME apigee-env/ \ --namespace APIGEE_NAMESPACE \ --atomic \ --set env=$ENV_NAME \ -f overrides.yaml
See the Apigee hybrid Helm reference for a list of components and their corresponding charts.
kubectl get sa -n APIGEE_NAMESPACE
| Kubernetes service accounts | IAM service account |
|---|---|
| Org-level Kubernetes service accounts | |
apigee-connect-agent-ORG_NAME-ORG_HASH_ID |
apigee-mart |
apigee-mart-ORG_NAME-ORG_HASH_ID |
apigee-mart |
apigee-metrics-apigee-telemetry |
apigee-metrics |
apigee-open-telemetry-collector-apigee-telemetry |
apigee-metrics |
apigee-mint-task-scheduler-ORG_NAME-ORG_HASH_ID(If using Monetization for Apigee hybrid) |
apigee-mint-task-scheduler |
apigee-udca-ORG_NAME-ORG_HASH_ID |
apigee-udca |
apigee-watcher-ORG_NAME-ORG_HASH_ID |
apigee-watcher |
| Env-level Kubernetes service accounts | |
apigee-runtime-ORG_NAME-ENV_NAME-ENV_HASH_ID |
apigee-runtime |
apigee-synchronizer-ORG_NAME-ENV_NAME-ENV_HASH_ID |
apigee-synchronizer |
| Cassandra backup and restore (if enabled) | |
apigee-cassandra-backup-sa |
apigee-cassandra |
apigee-cassandra-restore-sa |
apigee-cassandra |
Where:
ORG_NAME: The first 15 characters of the name of your organization.ORG_HASH_ID: A unique hash ID of your full organization name.ENV_NAME: The first 15 characters of the name of your environment.ENV_HASH_ID: A unique hash ID of your organization and environment names.For example:
apigee-connect-agent-myhybridorg-123abcdapigee-runtime-myhybridorg-prodenv-234bcdeGrant each Kubernetes service account access to impersonate the appropriate IAM service account with the following command:
gcloud iam service-accounts add-iam-policy-binding \
IAM_SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
--member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/MAPPED_SUBJECT" \
--role=roles/iam.workloadIdentityUserWhere:
IAM_SA_NAME: the name of the service account.PROJECT_ID: the ID of the project that is associated with the Apigee Org.PROJECT_NUMBER: the project number of the project where you created the workload identity pool.POOL_ID: the workload identity pool ID.MAPPED_SUBJECT: the Kubernetes ServiceAccount
from the claim in your ID token that you mapped to
google.subject. For example, if you mapped
google.subject=assertions.sub and your ID token contains
"sub": "system:serviceaccount:default:my-kubernetes-serviceaccount",
then MAPPED_SUBJECT is
system:serviceaccount:default:my-kubernetes-serviceaccount.
For more information about Workload Identity Federation and best practices, see Best practices for using Workload Identity Federation.
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2026-06-11 UTC.