Access secrets stored outside GKE clusters using client libraries

This tutorial shows you how to store the sensitive data that's used by yourGoogle Kubernetes Engine (GKE) clusters in Secret Manager. You learn how tomore securely access the data from your Pods by using Workload Identity Federation for GKE and theGoogle Cloud client libraries.

Storing your sensitive data outside your cluster storage reduces the risk ofunauthorized access to the data if an attack occurs. Using Workload Identity Federation for GKEto access the data lets you avoid the risks associated with managing long-livedservice account keys, and lets you control access to your secrets usingIdentity and Access Management (IAM) instead of in-cluster RBAC rules. You can use anyexternal secret store provider, such as Secret Manager orHashiCorp Vault.

This page is for Security specialists who want to move sensitive dataout of in-cluster storage. To learn more aboutcommon roles and example tasks that we reference in Google Cloud content, seeCommon GKE user roles and tasks.

This tutorial uses a GKE Autopilot cluster. To performthe steps using GKE Standard, you mustenable Workload Identity Federation for GKE manually.

You can use Workload Identity Federation for GKE to access any Google Cloud APIs fromGKE workloads without having to use less secure approaches likestatic service account key files. This tutorial uses Secret Manageras an example, but you can use the same steps to access other Google CloudAPIs. To learn more, seeWorkload Identity Federation for GKE.

Objectives

  • Create a secret in Google Cloud Secret Manager.
  • Create a GKE Autopilot cluster, Kubernetesnamespaces, and Kubernetes service accounts.
  • Create IAM allow policies to grant access to your Kubernetesservice accounts on the secret.
  • Use test applications to verify service account access.
  • Run a sample app that accesses the secret using theSecret Manager API.

Costs

In this document, you use the following billable components of Google Cloud:

To generate a cost estimate based on your projected usage, use thepricing calculator.

New Google Cloud users might be eligible for afree 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, seeClean up.

Before you begin

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.

  3. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  4. Toinitialize the gcloud CLI, run the following command:

    gcloudinit
  5. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.create permission.Learn how to grant roles.
    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 createPROJECT_ID

      ReplacePROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set projectPROJECT_ID

      ReplacePROJECT_ID with your Google Cloud project name.

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the Kubernetes Engine and Secret Manager APIs:

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains theserviceusage.services.enable permission.Learn how to grant roles.

    gcloudservicesenablecontainer.googleapis.com secretmanager.googleapis.com
  8. Install the Google Cloud CLI.

  9. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  10. Toinitialize the gcloud CLI, run the following command:

    gcloudinit
  11. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.create permission.Learn how to grant roles.
    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 createPROJECT_ID

      ReplacePROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set projectPROJECT_ID

      ReplacePROJECT_ID with your Google Cloud project name.

  12. Verify that billing is enabled for your Google Cloud project.

  13. Enable the Kubernetes Engine and Secret Manager APIs:

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains theserviceusage.services.enable permission.Learn how to grant roles.

    gcloudservicesenablecontainer.googleapis.com secretmanager.googleapis.com
  14. Grant roles to your user account. Run the following command once for each of the following IAM roles:roles/secretmanager.admin, roles/container.clusterAdmin

    gcloudprojectsadd-iam-policy-bindingPROJECT_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.

Prepare the environment

Clone the GitHub repository that contains the sample files for thistutorial:

gitclonehttps://github.com/GoogleCloudPlatform/kubernetes-engine-samplescd~/kubernetes-engine-samples/security/wi-secrets

Create a secret in Secret Manager

  1. The following example shows the data you'll use to create a secret:

    key=my-api-key
  2. Create a secret to store the sample data:

    gcloudsecretscreatebq-readonly-key\--data-file=manifests/bq-readonly-key\--ttl=3600s

    This command does the following:

    • Creates a new Secret Manager secret with the sample keyin theus-central1 Google Cloud region.
    • Sets the secret to expire one hour after you run the command.

Create the cluster and Kubernetes resources

