GCP Customer Workload Identity
This guide is the canonical customer walkthrough for connecting a customer GCP project to Dart Cloud Functions (DCF) through Workload Identity Federation (WIF).
The current DCF GCP onboarding flow is:
-
The customer owns the GCP project.
-
The customer owns the GCP service account that DCF will impersonate.
-
The customer owns the workload identity pool and provider that trust DCF’s Kubernetes identity.
-
The customer grants
roles/iam.workloadIdentityUseron that service account to the federated DCF principal.
This setup is one-time per customer project/environment. It is not repeated for every function deployment or release unless the customer changes project, service account, or workload identity pool/provider.
This is the current customer-owned WIF model. Do not use the older
direct service-account pattern of granting roles/iam.serviceAccountTokenCreator
or roles/iam.serviceAccountUser to
serviceAccount:flux-gsa-dcf-dev@aortem-prod.iam.gserviceaccount.com for this
onboarding flow.
|
What The Customer Must Provide To DCF
After the customer-side setup is complete, enter these values in the DCF GCP integration form:
-
gcpProjectId -
serviceAccountEmail -
workloadIdentityProjectNumber -
workloadIdentityPool -
workloadIdentityProvider
Example:
-
gcpProjectId=venturseed-website-dev -
serviceAccountEmail=dcf-dev-1@venturseed-website-dev.iam.gserviceaccount.com -
workloadIdentityProjectNumber=1085359854476 -
workloadIdentityPool=dcf-gke-pool -
workloadIdentityProvider=dcf-gke-provider
Standard Customer Contract
To keep onboarding consistent across customers, standardize on these IDs unless the customer is explicitly reusing existing approved workload identity resources:
-
workloadIdentityPool=dcf-gke-pool -
workloadIdentityProvider=dcf-gke-provider
For most customers, only these values should vary:
-
gcpProjectId -
serviceAccountEmail -
workloadIdentityProjectNumber
Recommended Resource Names
To reduce support drift, recommend these customer-side names in the docs:
-
Customer service account ID:
dcf-<environment>-1 -
Workload identity pool ID:
dcf-gke-pool -
Workload identity provider ID:
dcf-gke-provider
Examples:
-
Development service account:
dcf-dev-1@<customer-project-id>.iam.gserviceaccount.com -
Production service account:
dcf-prod-1@<customer-project-id>.iam.gserviceaccount.com
The customer can use different names, but then the exact service account, project number, pool, and provider values entered in DCF must match what exists in GCP exactly.
Current DCF Identity Values
Use the DCF environment that matches the customer environment you are connecting.
Development
-
DCF OIDC issuer:
https://container.googleapis.com/v1/projects/aortem-prod/locations/us-central1/clusters/aortem-infrastructure-core-new -
DCF Kubernetes subject:
system:serviceaccount:dartcloudfunctions-dev:flux-system-dartcloudfunctions-dev
Production
-
DCF OIDC issuer:
https://container.googleapis.com/v1/projects/aortem-prod/locations/us-central1/clusters/aortem-infrastructure-core-new -
DCF Kubernetes subject:
system:serviceaccount:devops-poc:flux-system-dartcloudfunctions-prod
Customer Setup Steps
1. Choose The Customer Service Account
Create or select a customer-owned service account in the customer project. DCF will impersonate this service account after the workload identity exchange succeeds.
Example:
-
dcf-dev-1@venturseed-website-dev.iam.gserviceaccount.com
| The IAM binding that matters for onboarding is attached to the service account itself, not just the project IAM page. |
2. Create A Workload Identity Pool
In the customer project, create a workload identity pool that will host the provider trusted by DCF.
PROJECT_ID="venturseed-website-dev"
gcloud services enable \
iam.googleapis.com \
iamcredentials.googleapis.com \
sts.googleapis.com \
--project="$PROJECT_ID"
If those APIs are already enabled, this command is safe to rerun.
PROJECT_ID="venturseed-website-dev"
gcloud iam workload-identity-pools create "dcf-gke-pool" \
--project="$PROJECT_ID" \
--location="global" \
--display-name="DCF GKE Pool"
3. Create An OIDC Provider Trusted By DCF
Create an OIDC provider in that pool:
-
issuer-urimust match the DCF OIDC issuer for the environment. -
attribute-mappingmust includegoogle.subject=assertion.sub. -
allowed-audiencesshould match the current DCF bound token audience, which follows the same cluster URL used as the DCF issuer in the current runtime.
PROJECT_ID="venturseed-website-dev"
POOL_ID="dcf-gke-pool"
PROVIDER_ID="dcf-gke-provider"
DCF_ISSUER="https://container.googleapis.com/v1/projects/aortem-prod/locations/us-central1/clusters/aortem-infrastructure-core-new"
gcloud iam workload-identity-pools providers create-oidc "$PROVIDER_ID" \
--project="$PROJECT_ID" \
--location="global" \
--workload-identity-pool="$POOL_ID" \
--display-name="DCF Dev Provider" \
--issuer-uri="$DCF_ISSUER" \
--allowed-audiences="$DCF_ISSUER" \
--attribute-mapping="google.subject=assertion.sub"
If the customer already has a compatible pool and provider, reuse them instead of creating new ones.
4. Grant DCF Workload Identity User On The Customer Service Account
Grant roles/iam.workloadIdentityUser on the customer service account to the
federated DCF principal:
PROJECT_ID="venturseed-website-dev"
PROJECT_NUMBER="$(gcloud projects describe "$PROJECT_ID" --format='value(projectNumber)')"
CUSTOMER_SA="dcf-dev-1@venturseed-website-dev.iam.gserviceaccount.com"
POOL_ID="dcf-gke-pool"
DCF_SUBJECT="system:serviceaccount:dartcloudfunctions-dev:flux-system-dartcloudfunctions-dev"
gcloud iam service-accounts add-iam-policy-binding \
"$CUSTOMER_SA" \
--role="roles/iam.workloadIdentityUser" \
--member="principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/subject/$DCF_SUBJECT"
If the workload identity pool lives in a different identity-host project,
use that pool-host project’s numeric project number in the principal://…
member and enter that value into workloadIdentityProjectNumber.
|
5. Validate The Customer Setup
Before entering values in DCF, confirm the customer setup is active and matches the DCF runtime identity.
gcloud iam workload-identity-pools describe dcf-gke-pool \
--project=venturseed-website-dev \
--location=global
gcloud iam workload-identity-pools providers describe dcf-gke-provider \
--project=venturseed-website-dev \
--location=global \
--workload-identity-pool=dcf-gke-pool
gcloud iam service-accounts get-iam-policy \
dcf-dev-1@venturseed-website-dev.iam.gserviceaccount.com \
--project=venturseed-website-dev
gcloud services list --enabled \
--filter="NAME:(iam.googleapis.com OR iamcredentials.googleapis.com OR sts.googleapis.com)"
Expected results:
-
The workload identity pool is
ACTIVE. -
The workload identity provider is
ACTIVE. -
The provider attribute mapping includes
google.subject: assertion.sub. -
The provider
issuerUrimatches the DCF runtime issuer. -
The provider
allowedAudiencescontains that same DCF runtime issuer value. -
The service account IAM policy includes
roles/iam.workloadIdentityUserfor the correct federatedprincipal://…member. -
iam.googleapis.com,iamcredentials.googleapis.com, andsts.googleapis.comare enabled.
Complete Example For The Venturseed Development Project
PROJECT_ID="venturseed-website-dev"
PROJECT_NUMBER="$(gcloud projects describe "$PROJECT_ID" --format='value(projectNumber)')"
CUSTOMER_SA="dcf-dev-1@venturseed-website-dev.iam.gserviceaccount.com"
POOL_ID="dcf-gke-pool"
PROVIDER_ID="dcf-gke-provider"
DCF_ISSUER="https://container.googleapis.com/v1/projects/aortem-prod/locations/us-central1/clusters/aortem-infrastructure-core-new"
DCF_SUBJECT="system:serviceaccount:dartcloudfunctions-dev:flux-system-dartcloudfunctions-dev"
gcloud iam workload-identity-pools create "$POOL_ID" \
--project="$PROJECT_ID" \
--location="global" \
--display-name="DCF GKE Pool"
gcloud iam workload-identity-pools providers create-oidc "$PROVIDER_ID" \
--project="$PROJECT_ID" \
--location="global" \
--workload-identity-pool="$POOL_ID" \
--display-name="DCF Dev Provider" \
--issuer-uri="$DCF_ISSUER" \
--allowed-audiences="$DCF_ISSUER" \
--attribute-mapping="google.subject=assertion.sub"
gcloud iam service-accounts add-iam-policy-binding \
"$CUSTOMER_SA" \
--role="roles/iam.workloadIdentityUser" \
--member="principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$POOL_ID/subject/$DCF_SUBJECT"
Then enter:
-
gcpProjectId=venturseed-website-dev -
serviceAccountEmail=dcf-dev-1@venturseed-website-dev.iam.gserviceaccount.com -
workloadIdentityProjectNumber=1085359854476 -
workloadIdentityPool=dcf-gke-pool -
workloadIdentityProvider=dcf-gke-provider
Validated bootstrap checks for the Venturseed example:
-
pool state is
ACTIVE -
provider state is
ACTIVE -
provider mapping is
google.subject: assertion.sub -
provider
issuerUriandallowedAudiencesboth match the DCF development issuer -
the customer service account includes the required
roles/iam.workloadIdentityUserbinding for the DCF development subject -
iam.googleapis.com,iamcredentials.googleapis.com, andsts.googleapis.comare enabled -
the DCF values to save are:
venturseed-website-dev,dcf-dev-1@venturseed-website-dev.iam.gserviceaccount.com,1085359854476,dcf-gke-pool,dcf-gke-provider
Current Deployment Note
The current DCF GCP runner does not deploy arbitrary Cloud Functions directly. The implemented GCP path currently:
-
builds a container image with Cloud Build
-
pushes that image to Artifact Registry
-
updates the selected runtime target
Cloud Run is the standard runtime target. GKE remains available as an advanced target for enterprise customers that already provide the cluster, namespace, deployment, and container references.
For Cloud Run, DCF runs gcloud run deploy against the configured
serviceName. Public functions use --allow-unauthenticated; private
functions use --no-allow-unauthenticated.
For GKE, DCF updates an existing Kubernetes deployment image and waits for the rollout to complete.
That means WIF onboarding is only the trust step. The customer project still needs the separate Cloud Build, Artifact Registry, and runtime-target prerequisites required by the selected target.
Minimum Cloud Run setup normally includes:
-
enabling
run.googleapis.com,cloudbuild.googleapis.com,artifactregistry.googleapis.com,iam.googleapis.com,iamcredentials.googleapis.com, andsts.googleapis.com -
creating the target Artifact Registry Docker repository
-
granting the impersonated customer service account permissions to upload artifacts, start Cloud Build, write the resulting image, and update the Cloud Run service
-
granting
roles/iam.serviceAccountUseron the Cloud Run runtime service account if the deployment attaches a user-managed service identity
Security-first customers do not have to grant broad Cloud Run Admin by default.
roles/run.developer can be enough to create and update services, but making a
service public through IAM requires run.services.setIamPolicy or a customer
managed public roles/run.invoker binding.
Common Mistakes
-
Granting
roles/iam.serviceAccountTokenCreatortoserviceAccount:flux-gsa-dcf-dev@aortem-prod.iam.gserviceaccount.cominstead of grantingroles/iam.workloadIdentityUserto the federatedprincipal://…member. -
Checking only the project IAM page instead of the service account IAM policy.
-
Entering the customer project ID instead of the numeric workload identity host project number when the pool is hosted in a different project.
-
Reusing a provider that does not trust the DCF issuer or does not map
google.subject=assertion.sub.