Skip to content

GCP Developer Authentication Guide: Local, CI & Kubernetes

This guide provides developers with the standard, secure methods for authenticating applications to Google Cloud Platform (GCP) resources from local development machines, CI pipelines and Kubernetes clusters.

The primary goal is to avoid using static, long-lived service account keys (JSON files), which are a security risk.

Instead, we will use a combination of two modern GCP features:

  1. Application Default Credentials (ADC): A standard feature in GCP client libraries. It allows your code to automatically find the correct credentials based on the environment it's running in, with no code changes.

  2. Workload Identity Federation (WIF): The technology that allows identities outside of GCP (like your local machine or a Kubernetes pod) to securely impersonate a GCP service account and get short-lived, temporary credentials.

Part 1: Local Development with Application Default Credentials (ADC)

When you're building and testing code on your local machine, you need a simple way to grant your code the same permissions you have.

The Concept

Application Default Credentials (ADC) is a strategy used by Google client libraries to automatically find credentials based on the environment. On your local machine, you can "log in" via the gcloud CLI, and ADC will use those credentials.

How to Use It

1. Install the gcloud CLI:

If you haven't already, install the Google Cloud CLI.

2. Log in and Set Up ADC

Run the following command in your terminal:

gcloud auth application-default login

This command will open a browser window, asking you to log in with your Google account (the one you use for GCP).

It will ask for permission to access your Google Cloud resources.

Once authorized, it stores your user credentials in a secure, well-known location on your file system.