Create a GKE cluster, Kubernetes namespaces, and Kubernetesservice accounts. You create two namespaces, one for read-only access and one forread-write access to the secret. You also create a Kubernetes service account ineach namespace to use with Workload Identity Federation for GKE.

  1. Create a GKE Autopilot cluster:

    gcloudcontainerclusterscreate-autosecret-cluster\--location=us-central1

    The cluster might take about five minutes to deploy. Autopilotclusters always have Workload Identity Federation for GKE enabled. If you want to use aGKE Standard cluster instead, you must manuallyenable Workload Identity Federation for GKE before you continue.

  2. Create areadonly-ns namespace and anadmin-ns namespace:

    kubectlcreatenamespacereadonly-nskubectlcreatenamespaceadmin-ns
  3. Create areadonly-sa Kubernetes service account and anadmin-saKubernetes service account:

    kubectlcreateserviceaccountreadonly-sa--namespace=readonly-nskubectlcreateserviceaccountadmin-sa--namespace=admin-ns

Create IAM allow policies

  1. Grant thereadonly-sa service account read-only access to the secret:

    gcloudsecretsadd-iam-policy-bindingbq-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 Cloudproject number.
    • PROJECT_ID: your Google Cloud project ID.
  2. Grant theadmin-sa service account read-write access to the secret:

    gcloudsecretsadd-iam-policy-bindingbq-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=Nonegcloudsecretsadd-iam-policy-bindingbq-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

Verify secret access

Deploy test Pods in each namespace to verify the read-only and read-writeaccess.

  1. Review the read-only Pod manifest:

    # Copyright 2022 Google LLC## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at##     http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.apiVersion:v1kind:Podmetadata:name:readonly-testnamespace:readonly-nsspec:containers:-image:google/cloud-sdk:slimname:workload-identity-testcommand:["sleep","infinity"]resources:requests:cpu:"150m"memory:"150Mi"serviceAccountName:readonly-sa

    This Pod uses thereadonly-sa service account in thereadonly-nsnamespace.

  2. Review the read-write Pod manifest:

    # Copyright 2022 Google LLC## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at##     http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.apiVersion:v1kind:Podmetadata:name:admin-testnamespace:admin-nsspec:containers:-image:google/cloud-sdk:slimname:workload-identity-testcommand:["sleep","infinity"]resources:requests:cpu:"150m"memory:"150Mi"serviceAccountName:admin-sa

    This Pod uses theadmin-sa service account in theadmin-nsnamespace.

  3. Deploy the test Pods:

    kubectlapply-fmanifests/admin-pod.yamlkubectlapply-fmanifests/readonly-pod.yaml

    The Pods might take a few minutes to start running. To monitor progress, runthe following command:

    watchkubectlgetpods-nreadonly-ns

    When the Pod status changes toRUNNING, pressCtrl+C to return to thecommand-line.

Test read-only access

  1. Open a shell in thereadonly-test Pod:

    kubectlexec-itreadonly-test--namespace=readonly-ns--/bin/bash
  2. Try to read the secret:

    gcloudsecretsversionsaccess1--secret=bq-readonly-key

    The output iskey=my-api-key.

  3. Try to write new data to the secret:

    printf"my-second-api-key"|gcloudsecretsversionsaddbq-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.

  4. Exit the Pod:

    exit

Test read-write access

  1. Open a shell in theadmin-test Pod:

    kubectlexec-itadmin-test--namespace=admin-ns--/bin/bash
  2. Try to read the secret:

    gcloudsecretsversionsaccess1--secret=bq-readonly-key

    The output iskey=my-api-key.

  3. Try to write new data to the secret:

    printf"my-second-api-key"|gcloudsecretsversionsaddbq-readonly-key--data-file=-

    The output is similar to the following:

    Created version [2] of the secret [bq-readonly-key].
  4. Read the new secret version:

    gcloudsecretsversionsaccess2--secret=bq-readonly-key

    The output ismy-second-api-key.

  5. Exit the Pod:

    exit

The Pods only get the level of access you granted to the Kubernetesservice account used in the Pod manifest. Any Pods that use theadmin-saKubernetes account in theadmin-ns namespace can write new versions of thesecret, but any Pods in thereadonly-ns namespace that use thereadonly-saKubernetes service account can only read the secret.

Access secrets from your code

In this section, you do the following:

  1. Deploy a sample application that reads your secret inSecret Manager using client libraries.

  2. Check that the application can access your secret.

