An Auditor’s Checklist for Securing Ruby Backends on Google Cloud
If your GKE cluster doesn’t already have Workload Identity enabled, you’ll need to enable it. This is typically done during cluster creation or by updating an existing cluster.
Enabling during cluster creation:
Using gcloud:
gcloud container clusters create CLUSTER_NAME \
--zone COMPUTE_ZONE \
--workload-pool PROJECT_ID.svc.id.goog
Replace CLUSTER_NAME, COMPUTE_ZONE, and PROJECT_ID with your specific values.
Enabling on an existing cluster:
You can update an existing cluster to enable Workload Identity. Note that this might require a node pool upgrade.
gcloud container clusters update CLUSTER_NAME \
--zone COMPUTE_ZONE \
--update-addons WorkloadIdentity=ENABLED
Step 2: Create Google Cloud Service Account (GSA)
Create a dedicated GSA for your Ruby application. Avoid using the default Compute Engine service account.
gcloud iam service-accounts create ruby-app-sa \
--display-name "Ruby Application Service Account"
Step 3: Grant Necessary Permissions to GSA
Assign the minimum required IAM roles to the newly created GSA. For example, if your Ruby app needs to read from a Cloud Storage bucket:
gcloud projects add-iam-policy-binding PROJECT_ID \
--member "serviceAccount:ruby-app-sa@PROJECT_ID.iam.gserviceaccount.com" \
--role "roles/storage.objectViewer"
Replace PROJECT_ID with your actual project ID.
Step 4: Create Kubernetes Service Account (KSA)
Create a KSA within your GKE cluster that your application pods will use.
apiVersion: v1 kind: ServiceAccount metadata: name: ruby-app-ksa namespace: default # Or your application's namespace
Step 5: Bind KSA to GSA
This is the crucial step where you link the KSA to the GSA. This is done by annotating the KSA with the GSA’s identity.
gcloud container clusters get-credentials CLUSTER_NAME --zone COMPUTE_ZONE --project PROJECT_ID
kubectl annotate serviceaccount ruby-app-ksa \
--namespace default \
iam.gke.io/gcp-service-account=ruby-app-sa@PROJECT_ID.iam.gserviceaccount.com
Step 6: Configure Ruby Application to Use Workload Identity
Your Ruby application, when running within the GKE pod, will automatically pick up the credentials of the bound GSA. You can use the Google Cloud Client Libraries for Ruby. Ensure you have the google-cloud-storage gem (or relevant gem for other services) installed.
require "google/cloud/storage"
# The client library automatically detects the Workload Identity credentials
# when running in a GKE pod with the correct Workload Identity configuration.
storage = Google::Cloud::Storage.new
# Example: Listing buckets (requires roles/storage.admin or similar)
# If only roles/storage.objectViewer is granted, this might fail.
# Adjust operations based on the granted permissions.
begin
puts "Buckets:"
storage.buckets.each do |bucket|
puts "- #{bucket.name}"
end
rescue Google::Cloud::Error => e
puts "Error accessing Cloud Storage: #{e.message}"
# Log the error and handle appropriately
end
# Example: Reading an object (requires roles/storage.objectViewer)
begin
bucket = storage.bucket "your-bucket-name"
if bucket
file = bucket.file "your-object-name.txt"
if file
puts "Content of #{file.name}:"
puts file.download.read
else
puts "File 'your-object-name.txt' not found in bucket 'your-bucket-name'."
end
else
puts "Bucket 'your-bucket-name' not found."
end
rescue Google::Cloud::Error => e
puts "Error accessing Cloud Storage object: #{e.message}"
# Log the error and handle appropriately
end
Step 7: Deploy Application Pods with the KSA
In your Kubernetes deployment manifest, specify the KSA created in Step 4.
apiVersion: apps/v1
kind: Deployment
metadata:
name: ruby-app-deployment
spec:
replicas: 3
selector:
matchLabels:
app: ruby-app
template:
metadata:
labels:
app: ruby-app
spec:
serviceAccountName: ruby-app-ksa # This links the pod to the KSA
containers:
- name: ruby-app-container
image: your-docker-registry/your-ruby-app-image:latest
ports:
- containerPort: 3000
# ... other container configurations
Auditing Workload Identity Configuration
To audit this setup:
- Verify GKE Cluster Configuration: Ensure Workload Identity is enabled on the GKE cluster. Use
gcloud container clusters describe CLUSTER_NAME --zone COMPUTE_ZONE --format='value(addonsConfig.workloadIdentityConfig.workloadIdentityEnabled)'. The output should beTrue. - Inspect GSA Permissions: Review the IAM policy for the GSA (
ruby-app-sa@PROJECT_ID.iam.gserviceaccount.com) to confirm it only has the necessary, least-privilege roles. Usegcloud projects get-iam-policy PROJECT_ID --filter="bindings.members:serviceAccount:ruby-app-sa@PROJECT_ID.iam.gserviceaccount.com". - Check KSA Annotations: Verify that the KSA (
ruby-app-ksain thedefaultnamespace) is correctly annotated. Usekubectl get serviceaccount ruby-app-ksa -n default -o yamland look for theiam.gke.io/gcp-service-accountannotation. - Review Deployment Manifest: Confirm that the Kubernetes Deployment manifest correctly specifies
serviceAccountName: ruby-app-ksa. - Application Code: Ensure the Ruby application code uses Google Cloud client libraries and does not attempt to load credentials from files or environment variables that would bypass Workload Identity. The absence of explicit credential loading (e.g.,
Google::Cloud.new(project_id: "...", credentials: "path/to/key.json")) is a good indicator.
IAM Role Best Practices for Ruby Applications on GKE
When deploying Ruby applications on Google Kubernetes Engine (GKE), leveraging Identity and Access Management (IAM) roles is paramount for secure access to Google Cloud resources. Instead of embedding service account keys directly into your application or Kubernetes secrets, the recommended approach is to use Workload Identity. This allows your GKE pods to impersonate a Google Cloud service account, granting them fine-grained permissions without exposing credentials.
The process involves two main steps: configuring Workload Identity on your GKE cluster and then binding a Kubernetes Service Account (KSA) to a Google Cloud Service Account (GSA).
Step 1: Enable Workload Identity on GKE
If your GKE cluster doesn’t already have Workload Identity enabled, you’ll need to enable it. This is typically done during cluster creation or by updating an existing cluster.
Enabling during cluster creation:
Using gcloud:
gcloud container clusters create CLUSTER_NAME \
--zone COMPUTE_ZONE \
--workload-pool PROJECT_ID.svc.id.goog
Replace CLUSTER_NAME, COMPUTE_ZONE, and PROJECT_ID with your specific values.
Enabling on an existing cluster:
You can update an existing cluster to enable Workload Identity. Note that this might require a node pool upgrade.
gcloud container clusters update CLUSTER_NAME \
--zone COMPUTE_ZONE \
--update-addons WorkloadIdentity=ENABLED
Step 2: Create Google Cloud Service Account (GSA)
Create a dedicated GSA for your Ruby application. Avoid using the default Compute Engine service account.
gcloud iam service-accounts create ruby-app-sa \
--display-name "Ruby Application Service Account"
Step 3: Grant Necessary Permissions to GSA
Assign the minimum required IAM roles to the newly created GSA. For example, if your Ruby app needs to read from a Cloud Storage bucket:
gcloud projects add-iam-policy-binding PROJECT_ID \
--member "serviceAccount:ruby-app-sa@PROJECT_ID.iam.gserviceaccount.com" \
--role "roles/storage.objectViewer"
Replace PROJECT_ID with your actual project ID.
Step 4: Create Kubernetes Service Account (KSA)
Create a KSA within your GKE cluster that your application pods will use.
apiVersion: v1 kind: ServiceAccount metadata: name: ruby-app-ksa namespace: default # Or your application's namespace
Step 5: Bind KSA to GSA
This is the crucial step where you link the KSA to the GSA. This is done by annotating the KSA with the GSA’s identity.
gcloud container clusters get-credentials CLUSTER_NAME --zone COMPUTE_ZONE --project PROJECT_ID
kubectl annotate serviceaccount ruby-app-ksa \
--namespace default \
iam.gke.io/gcp-service-account=ruby-app-sa@PROJECT_ID.iam.gserviceaccount.com
Step 6: Configure Ruby Application to Use Workload Identity
Your Ruby application, when running within the GKE pod, will automatically pick up the credentials of the bound GSA. You can use the Google Cloud Client Libraries for Ruby. Ensure you have the google-cloud-storage gem (or relevant gem for other services) installed.
require "google/cloud/storage"
# The client library automatically detects the Workload Identity credentials
# when running in a GKE pod with the correct Workload Identity configuration.
storage = Google::Cloud::Storage.new
# Example: Listing buckets (requires roles/storage.admin or similar)
# If only roles/storage.objectViewer is granted, this might fail.
# Adjust operations based on the granted permissions.
begin
puts "Buckets:"
storage.buckets.each do |bucket|
puts "- #{bucket.name}"
end
rescue Google::Cloud::Error => e
puts "Error accessing Cloud Storage: #{e.message}"
# Log the error and handle appropriately
end
# Example: Reading an object (requires roles/storage.objectViewer)
begin
bucket = storage.bucket "your-bucket-name"
if bucket
file = bucket.file "your-object-name.txt"
if file
puts "Content of #{file.name}:"
puts file.download.read
else
puts "File 'your-object-name.txt' not found in bucket 'your-bucket-name'."
end
else
puts "Bucket 'your-bucket-name' not found."
end
rescue Google::Cloud::Error => e
puts "Error accessing Cloud Storage object: #{e.message}"
# Log the error and handle appropriately
end
Step 7: Deploy Application Pods with the KSA
In your Kubernetes deployment manifest, specify the KSA created in Step 4.
apiVersion: apps/v1
kind: Deployment
metadata:
name: ruby-app-deployment
spec:
replicas: 3
selector:
matchLabels:
app: ruby-app
template:
metadata:
labels:
app: ruby-app
spec:
serviceAccountName: ruby-app-ksa # This links the pod to the KSA
containers:
- name: ruby-app-container
image: your-docker-registry/your-ruby-app-image:latest
ports:
- containerPort: 3000
# ... other container configurations
Auditing Workload Identity Configuration
To audit this setup:
- Verify GKE Cluster Configuration: Ensure Workload Identity is enabled on the GKE cluster. Use
gcloud container clusters describe CLUSTER_NAME --zone COMPUTE_ZONE --format='value(addonsConfig.workloadIdentityConfig.workloadIdentityEnabled)'. The output should beTrue. - Inspect GSA Permissions: Review the IAM policy for the GSA (
ruby-app-sa@PROJECT_ID.iam.gserviceaccount.com) to confirm it only has the necessary, least-privilege roles. Usegcloud projects get-iam-policy PROJECT_ID --filter="bindings.members:serviceAccount:ruby-app-sa@PROJECT_ID.iam.gserviceaccount.com". - Check KSA Annotations: Verify that the KSA (
ruby-app-ksain thedefaultnamespace) is correctly annotated. Usekubectl get serviceaccount ruby-app-ksa -n default -o yamland look for theiam.gke.io/gcp-service-accountannotation. - Review Deployment Manifest: Confirm that the Kubernetes Deployment manifest correctly specifies
serviceAccountName: ruby-app-ksa. - Application Code: Ensure the Ruby application code uses Google Cloud client libraries and does not attempt to load credentials from files or environment variables that would bypass Workload Identity. The absence of explicit credential loading (e.g.,
Google::Cloud.new(project_id: "...", credentials: "path/to/key.json")) is a good indicator.