Stay organized with collections Save and categorize content based on your preferences.
This tutorial shows you how to store the sensitive data that's used by your Google Kubernetes Engine (GKE) clusters in Secret Manager. You learn how to more securely access the data from your Pods by using Workload Identity Federation for GKE and the Google Cloud client libraries.
Storing your sensitive data outside your cluster storage reduces the risk of unauthorized access to the data if an attack occurs. Using Workload Identity Federation for GKE to access the data lets you avoid the risks associated with managing long-lived service account keys, and lets you control access to your secrets using Identity and Access Management (IAM) instead of in-cluster RBAC rules. You can use any external secret store provider, such as Secret Manager or HashiCorp Vault.
This page is for Security specialists who want to move sensitive data out of in-cluster storage. To learn more about common roles and example tasks that we reference in Google Cloud content, see Common GKE user roles and tasks.
This tutorial uses a GKE Autopilot cluster. To perform the steps using GKE Standard, you must enable Workload Identity Federation for GKE manually.
You can use Workload Identity Federation for GKE to access any Google Cloud APIs from GKE workloads without having to use less secure approaches like static service account key files. This tutorial uses Secret Manager as an example, but you can use the same steps to access other Google Cloud APIs. To learn more, see Workload Identity Federation for GKE.
ObjectivesIn this document, you use the following billable components of Google Cloud:
To generate a cost estimate based on your projected usage, use the pricing calculator.
New Google Cloud users might be eligible for a
free trial.
When you finish the tasks that are described in this document, you can avoid continued billing by deleting the resources that you created. For more information, see Clean up.
Before you beginInstall the Google Cloud CLI.
If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.
To initialize the gcloud CLI, run the following command:
gcloud init
Create or select a Google Cloud project.
Note: If you don't plan to keep the resources that you create in this procedure, create a project instead of selecting an existing project. After you finish these steps, you can delete the project, removing all resources associated with the project.Create a Google Cloud project:
gcloud projects create PROJECT_ID
Replace PROJECT_ID
with a name for the Google Cloud project you are creating.
Select the Google Cloud project that you created:
gcloud config set project PROJECT_ID
Replace PROJECT_ID
with your Google Cloud project name.
Verify that billing is enabled for your Google Cloud project.
Enable the Kubernetes Engine and Secret Manager APIs:
gcloud services enable container.googleapis.com secretmanager.googleapis.com
Install the Google Cloud CLI.
If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.
To initialize the gcloud CLI, run the following command:
gcloud init
Create or select a Google Cloud project.
Note: If you don't plan to keep the resources that you create in this procedure, create a project instead of selecting an existing project. After you finish these steps, you can delete the project, removing all resources associated with the project.Create a Google Cloud project:
gcloud projects create PROJECT_ID
Replace PROJECT_ID
with a name for the Google Cloud project you are creating.
Select the Google Cloud project that you created:
gcloud config set project PROJECT_ID
Replace PROJECT_ID
with your Google Cloud project name.
Verify that billing is enabled for your Google Cloud project.
Enable the Kubernetes Engine and Secret Manager APIs:
gcloud services enable container.googleapis.com secretmanager.googleapis.com
Grant roles to your user account. Run the following command once for each of the following IAM roles: roles/secretmanager.admin, roles/container.clusterAdmin
gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE
Replace the following:
PROJECT_ID
: your project ID.USER_IDENTIFIER
: the identifier for your user account—for example, myemail@example.com
.ROLE
: the IAM role that you grant to your user account.Clone the GitHub repository that contains the sample files for this tutorial:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
cd ~/kubernetes-engine-samples/security/wi-secrets
Create a secret in Secret Manager
The following example shows the data you'll use to create a secret:
Create a secret to store the sample data:
gcloud secrets create bq-readonly-key \
--data-file=manifests/bq-readonly-key \
--ttl=3600s
This command does the following:
us-central1
Google Cloud region.Create a GKE cluster, Kubernetes namespaces, and Kubernetes service accounts. You create two namespaces, one for read-only access and one for read-write access to the secret. You also create a Kubernetes service account in each namespace to use with Workload Identity Federation for GKE.
Create a GKE Autopilot cluster:
gcloud container clusters create-auto secret-cluster \
--location=us-central1
The cluster might take about five minutes to deploy. Autopilot clusters always have Workload Identity Federation for GKE enabled. If you want to use a GKE Standard cluster instead, you must manually enable Workload Identity Federation for GKE before you continue.
Create a readonly-ns
namespace and an admin-ns
namespace:
kubectl create namespace readonly-ns
kubectl create namespace admin-ns
Create a readonly-sa
Kubernetes service account and an admin-sa
Kubernetes service account:
kubectl create serviceaccount readonly-sa --namespace=readonly-ns
kubectl create serviceaccount admin-sa --namespace=admin-ns
Grant the readonly-sa
service account read-only access to the secret:
gcloud secrets add-iam-policy-binding bq-readonly-key \
--member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/readonly-ns/sa/readonly-sa \
--role='roles/secretmanager.secretAccessor' \
--condition=None
Replace the following:
PROJECT_NUMBER
: your numerical Google Cloud project number.PROJECT_ID
: your Google Cloud project ID.Grant the admin-sa
service account read-write access to the secret:
gcloud secrets add-iam-policy-binding bq-readonly-key \
--member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/admin-ns/sa/admin-sa \
--role='roles/secretmanager.secretAccessor' \
--condition=None
gcloud secrets add-iam-policy-binding bq-readonly-key \
--member=principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.svc.id.goog/subject/ns/admin-ns/sa/admin-sa \
--role='roles/secretmanager.secretVersionAdder' \
--condition=None
Deploy test Pods in each namespace to verify the read-only and read-write access.
Review the read-only Pod manifest:
This Pod uses the readonly-sa
service account in the readonly-ns
namespace.
Review the read-write Pod manifest:
This Pod uses the admin-sa
service account in the admin-ns
namespace.
Deploy the test Pods:
kubectl apply -f manifests/admin-pod.yaml
kubectl apply -f manifests/readonly-pod.yaml
The Pods might take a few minutes to start running. To monitor progress, run the following command:
watch kubectl get pods -n readonly-ns
When the Pod status changes to RUNNING
, press Ctrl+C
to return to the command-line.
Open a shell in the readonly-test
Pod:
kubectl exec -it readonly-test --namespace=readonly-ns -- /bin/bash
Try to read the secret:
gcloud secrets versions access 1 --secret=bq-readonly-key
The output is key=my-api-key
.
Try to write new data to the secret:
printf "my-second-api-key" | gcloud secrets versions add bq-readonly-key --data-file=-
The output is similar to the following:
ERROR: (gcloud.secrets.versions.add) PERMISSION_DENIED: Permission 'secretmanager.versions.add' denied for resource 'projects/PROJECT_ID/secrets/bq-readonly-key' (or it may not exist).
The Pod using the read-only service account can only read the secret, and can't write new data.
Exit the Pod:
exit
Open a shell in the admin-test
Pod:
kubectl exec -it admin-test --namespace=admin-ns -- /bin/bash
Try to read the secret:
gcloud secrets versions access 1 --secret=bq-readonly-key
The output is key=my-api-key
.
Try to write new data to the secret:
printf "my-second-api-key" | gcloud secrets versions add bq-readonly-key --data-file=-
The output is similar to the following:
Created version [2] of the secret [bq-readonly-key].
Read the new secret version:
gcloud secrets versions access 2 --secret=bq-readonly-key
The output is my-second-api-key
.
Exit the Pod:
exit
The Pods only get the level of access you granted to the Kubernetes service account used in the Pod manifest. Any Pods that use the admin-sa
Kubernetes account in the admin-ns
namespace can write new versions of the secret, but any Pods in the readonly-ns
namespace that use the readonly-sa
Kubernetes service account can only read the secret.
In this section, you do the following:
Deploy a sample application that reads your secret in Secret Manager using client libraries.
Check that the application can access your secret.
You should access Secret Manager secrets from your application code whenever possible, using the Secret Manager API.
Review the sample application source code:
This application calls the Secret Manager API to try and read the secret.
Review the sample application Pod manifest:
This manifest does the following:
readonly-ns
namespace that uses the readonly-sa
service account./main.go
in the repository.Replace environment variables in the sample application:
sed -i "s/YOUR_PROJECT_ID/PROJECT_ID/g" "manifests/secret-app.yaml"
Deploy the sample app:
kubectl apply -f manifests/secret-app.yaml
The Pod might take a few minutes to start working. If the Pod needs a new node in your cluster, you might notice CrashLoopBackOff
type events while GKE provisions the node. The crashes stop when the node provisions successfully.
Verify the secret access:
kubectl logs readonly-secret-test -n readonly-ns
The output is my-second-api-key
. If the output is blank, the Pod might not be running yet. Wait a few minutes and try again.
If you need to mount your sensitive data to your Pods, use the Secret Manager add-on for GKE. This add-on deploys and manages the Google Cloud Secret Manager provider for the Kubernetes Secret Store CSI driver in your GKE clusters. For instructions, see Use Secret Manager add-on with GKE.
Providing secrets as mounted volumes has the following risks:
Whenever possible, we recommend that you programmatically access secrets through the Secret Manager API. For instructions, use the sample application in this tutorial or refer to Secret Manager client libraries.
Clean upTo avoid incurring charges to your Google Cloud account for the resources used in this tutorial, either delete the project that contains the resources, or keep the project and delete the individual resources.
Delete individual resourcesDelete the cluster:
gcloud container clusters delete secret-cluster \
--location=us-central1
Optional: Delete the secret in Secret Manager:
gcloud secrets delete bq-readonly-key
If you don't do this step, the secret automatically expires because you set the --ttl
flag during creation.
appspot.com
URL, delete selected resources inside the project instead of deleting the whole project.If you plan to explore multiple architectures, tutorials, or quickstarts, reusing projects can help you avoid exceeding project quota limits.
Delete a Google Cloud project:
gcloud projects delete PROJECT_ID
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-08-12 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Hard to understand","hardToUnderstand","thumb-down"],["Incorrect information or sample code","incorrectInformationOrSampleCode","thumb-down"],["Missing the information/samples I need","missingTheInformationSamplesINeed","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-12 UTC."],[],[]]
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4