You should access Secret Manager secrets from your applicationcode whenever possible, using the Secret Manager API.

  1. Review the sample application source code:

    // Copyright 2022 Google LLC//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////     http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.packagemainimport("context""fmt""log""os"secretmanager"cloud.google.com/go/secretmanager/apiv1"secretmanagerpb"google.golang.org/genproto/googleapis/cloud/secretmanager/v1")funcmain(){// Get environment variables from Pod spec.projectID:=os.Getenv("PROJECT_ID")secretId:=os.Getenv("SECRET_ID")secretVersion:=os.Getenv("SECRET_VERSION")// Create the Secret Manager client.ctx:=context.Background()client,err:=secretmanager.NewClient(ctx)iferr!=nil{log.Fatalf("failed to setup client: %v",err)}deferclient.Close()// Create the request to access the secret.accessSecretReq:=&secretmanagerpb.AccessSecretVersionRequest{Name:fmt.Sprintf("projects/%s/secrets/%s/versions/%s",projectID,secretId,secretVersion),}secret,err:=client.AccessSecretVersion(ctx,accessSecretReq)iferr!=nil{log.Fatalf("failed to access secret: %v",err)}// Print the secret payload.//// WARNING: Do not print the secret in a production environment - this// snippet is showing how to access the secret material.log.Printf("Welcome to the key store, here's your key:\nKey: %s",secret.Payload.Data)}

    This application calls the Secret Manager API to try and read thesecret.

  2. Review the sample application Pod manifest:

    # Copyright 2022 Google LLC## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at##     http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.apiVersion:v1kind:Podmetadata:name:readonly-secret-testnamespace:readonly-nsspec:containers:-image:us-docker.pkg.dev/google-samples/containers/gke/wi-secret-store:latestname:secret-appenv:-name:PROJECT_IDvalue:"YOUR_PROJECT_ID"-name:SECRET_IDvalue:"bq-readonly-key"-name:SECRET_VERSIONvalue:"latest"resources:requests:cpu:"125m"memory:"64Mi"serviceAccountName:readonly-sa

    This manifest does the following:

    • Creates a Pod in thereadonly-ns namespace that uses thereadonly-saservice account.
    • Pulls a sample application from a Google image registry. Thisapplication calls the Secret Manager API using theGoogle Cloud client libraries. You can view the application codein/main.go in the repository.
    • Sets environment variables for the sample application to use.
  3. Replace environment variables in the sample application:

    sed-i"s/YOUR_PROJECT_ID/PROJECT_ID/g""manifests/secret-app.yaml"
  4. Deploy the sample app:

    kubectlapply-fmanifests/secret-app.yaml

    The Pod might take a few minutes to start working. If the Pod needs a newnode in your cluster, you might noticeCrashLoopBackOff type events whileGKE provisions the node. The crashes stop when the nodeprovisions successfully.

  5. Verify the secret access:

    kubectllogsreadonly-secret-test-nreadonly-ns

    The output ismy-second-api-key. If the output is blank, the Pod might notbe running yet. Wait a few minutes and try again.

Alternative approaches

If you need tomountyour sensitive data to your Pods, use the Secret Manageradd-on for GKE. This add-ondeploys and manages the Google Cloud Secret Managerprovider for the Kubernetes Secret Store CSI driver in your GKEclusters. For instructions, seeUse Secret Manager add-on with GKE.

Providing secrets as mounted volumes has the following risks:

  1. Mounted volumes are susceptible to directory traversal attacks.
  2. Environment variables can be compromised due to misconfigurations such asopening a debug endpoint.

Whenever possible, we recommend that you programmatically access secrets throughthe Secret Manager API. For instructions, use the sample application inthis tutorial or refer toSecret Manager client libraries.

Clean up

To 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 resources

  1. Delete the cluster:

    gcloudcontainerclustersdeletesecret-cluster\--location=us-central1
  2. Optional: Delete the secret in Secret Manager:

    gcloudsecretsdeletebq-readonly-key

    If you don't do this step, the secret automatically expires because you setthe--ttl flag during creation.

Delete the project

    Caution: Deleting a project has the following effects:
    • Everything in the project is deleted. If you used an existing project for the tasks in this document, when you delete it, you also delete any other work you've done in the project.
    • Custom project IDs are lost. When you created this project, you might have created a custom project ID that you want to use in the future. To preserve the URLs that use the project ID, such as anappspot.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 deletePROJECT_ID

What's next

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-18 UTC.