3. Run Your Code (That's It!)

Google client libraries (e.g., for Python, Node.js, Go, Java) are built to automatically check for these credentials. You don't need to specify a key file path or write any special auth logic.

Example (Python):

# No key file or auth logic needed!
from google.cloud import storage

# The client library automatically finds the credentials
# created by `gcloud auth application-default login`.
client = storage.Client()

# Your code now runs with the permissions of your user account.
for bucket in client.list_buckets():
    print(bucket.name)

Your code will now run with the same IAM permissions that your user account has in the GCP project.

Local development in Docker/Podman

For your local docker/podman containers to use ADC, you need to share the ADC credentials file with the container.

  1. Locate the ADC credentials file on your host machine. By default, it is located at:

  2. Linux/macOS: ~/.config/gcloud/application_default_credentials.json

  3. Windows: %APPDATA%\gcloud\application_default_credentials.json

  4. When running your container, mount the directory containing the credentials file to the same path inside the container.

  5. Set the GOOGLE_APPLICATION_CREDENTIALS environment variable inside the container to point to the credentials file.
  6. Example Docker run command:
docker run -it --rm \
  -v ~/.config/gcloud:/root/.config/gcloud \
  -e GOOGLE_APPLICATION_CREDENTIALS=/root/.config/gcloud/application_default_credentials.json \
  your-image-name

Pro Tip: Impersonating a Service Account Locally

If you need to test your code as a specific service account (e.g., to test permissions), you can!

Ensure your user account has the "Service Account Token Creator" (roles/iam.serviceAccountTokenCreator) role on the target service account.

Run this command:

gcloud auth application-default login --impersonate-service-account=YOUR_SA_EMAIL@PROJECT.iam.gserviceaccount.com

Run your code. It now acts as the service account.

To stop, simply run: gcloud auth application-default login and you will login back under your standard identity.

Part 2: CI/CD with Workload Identity Federation (WIF)

When running code in CI/CD pipelines, you want to avoid using static service account keys. Instead, you can use Workload Identity Federation to obtain short-lived credentials.

The Concept

Workload Identity Federation (WIF) allows your CI/CD system to securely impersonate a GCP service account without using long-lived keys. You can use a GitLab JWT ID token in your pipelines and exchange it for GCP credentials of a specific service account. Alternatively, you can configure WIF to allow your GitLab identity to access GCP resources directly.

Basic setup

1. Create a GCP Service Account

Create a service account in GCP with the necessary IAM roles for your application. Alternatively, you can configure WIF to allow your GitLab identity to access GCP resources directly without a service account (see section ), but using a service account is generally recommended for better security and auditability.

2. Grant the Workload Identity Role to your GitLab identity

Locate your GitLab User ID (found in your GitLab profile settings). Grant the roles/iam.workloadIdentityUser role to the following principal on the service account you've just created:

principalSet://iam.googleapis.com/projects/550463210744/locations/global/workloadIdentityPools/cr-gitlab-fftrader/attribute.user_id/<USER_ID>

where <USER_ID> is your GitLab User ID.

3. Configure your GitLab CI/CD Pipeline

In your .gitlab-ci.yml, include the WIF template provided by the Cloud Platform team and set the necessary variables:

include:
  - project: 'devops/cicd-components/gitlab-templates'
    file: 'gitlab-fftrader-wif.yml'

example_job:
  stage: deploy
  variables:
    WORKLOAD_IDENTITY_PROJECT_NUMBER: 550463210744
    WORKLOAD_IDENTITY_POOL: "cr-gitlab-fftrader"
    WORKLOAD_IDENTITY_PROVIDER: "cr-gitlab-fftrader-jwt"
    SERVICE_ACCOUNT: "YOUR_SA_NAME@PROJECT_ID.iam.gserviceaccount.com"
  extends: .workload-identity # Injects before_script to pipeline with WIF configuration
  script:
    # Anything you need with access to GCP via Application Default Credentials...

The before_script will handle the authentication using WIF, and your script can use Application Default Credentials as usual.

Setup without service account impersonation

If you prefer to allow your GitLab identity to access GCP resources directly without using a service account, you can grant the necessary IAM roles directly to your GitLab identity principal. Locate your GitLab User ID (found in your GitLab profile settings) and grant the required roles (e.g., roles/storage.objectViewer) to the following principal:

principalSet://iam.googleapis.com/projects/550463210744/locations/global/workloadIdentityPools/cr-gitlab-fftrader/attribute.user_id/<USER_ID>

Then, in your .gitlab-ci.yml, you can use the alternative WIF template (.workload-identity-direct) as follows:

include:
  - project: "devops/cicd-components/gitlab-templates"
    file: "gitlab-fftrader-wif.yml"

example_job:
  stage: deploy
  variables:
    WORKLOAD_IDENTITY_PROJECT_NUMBER: 550463210744
    WORKLOAD_IDENTITY_POOL: "cr-gitlab-fftrader"
    WORKLOAD_IDENTITY_PROVIDER: "cr-gitlab-fftrader-jwt"
  extends: .workload-identity-direct # Injects before_script to pipeline with WIF configuration
  script:
    # Anything you need with access to GCP via Application Default Credentials...

Pro tip: Using gsutil with WIF

The gsutil command-line tool does not respect the prepared environment variable with the Application Default Credentials. You need to run gcloud auth login command first to authenticate gsutil:

  script:
    - gcloud auth login --cred-file $GOOGLE_APPLICATION_CREDENTIALS --project $GCP_PROJECT_ID
    - gsutil ls gs://your-bucket-name

Part 3: Kubernetes with Workload Identity Federation (WIF)

In Kubernetes, we don't have a "user" to log in as. Instead, we want our application (running in a Pod) to act as a specific Google Service Account (GSA).

Workload Identity Federation (WIF) allows a Kubernetes Service Account in your cluster to impersonate a GCP Service Account or grant access to GCP resources directly.

This process involves NO service account keys.

Method A: Grant access to the Kubernetes resources directly

To provide access with Workload Identity Federation for GKE, you create an IAM allow policy that grants access on a specific Google Cloud resource to a principal that corresponds to your application's identity. For example, you could give read permissions on a Cloud Storage bucket to all Pods that use the database-reader Kubernetes ServiceAccount.

Reference Kubernetes resources in IAM policies

In your IAM policy, you refer to a Kubernetes resource by using an IAM principal identifier to select the resource. This identifier has the following syntax:

Grant access based on a service account:

principal://iam.googleapis.com/projects/412451610001/locations/global/workloadIdentityPools/devops-309909.svc.id.goog/subject/ns/<NAMESPACE>/sa/<SERVICEACCOUNT>

Where <NAMESPACE> is the Kubernetes namespace and <SERVICEACCOUNT> is the Kubernetes Service Account name.

or

Grant access to all pods in a namespace:

principalSet://iam.googleapis.com/projects/412451610001/locations/global/workloadIdentityPools/devops-309909.svc.id.goog/namespace/<NAMESPACE>

Where <NAMESPACE> is the Kubernetes namespace.

Method B: Linking Kubernetes Service Account to Google Service Account

You can link a specific Kuibernetes Service Account to a Google Service Account to gain the same privileges the Google Service Account has.

How it Works

  1. Your Pod runs with a specific Kubernetes Service Account.

  2. You configure a "trust" relationship between your Kubernetes Service Account and a GCP Service Account.

  3. The GCP client libraries in your Pod (using ADC) automatically detect they are in GKE.

  4. ADC automatically exchanges the Kubernetes Service Account's token for a short-lived GCP Service Account token from the GKE metadata server.

  5. Your application transparently runs with the permissions of the GCP Service Account.

Setup

1. Create a GCP Service Account and grant it the necessary IAM roles for your application.
2. Create a Kubernetes Service Account (KSA) in your namespace.
3. Annotate your Kubernetes Service Account with the name of the GCP Service Account.
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-ksa-name
  namespace: my-k8s-namespace
  annotations:
    # This annotation links the Kubernetes Service Account to the GCP Service Account
    iam.gke.io/gcp-service-account: YOUR_SA_NAME@PROJECT_ID.iam.gserviceaccount.com
4. Use the Kubernetes Service Account in your Pod
apiVersion: apps/v1
kind: Deployment;
metadata:
  name: my-app
  namespace: my-k8s-namespace
spec:
  # ...
  template:
    metadata:
      # ...
    spec:
      # Use the annotated KSA
      serviceAccountName: my-ksa-name
      containers:
      - name: my-app-container
        image: gcr.io/my-project/my-app
        # ...

If you are using the Standard Service Chart provided by Cloud Platform team, just set this in your values.yaml:

serviceAccountName: my-ksa-name
5. That's it!

On GKE, the client libraries (ADC) inside your container will automatically detect this setup and perform the token exchange for you. Your code remains identical to the local development example.

The Payoff: Identical Application Code

The biggest benefit of ADC and WIF is that your application code does not change. The exact same code you wrote for local development will work perfectly inside your Kubernetes container or CI pipeline!

# This code works LOCALLY and in KUBERNETES (GKE or non-GKE)
# without any changes.
from google.cloud import storage

# ADC handles the "how" of getting credentials.
# - Locally: Uses gcloud login.
# - In K8s: Uses the WIF token exchange.
client = storage.Client()

for bucket in client.list_buckets():
    print(bucket.name)

By configuring the environment correctly, you free your application from managing authentication logic or handling sensitive key files.