Skip to content

Instantly share code, notes, and snippets.

@pre
Last active March 27, 2025 13:24
Show Gist options
  • Save pre/3c989b593e41cebbfe2f4b5b18d33a1b to your computer and use it in GitHub Desktop.
Save pre/3c989b593e41cebbfe2f4b5b18d33a1b to your computer and use it in GitHub Desktop.
Google Workload Identity Federation (WIF) using a Kubernetes Service Account
SERVICE_ACCOUNT_NAME="example-sa"
GOOGLE_PROJECT_NAME="example-google-project"
GOOGLE_PROJECT_ID="123456"
PROVIDER_NAME="example-provider"
POOL_NAME="example-pool"
cat >ksa.json <<EOF
{
"type": "external_account",
"audience": "//iam.googleapis.com/projects/${GOOGLE_PROJECT_ID}/locations/global/workloadIdentityPools/${PROVIDER_NAME}/providers/${POOL_NAME}",
"subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
"token_url": "https://sts.googleapis.com/v1/token",
"credential_source": {
"file": "/var/run/secrets/tokens/gcp-token"
},
"service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${SERVICE_ACCOUNT_NAME}@${GOOGLE_PROJECT_NAME}.iam.gserviceaccount.com:generateAccessToken"
}
EOF
export GOOGLE_APPLICATION_CREDENTIALS=ksa.json
gcloud auth revoke
gcloud auth login --cred-file=$GOOGLE_APPLICATION_CREDENTIALS
gcloud auth print-access-token
gcloud storage cp gs://example-bucket/test.txt .
data "google_project" "default" {
project_id = var.GOOGLE_PROJECT
}
data "google_iam_workload_identity_pool" "default" {
provider = google
workload_identity_pool_id = var.EXAMPLE_ENV
}
resource "google_service_account" "default" {
account_id = "${var.EXAMPLE_ENV}-workload-default"
display_name = "${var.EXAMPLE_ENV} Workload Identity of example"
}
resource "google_service_account_iam_binding" "default" {
service_account_id = google_service_account.default.name
role = "roles/iam.workloadIdentityUser"
members = [
"principalSet://iam.googleapis.com/projects/${data.google_project.default.number}/locations/global/workloadIdentityPools/${data.google_iam_workload_identity_pool.default.workload_identity_pool_id}/attribute.subject/system:serviceaccount:k8s_namespace_name:k8s_serviceaccount_name",
"principalSet://iam.googleapis.com/projects/${data.google_project.default.number}/locations/global/workloadIdentityPools/${data.google_iam_workload_identity_pool.default.workload_identity_pool_id}/attribute.google.subject/system:serviceaccount:k8s_namespace_name:k8s_serviceaccount_name",
]
}
resource "google_project_iam_binding" "k8s_authenticators" {
project = var.GOOGLE_PROJECT
role = "roles/iam.serviceAccountTokenCreator"
members = [
"serviceAccount:${google_service_account.default.email}",
]
}
variable "EXAMPLE_ENV" {}
variable "cluster_issuer" {
default = "https://example.com"
}
data "google_project" "default" {}
resource "google_project_service" "iam_credentials" {
project = data.google_project.default.project_id
service = "iamcredentials.googleapis.com"
disable_on_destroy = false
}
resource "google_iam_workload_identity_pool" "default" {
provider = google
workload_identity_pool_id = var.EXAMPLE_ENV
display_name = "${var.EXAMPLE_ENV} workload identity pool"
}
resource "google_iam_workload_identity_pool_provider" "default" {
workload_identity_pool_id = google_iam_workload_identity_pool.default.workload_identity_pool_id
workload_identity_pool_provider_id = var.EXAMPLE_ENV
display_name = "${var.EXAMPLE_ENV} Identity Provider"
attribute_mapping = {
"google.subject" = "assertion.sub"
"attribute.subject" = "assertion.sub"
}
oidc {
allowed_audiences = ["sts.googleapis.com"]
issuer_uri = var.cluster_issuer
}
}
apiVersion: v1
kind: Namespace
metadata:
name: example-ns
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: example-sa
namespace: example-ns
---
apiVersion: v1
kind: Pod
metadata:
name: dt-1
namespace: example-ns
spec:
serviceAccountName: example-sa
containers:
- name: gcs-access-container
image: google/cloud-sdk:latest
command: ["tail", "-f", "/dev/null"]
env:
- name: GOOGLE_APPLICATION_CREDENTIALS
value: "/gcp/creds/sts-creds.json"
volumeMounts:
- name: gcp-token-volume
mountPath: "/var/run/secrets/tokens"
readOnly: true
- mountPath: /gcp/creds
name: gcp-config-vol
readOnly: true
volumes:
- name: gcp-token-volume
projected:
sources:
- serviceAccountToken:
path: "gcp-token"
expirationSeconds: 36000
audience: "sts.googleapis.com"
- name: gcp-config-vol
configMap:
name: gcp-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: gcp-config
namespace: example-ns
data:
# Change
# - GOOGLE_PROJECT_NAME
# - GOOGLE_PROJECT_ID
# - example-*
sts-creds.json: |
{
"type": "external_account",
"audience": "//iam.googleapis.com/projects/GOOGLE_PROJECT_ID/locations/global/workloadIdentityPools/example-pool/providers/example-provider",
"subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
"token_url": "https://sts.googleapis.com/v1/token",
"credential_source": {
"file": "/var/run/secrets/tokens/gcp-token"
},
"service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/example-workload-default@GOOGLE_PROJECT_NAME.iam.gserviceaccount.com:generateAccessToken"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment