Zero Trust CI/CD: Keyless Bitbucket Deployment on Google Cloud
Using static Service Account (SA) keys in CI/CD pipelines has long been a common method for authenticating to Google Cloud Platform (GCP). However, storing long-lived credentials inside external pipeline environment vari
Using static Service Account (SA) keys in CI/CD pipelines has long been a common method for authenticating to Google Cloud Platform (GCP). However, storing long-lived credentials inside external pipeline environment variables introduces severe security vulnerabilities and ongoing operational friction.
Google Mandiant demonstrated in a threat intelligence blog post (Holes in Your Bitbucket: Why Your CI/CD Pipeline Is Leaking Secrets) that secret variables in Bitbucket pipelines can easily be extracted from environment variables during runtime. Moving away from static JSON keys toward Google Cloud Workload Identity Federation (WIF) provides a modern, keyless authentication mechanism that leverages OpenID Connect (OIDC) to exchange short-lived tokens, eliminating the risks associated with static credential management.
Why Service Account Keys Are a Bad Security Practice
While Atlassian Bitbucket documentation describes deployment to Google Cloud using Service Account keys, relying on traditional static JSON key files introduces two fundamental security and operational flaws:
High Security Risk & Lack of Traceability: Service account keys do not expire automatically and carry persistent security exposure. They lack strict origin traceability and can easily be copied, downloaded, or exfiltrated to execute commands anywhere outside Bitbucket without network restrictions or audit context. If a key is compromised, malicious actors gain unrestricted access until it is manually identified and revoked.
Management & Operational Overhead: Even if key expiration limits are configured, security compliance mandates continuous key lifecycle management, including periodic rotation and distribution across multiple repositories and workspaces. This creates substantial administrative overhead for platform engineering teams and risks pipeline failures when keys expire or are revoked prematurely.
Introducing Workload Identity Federation (WIF)
Workload Identity Federation establishes direct federated trust between Atlassian Bitbucket, acting as the Identity Provider and Google Cloud using OpenID Connect (OIDC) over the OAuth 2.0 framework. While OAuth 2.0 handles authorization, deciding what resources can be accessed, OIDC adds authentication verifying identity.
Key benefits of WIF include:
Short-Lived Token Exchange: Bitbucket generates a temporary OIDC identity token for each pipeline step. Workload Identity Federation validates this token and exchanges it for a short-lived access token to Google Cloud, valid strictly for the duration of the job.
Fine-Grained Scope Control: Access permissions can be tightly scoped per Bitbucket workspace, project, repository, or down to a specific deployment environment pipeline (e.g., staging vs. production).
Migrating Bitbucket Pipelines from using Service Account Keys to Google Cloud Workload Identity Federation
Before configuring Workload Identity Federation, gather your Bitbucket workspace OIDC configurations from your repository admin setting page.
You will need the following details from Bitbucket Workspace :
- Identity Provider URL:
https://api.bitbucket.org/2.0/workspaces/WORKSPACE_ID/pipelines-config/identity/oidc - Audience:
ari:cloud:bitbucket::workspace/WORKSPACE_UUID
Bitbucket issues an OIDC token claim payload during pipeline execution structured as follows:
{
"sub": "{REPOSITORY_UUID}:{stepUuid}",
"aud": "ari:cloud:bitbucket::workspace/WORKSPACE_UUID",
"stepUuid": "{xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx}",
"iss": "https://api.bitbucket.org/2.0/workspaces/WORKSPACE_ID/pipelines-config/identity/oidc",
"repositoryUuid": "{REPOSITORY_UUID}",
"branchName": "xxxxxxxxx",
"exp": "xxxxxxxxxx",
"iat": "xxxxxxxxxx",
"pipelineUuid": "{xxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxx}",
"workspaceUuid": "{WORKSPACE_UUID}"
}
Bitbucket OpenID Connect settings page looks like this: https://bitbucket.org/WORKSPACE_ID/REPO_ID/admin/pipelines/openid-connect
Step 1: Enable and Set Up WIF in Target GCP Projects
To establish federated authentication between Bitbucket Pipelines and GCP, create a Workload Identity Pool and Provider in your target GCP project.
1.1 Create a Workload Identity Pool
Create a global Workload Identity Pool dedicated to Bitbucket:
gcloud iam workload-identity-pools create bitbucket \
--location="global" \
--description="Bitbucket Workload Identity Pool" \
--display-name="Bitbucket"
1.2 Create the Workload Identity Provider
Configure an OIDC provider that trusts Bitbucket's issuer URL and maps claims (such as workspace UUID, repository UUID, and deployment environment) to Google attributes:
gcloud iam workload-identity-pools providers create-oidc bitbucket \
--location="global" \
--display-name="Bitbucket" \
--description="Bitbucket Identity Provider" \
--workload-identity-pool="bitbucket" \
--issuer-uri="https://api.bitbucket.org/2.0/workspaces/WORKSPACE_ID/pipelines-config/identity/oidc" \
--allowed-audiences="ari:cloud:bitbucket::workspace/WORKSPACE_UUID" \
--attribute-mapping="google.subject=assertion.sub,attribute.workspace_uuid=assertion.workspaceUuid,attribute.repository_uuid=assertion.repositoryUuid,attribute.deployment_env_uuid=assertion.deploymentEnvironmentUuid"
1.3 Map Bitbucket Identity to the GCP Service Account
Grant your Bitbucket Workspace permission to impersonate the target GCP existing Service Account by binding the roles/iam.workloadIdentityUser role:
gcloud iam service-accounts add-iam-policy-binding bitbucket-pipelines@PROJECT_ID.iam.gserviceaccount.com \
--role=roles/iam.workloadIdentityUser \
--member="principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/bitbucket/attribute.workspace_uuid/{WORKSPACE_UUID}"
Step 2: Update Bitbucket Pipelines to Use OIDC Authentication
Once Workload Identity Federation and the Identity Pool are configured, update your bitbucket-pipelines.yml configuration.
Legacy Pipeline Configuration (Using Static SA Keys):
pipelines:
default:
- step:
name: Deployment Step
script:
- gcloud auth activate-service-account --key-file <(echo "${GCLOUD_DEPLOYER_KEYFILE}" | base64 --decode --ignore-garbage)
- gcloud config set project $GCLOUD_PROJECT
To migrate your pipeline to OIDC authentication, first update each pipeline step requiring Google Cloud access by enabling oidc: true. This allows Bitbucket to generate an OIDC token during execution, which you then export from the $BITBUCKET_STEP_OIDC_TOKEN environment variable to a temporary file for gcloud usage.
Next, update your authentication commands by switching
from gcloud auth activate-service-account --key-file=file.json
to gcloud auth login --cred-file=file.json.
Finally, update your workspace variables to replace the legacy key variable (GCLOUD_DEPLOYER_KEYFILE) with a reference pointing to your credential configuration file (GCLOUD_DEPLOYER_CREDFILE).
Migrated Pipeline Configuration (Using Keyless WIF via OIDC):
pipelines:
default:
- step:
name: Deployment Step with OIDC
oidc: true
script:
- echo $BITBUCKET_STEP_OIDC_TOKEN > /tmp/bitbucket-step-oidc-token.txt
- gcloud auth login --cred-file <(echo "$GCLOUD_DEPLOYER_CREDFILE")
- gcloud config set project $GCLOUD_PROJECT
Step 3: Remove Bitbucket Workspace Level GCP SA Keys
After validating that the updated pipeline runs and authenticates successfully using Workload Identity Federation, navigate to your Bitbucket Workspace or Repository Settings to permanently delete the legacy Service Account key variables, such as GCLOUD_DEPLOYER_KEYFILE.
Finally, navigate to the Google Cloud Console or run gcloud iam service-accounts keys delete to revoke and delete the corresponding static Service Account JSON keys from GCP.
Summary & Best Practices
Migrating from static Service Account keys to Workload Identity Federation aligns your CI/CD workflows with Zero Trust security principles. By enforcing keyless authentication with short-lived OIDC tokens, you eliminate secret leakage risks, remove rotation management overhead, and gain fine-grained control over your Google Cloud deployments.
To maximize your security posture during and after migration:
Apply Least Privilege: Restrict IAM role permissions on target GCP Service Accounts to only the explicit roles required for deployment.
Leverage Fine-Grained Attribute Mappings: Use WIF attribute conditions to strictly isolate non-production environments from production infrastructure based on repository UUIDs, branch names, or deployment environments.
Audit Organization Workflows: Review active pipelines across your repositories to ensure all legacy gcloud auth activate-service-account commands and static key variables are fully removed.
Reference links:
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.



