Free lesson · GenAI Security Engineering
Deploy security infrastructure on GKE
Deploy full security stack with Helm umbrella chart. Configure GKE Workload Identity, network policies, and end-to-end verification.
Course: AI Security Engineering · Chapter 20 · Security Engineering Capstone
Free to read — no subscription required.
Introduction
Engineers often find that coordinating a multi-service AI platform on Kubernetes becomes a credential-management problem as much as an infrastructure problem: each service needs access to different Cloud APIs, and hardcoded keys create sprawling security debt with no clear audit trail. This lesson shows how to solve both problems at once by deploying the full AI security platform as a Helm umbrella chart while configuring Workload Identity for each service—eliminating key files entirely and enforcing least-privilege access at the IAM layer. By the end, you'll be able to deploy the platform to GKE and verify that each component authenticates to Secret Manager, Cloud Monitoring, and Cloud Storage through short-lived, automatically rotated credentials.
Key Terminology
- Workload Identity — A GKE mechanism that binds a Kubernetes service account to a Google Cloud IAM service account so pods authenticate to Cloud APIs via automatically rotated short-lived OAuth tokens instead of mounted key files.
- IAM service account — A Google Cloud identity (e.g.,
defense-pipeline-sa@<project>.iam.gserviceaccount.com) created withgcloud iam service-accounts createthat represents a workload rather than a human user, and to which IAM roles are attached. - Workload Identity binding — The IAM policy binding that associates a Kubernetes service account (expressed as
serviceAccount:<project>.svc.id.goog[<namespace>/<k8s-sa>]) with a Google Cloud IAM service account usingroles/iam.workloadIdentityUser, completing the trust chain between the cluster and Cloud IAM. - Least-privilege IAM role — A narrowly scoped Cloud IAM role—such as
roles/secretmanager.secretAccessorfor read-only secret access—assigned individually to each service's IAM account so that a compromised workload can only affect the APIs its role explicitly permits. - GKE metadata server — The node-level component that intercepts outbound credential requests from pods, resolves the Workload Identity binding for the pod's Kubernetes service account, and returns a short-lived OAuth token scoped to the corresponding IAM service account.
- umbrella chart annotation — The
iam.gke.io/gcp-service-accountkey written into a KubernetesServiceAccountmanifest viavalues.yaml, which the GKE metadata server reads to determine which IAM service account to impersonate when issuing tokens to that pod.
Concepts
Why Credential Files Are the Wrong Unit of Trust
When an AI security platform spans multiple services each needing different Cloud APIs, the naive approach is to export service account key files as JSON and mount them as Kubernetes Secrets. This creates credential sprawl: keys live on disk, in etcd, and in backups; they require manual rotation; and if any pod is compromised, the attacker inherits long-lived credentials scoped to everything that key can do. There is also no fine-grained audit trail—Cloud logs record a key ID, not the specific workload that used it.
Workload Identity eliminates the key file as an artifact entirely. Pods never possess a credential on disk; instead, the GKE metadata server intercepts each outbound Cloud API call, resolves which Kubernetes service account the pod is running as, looks up the bound IAM service account, and issues a short-lived OAuth token just-in-time. The token expires in under an hour and is rotated automatically with no operator intervention. Cloud audit logs record the IAM service account name on every request, so calls are attributable to the specific workload—not a shared key ID.
The Three-Step Pattern, Applied Once Per Service
Every service in the umbrella chart follows the same three-step setup that must be completed in Cloud IAM before the Helm chart is applied (see Code Walkthrough):
- Create the IAM service account (
gcloud iam service-accounts create) — establishes the Google Cloud identity that IAM policy will attach to. - Grant minimum permissions (
gcloud projects add-iam-policy-binding) — each service receives exactly the roles its workload requires. The defense pipeline getsroles/secretmanager.secretAccessor(read-only secret retrieval); the monitoring stack getsroles/monitoring.metricWriter; the compliance API getsroles/storage.objectCreator. No service's IAM account can touch another service's APIs. - Add the Workload Identity binding (
gcloud iam service-accounts add-iam-policy-bindingwithroles/iam.workloadIdentityUser) — authorizes the Kubernetes service account running in theai-securitynamespace to impersonate the IAM service account.
These three steps configure state in Cloud IAM that persists across redeployments. The Helm chart does not replicate this state; it only references it through a single annotation per service.
Annotations as the Bridge Between Kubernetes and IAM
The Helm umbrella chart's values.yaml centralizes one annotation per service—iam.gke.io/gcp-service-account—pointing at the IAM service account email. When Helm renders the sub-chart templates and applies them to the cluster, that annotation lands on each Kubernetes ServiceAccount object. The GKE metadata server reads it at pod scheduling time to determine which IAM service account to impersonate when the pod requests credentials.
The IAM binding (Cloud-side) and the annotation (cluster-side) must both be present and agree with each other. If the annotation is missing, the metadata server has no IAM account to impersonate. If the binding is missing, the impersonation is rejected even though the annotation is there. Either gap produces a permission-denied error on the pod's first Cloud API call. Running kubectl describe serviceaccount defense-pipeline -n ai-security confirms the annotation was written by Helm; inspecting the IAM policy confirms the binding exists on the Cloud side. Both checks are required before the defense pipeline can successfully read from Secret Manager.
The three-step Workload Identity pattern wires a Kubernetes service account to a Google Cloud identity without key files:
Code Walkthrough
Now that you understand how Workload Identity eliminates credential sprawl by binding Kubernetes service accounts to Google Cloud IAM accounts, you can wire each platform service to exactly the Cloud APIs it needs. The three-step process—create an IAM service account, grant minimum permissions, add the Workload Identity binding—repeats for each service in the umbrella chart.
The following commands configure Workload Identity for the defense pipeline, which requires read-only access to Secret Manager to retrieve LLM API keys:
Code snippetbash
1PROJECT_ID="your-project-id" 2NAMESPACE="ai-security" 3 4# Create the IAM service account for the defense pipeline 5gcloud iam service-accounts create defense-pipeline-sa \ 6 --display-name="Defense Pipeline SA" \ 7 --project="${PROJECT_ID}" 8 9# Grant read-only Secret Manager access (least privilege) 10gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ 11 --member="serviceAccount:defense-pipeline-sa@${PROJECT_ID}.iam.gserviceaccount.com" \ 12 --role="roles/secretmanager.secretAccessor" 13 14# Bind the Kubernetes service account to the IAM account 15gcloud iam service-accounts add-iam-policy-binding \ 16 "defense-pipeline-sa@${PROJECT_ID}.iam.gserviceaccount.com" \ 17 --member="serviceAccount:${PROJECT_ID}.svc.id.goog[${NAMESPACE}/defense-pipeline]" \ 18 --role="roles/iam.workloadIdentityUser"
Repeat this pattern for the monitoring stack (using roles/monitoring.metricWriter) and the compliance API (using roles/storage.objectCreator). Once the IAM bindings exist, the Helm umbrella chart propagates the annotation that links each Kubernetes service account to its IAM counterpart. A single values.yaml excerpt defines all three annotations in one place, so sub-chart templates inject them automatically during helm install:
Code snippetyaml
1defensePipeline: 2 serviceAccount: 3 annotations: 4 iam.gke.io/gcp-service-account: "defense-pipeline-sa@your-project-id.iam.gserviceaccount.com" 5 6monitoring: 7 serviceAccount: 8 annotations: 9 iam.gke.io/gcp-service-account: "monitoring-sa@your-project-id.iam.gserviceaccount.com" 10 11complianceApi: 12 serviceAccount: 13 annotations: 14 iam.gke.io/gcp-service-account: "compliance-api-sa@your-project-id.iam.gserviceaccount.com"
When Helm renders the sub-chart templates, these annotations are written into each Kubernetes ServiceAccount manifest. The defense pipeline pod never reads a key file; the GKE metadata server intercepts its credential requests and exchanges the Workload Identity binding for a short-lived OAuth token scoped to Secret Manager reads only. The monitoring stack receives an equally narrow token scoped to metric writes, and the compliance API receives one scoped to Cloud Storage object creation—each service is isolated from the others' APIs at the IAM layer.
Verify by running kubectl describe serviceaccount defense-pipeline -n ai-security and confirming the iam.gke.io/gcp-service-account annotation is present, then hitting the defense pipeline's /health endpoint and checking that its response reports a successful Secret Manager connection rather than an authentication error.
Do's and Don'ts
Now that you have worked through the implementation, the practices below separate a durable approach from a fragile one.
Do's
- ✓Do repeat the three-step Workload Identity pattern—
gcloud iam service-accounts create,add-iam-policy-bindingfor the scoped role, thenadd-iam-policy-bindingforroles/iam.workloadIdentityUser—for every service in the umbrella chart — skipping or reordering any step leaves the Kubernetes service account without a valid token exchange path, causing the GKE metadata server to reject credential requests at runtime. - ✓Do assign the narrowest predefined role each service actually calls:
roles/secretmanager.secretAccessorfor the defense pipeline,roles/monitoring.metricWriterfor the monitoring stack, androles/storage.objectCreatorfor the compliance API — broader roles likeroles/editorsilently grant each pod access to every other service's APIs, eliminating the per-service IAM isolation that Workload Identity is designed to enforce. - ✓Do centralize all three
iam.gke.io/gcp-service-accountannotations in the umbrella chart'svalues.yamlso sub-chart templates inject them automatically duringhelm install— hardcoding annotations inside individual sub-chart templates breaks the single-source-of-truth model and forces manual edits in multiple files whenever a project ID or service account name changes.
Don'ts
- ✗Don't hardcode or mount GCP service account key files in pods instead of using Workload Identity — key files create persistent, manually rotated credentials with no automatic audit trail; the entire point of the
gcloud iam service-accounts add-iam-policy-binding … --role="roles/iam.workloadIdentityUser"binding is to let the GKE metadata server issue short-lived OAuth tokens so key files never exist on the node. - ✗Don't reuse a single IAM service account (e.g.,
defense-pipeline-sa) for multiple services by granting it the union of all required roles — this collapses the per-service isolation boundary: a compromised defense pipeline pod would inheritroles/monitoring.metricWriterandroles/storage.objectCreatoralongside its ownsecretAccessor, which is exactly the credential-sprawl problem Workload Identity is meant to solve. - ✗Don't skip the post-deploy verification step of running
kubectl describe serviceaccount defense-pipeline -n ai-securityand checking the/healthendpoint for a successful Secret Manager connection — a missingiam.gke.io/gcp-service-accountannotation (e.g., from a Helm values typo or a forgottenhelm upgrade) causes the pod to fall through to the node's default service account and fail silently with authentication errors rather than a clear startup crash.
This lesson is free to read. Its 3 hands-on labs — real code, in a cloud IDE — are part of the GenAI Security Engineering subscription.
From · cancel anytime
More free lessons in AI Security Engineering
- Ch 11Deploy secure MCP infrastructure on GKE
- Ch 12Monitor GKE security posture continuously
- Ch 13Deploy LLM API gateway on GKE with LiteLLM
- Ch 14Deploy secrets infrastructure on GKE with Workload Identity
- Ch 17Deploy security monitoring stack on GKE
- Ch 18Deploy incident response automation on GKE
- Ch 20Deploy security infrastructure on GKEYou are here