Workload Indentity in Google Kubernetes Engine
Workload Identity allows workloads (applications) in GKE clusters to impersonate Identity and Access Management (IAM) service accounts to access other Google Cloud services.
This document explains how to configure and use Workload Identity in GKE. The guide is divided into two parts: one for Kubernetes cluster administrators and one for application developers.
Useful References
- Official Guide: Use Workload Identity in GKE
- IAM basic and predefined roles reference
- Git branch with the PoC
GKE Administrators Part
The next instructions demonstrate general steps to prepare a workload identity for a GKE namespace by Terraform code. In this particular example we will grant permissions to an application to view objects in GCP Object Storage bucket.
There are 3 configuration stages (in any order): 1. IAM configuration. 2. Target GCP service provision. 3. Kubernetes Service Account configuration
1. IAM Configuration
It makes sense to create the next 3 resources in the Terraform stage related to IAM (https://bitbucket.org/jacksonlaboratory/terraform-prod/src/main/src/jax-cluster-nc/stages/00_iam/)
1.1. Google Service Account creation:
resource "google_service_account" "k8s_workload_identity_poc" {
account_id = "k8s-workload-identity-poc"
project = var.project_name
display_name = "Service Account for Kubernetes Workload Identity PoC"
}
1.2. Grant the Service Account required permissions:
resource "google_project_iam_member" "k8s_workload_identity_poc" {
member = "serviceAccount:${google_service_account.k8s_workload_identity_poc.email}"
project = var.project_name
role = "roles/storage.objectViewer" # https://cloud.google.com/iam/docs/understanding-roles
}
Note: Change the role to grant desired permissions. In this example we grant permissions to view objects in all buckets.
1.3. Allow specific Kubernetes Service Account to use the created AIM Service Account:
resource "google_service_account_iam_member" "k8s_workload_identity_poc_binding" {
service_account_id = "projects/${var.project_name}/serviceAccounts/${google_service_account.k8s_workload_identity_poc.email}"
role = "roles/iam.workloadIdentityUser"
member = "serviceAccount:${var.project_name}.svc.id.goog[${var.namespace}/workload-identity-poc]"
}
Notes: * Replace ${var.namespace} by a namespace with the desired Kubernetes Service Account * Replace workload-identity-poc by the desired Kubernetes Service Account name.
2. Target GCP Service Provision
It makes sense to provision infrastructure in 01_root_infra terraform stage. In this particular example an Object Storage Bucket is created:
resource "google_storage_bucket" "workload-identity-poc" {
name = "jax-compsci-nc-${var.environment}-poc-workload"
location = local.location
force_destroy = true
uniform_bucket_level_access = true
public_access_prevention = "enforced"
}
3. Kubernetes Service Account Creation
It makes sense to create Kubernetes service accounts along with the namespace creation in 02_k8s_resources terraform stage
resource "kubernetes_service_account" "k8s_workload_identity_poc" {
metadata {
name = "workload-identity-poc" # Replace by Desired KSA name
namespace = dev # Replace by the application namespace
annotations = {
"iam.gke.io/gcp-service-account" = "k8s-workload-identity-poc@${var.project_name}.iam.gserviceaccount.com"
}
}
}
Notes: * Replace namespace value by the application namespace * Replace k8s-workload-identity-poc by account_id from "1. IAM Configuration" stage.
Guide for Application Developers
This section outlines the procedure to configure a Kubernetes pod or container to use a pre-existing IAM Service Account, thereby gaining access to another GCP service. To configure container permissions select a proper Kubernetes Service Account (KSA). The creation of a privileged KSA takes place in Step 3 of the IAM Configuration section detailed in this guide above.
Here is an example of a Pod configuration to use workload-identity-poc KSA in order to get access to a GCP Object Storage bucket:
# application-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: dev
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
serviceAccountName: workload-identity-poc
containers:
- name: my-app
image: google/cloud-sdk:alpine
command: [ "/bin/sh" ] # Override the default command
args: [ "-c", "echo 'Content:'; gsutil ls gs://jax-compsci-nc-dev-poc-workload; sleep 3600" ]
In this example we use google/cloud-sdk:alpine Docker image to list all objects inside jax-compsci-nc-dev-poc-workload GCP Object Storage bucket. The pod is authorized to do that because it uses workload-identity-poc KSA that configured to use k8s-workload-identity-poc@jax-compsci-nc-dev-01.iam.gserviceaccount.com Google Service Account (see "3. Kubernetes Service Account Creation") that had been created and configured in 1.1 part of IAM Configuration.
Example of the pod output: