Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
bagelhole avatar

Gcp Secret Manager

  • 102 installs
  • 44 repo stars
  • Updated May 22, 2026
  • bagelhole/devops-security-agent-skills

gcp-secret-manager is a Claude skill that securely stores, versions, and controls access to secrets in Google Cloud Secret Manager, including GKE integration.

About

gcp-secret-manager stores and manages secrets securely in Google Cloud Secret Manager. A developer uses it to create and version secrets, configure least-privilege IAM bindings, integrate secrets with GKE workloads via Workload Identity, and handle rotation and expiration. It provides gcloud commands and Kubernetes manifests.

  • Create, version, rotate, and expire secrets via gcloud
  • Scoped IAM bindings with conditions for least-privilege access
  • Workload Identity and Secrets Store CSI integration for GKE

Gcp Secret Manager by the numbers

  • 102 all-time installs (skills.sh)
  • Ranked #1,006 of 2,203 Security skills by installs in the Skillselion catalog
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

gcp-secret-manager capabilities & compatibility

Skill is free; Secret Manager bills per secret version and access operation on GCP.

Capabilities
secrets management · iam config · kubernetes management
Works with
gcp · kubernetes
Use cases
security audit · devops
Runs
Hosted SaaS
Pricing
Freemium
From the docs

What gcp-secret-manager says it does

Secure secrets in Google Cloud Secret Manager. Configure IAM policies, integrate with GKE, and manage secret versions.
SKILL.md
Store and manage secrets securely in Google Cloud Platform.
SKILL.md
npx skills add https://github.com/bagelhole/devops-security-agent-skills --skill gcp-secret-manager

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs102
repo stars44
Last updatedMay 22, 2026
Repositorybagelhole/devops-security-agent-skills

What it does

Store API keys and credentials in GCP Secret Manager with scoped IAM access and GKE Workload Identity.

Who is it for?

Managing API keys, credentials, and certificates in GCP with least-privilege IAM.

Skip if: Non-GCP environments or teams already standardized on another secrets vault.

When should I use this skill?

You are managing secrets in GCP, integrating them with GKE, or implementing versioning and rotation.

What you get

Versioned secrets in GCP Secret Manager with scoped IAM bindings and GKE Workload Identity access.

  • gcloud secret and version commands
  • scoped IAM policy bindings
  • GKE Workload Identity manifests

By the numbers

  • 2 IAM roles referenced (secretmanager.admin, secretmanager.secretAccessor)
  • Supports automatic and user-managed replication plus CMEK

Files

SKILL.mdMarkdownGitHub ↗

GCP Secret Manager

Store and manage secrets securely in Google Cloud Platform.

When to Use This Skill

Use this skill when:

  • Managing secrets in GCP environments
  • Integrating secrets with GKE workloads via Workload Identity
  • Storing API keys, database credentials, or TLS certificates
  • Implementing secret versioning and rotation
  • Meeting compliance requirements for centralized secret management

Prerequisites

  • GCP project with billing enabled
  • gcloud CLI installed and authenticated
  • Secret Manager API enabled (secretmanager.googleapis.com)
  • IAM permissions: roles/secretmanager.admin for management, roles/secretmanager.secretAccessor for reading
  • For GKE: Workload Identity configured on the cluster

Enable the API

# Enable Secret Manager API
gcloud services enable secretmanager.googleapis.com

# Verify it's enabled
gcloud services list --enabled --filter="name:secretmanager"

Secret Creation and Management

# Create a secret (creates the secret resource, not the value)
gcloud secrets create db-password \
  --replication-policy="automatic" \
  --labels="env=production,team=platform"

# Add the secret value (first version)
echo -n "S3cur3P@ssw0rd!" | gcloud secrets versions add db-password --data-file=-

# Create secret with value in one command
echo -n '{"username":"dbadmin","password":"S3cur3P@ss!","host":"10.0.1.5","port":5432}' | \
  gcloud secrets create db-credentials --data-file=- \
  --replication-policy="automatic" \
  --labels="env=production,team=platform"

# Create with specific region replication
gcloud secrets create regional-secret \
  --replication-policy="user-managed" \
  --locations="us-central1,us-east1"

# Create with customer-managed encryption key (CMEK)
gcloud secrets create sensitive-secret \
  --replication-policy="user-managed" \
  --locations="us-central1" \
  --kms-key-name="projects/my-project/locations/us-central1/keyRings/my-ring/cryptoKeys/my-key"

# Access the latest version
gcloud secrets versions access latest --secret=db-password

# Access a specific version
gcloud secrets versions access 3 --secret=db-password

# Add a new version (rotation)
echo -n "N3wS3cur3P@ss!" | gcloud secrets versions add db-password --data-file=-

# List all secrets
gcloud secrets list --format="table(name, createTime, labels)"

# List versions of a secret
gcloud secrets versions list db-password --format="table(name, state, createTime)"

# Disable a version (makes it inaccessible but recoverable)
gcloud secrets versions disable 1 --secret=db-password

# Enable a disabled version
gcloud secrets versions enable 1 --secret=db-password

# Destroy a version (permanent)
gcloud secrets versions destroy 1 --secret=db-password

# Delete the entire secret
gcloud secrets delete db-password

# Set expiration on a secret
gcloud secrets update db-password \
  --expire-time="2026-06-01T00:00:00Z"

# Set TTL-based expiration
gcloud secrets update temp-token \
  --ttl="2592000s"  # 30 days

# Update labels
gcloud secrets update db-password \
  --update-labels="rotation=enabled,last-rotated=2025-01-15"

# Add version aliases
gcloud secrets versions update 5 --secret=db-password --set-aliases="production"

IAM Bindings

# Grant secret accessor role to a service account
gcloud secrets add-iam-policy-binding db-password \
  --member="serviceAccount:myapp-sa@my-project.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

# Grant access to a specific secret version
gcloud secrets add-iam-policy-binding db-password \
  --member="serviceAccount:myapp-sa@my-project.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretVersionAccessor" \
  --condition='expression=resource.name.endsWith("versions/latest"),title=latest-only'

# Grant admin to security team
gcloud secrets add-iam-policy-binding db-password \
  --member="group:security-team@example.com" \
  --role="roles/secretmanager.admin"

# View IAM policy for a secret
gcloud secrets get-iam-policy db-password

# Remove access
gcloud secrets remove-iam-policy-binding db-password \
  --member="serviceAccount:old-sa@my-project.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

# Project-level IAM for all secrets
gcloud projects add-iam-policy-binding my-project \
  --member="serviceAccount:myapp-sa@my-project.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor" \
  --condition='expression=resource.name.startsWith("projects/my-project/secrets/myapp-"),title=myapp-secrets-only'

Workload Identity for GKE

# Enable Workload Identity on cluster (if not already)
gcloud container clusters update my-cluster \
  --zone us-central1-a \
  --workload-pool=my-project.svc.id.goog

# Create GCP service account for the workload
gcloud iam service-accounts create myapp-gke-sa \
  --display-name="MyApp GKE Service Account"

# Grant secret accessor role
gcloud secrets add-iam-policy-binding db-password \
  --member="serviceAccount:myapp-gke-sa@my-project.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

# Bind Kubernetes SA to GCP SA
gcloud iam service-accounts add-iam-policy-binding \
  myapp-gke-sa@my-project.iam.gserviceaccount.com \
  --role="roles/iam.workloadIdentityUser" \
  --member="serviceAccount:my-project.svc.id.goog[production/myapp-sa]"

Kubernetes Manifests

# Kubernetes service account annotated with GCP SA
apiVersion: v1
kind: ServiceAccount
metadata:
  name: myapp-sa
  namespace: production
  annotations:
    iam.gke.io/gcp-service-account: "myapp-gke-sa@my-project.iam.gserviceaccount.com"
---
# Secrets Store CSI Driver for GCP
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: gcp-secrets
  namespace: production
spec:
  provider: gcp
  parameters:
    secrets: |
      - resourceName: "projects/my-project/secrets/db-password/versions/latest"
        path: "db-password"
      - resourceName: "projects/my-project/secrets/db-credentials/versions/latest"
        path: "db-credentials"
      - resourceName: "projects/my-project/secrets/api-key/versions/latest"
        path: "api-key"
  secretObjects:
    - secretName: myapp-secrets
      type: Opaque
      data:
        - objectName: db-password
          key: DB_PASSWORD
        - objectName: api-key
          key: API_KEY
---
# Deployment using the secrets
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      serviceAccountName: myapp-sa
      containers:
        - name: myapp
          image: gcr.io/my-project/myapp:v1.0.0
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: myapp-secrets
                  key: DB_PASSWORD
          volumeMounts:
            - name: secrets
              mountPath: "/var/secrets"
              readOnly: true
      volumes:
        - name: secrets
          csi:
            driver: secrets-store.csi.k8s.io
            readOnly: true
            volumeAttributes:
              secretProviderClass: "gcp-secrets"

Application SDK Examples

Python

from google.cloud import secretmanager
from google.api_core import exceptions
import json

def get_secret(project_id: str, secret_id: str, version: str = "latest") -> str:
    """Access a secret version from GCP Secret Manager."""
    client = secretmanager.SecretManagerServiceClient()
    name = f"projects/{project_id}/secrets/{secret_id}/versions/{version}"

    try:
        response = client.access_secret_version(request={"name": name})
        return response.payload.data.decode("UTF-8")
    except exceptions.NotFound:
        raise ValueError(f"Secret {secret_id} version {version} not found")
    except exceptions.PermissionDenied:
        raise PermissionError(f"No access to secret {secret_id}")

def get_json_secret(project_id: str, secret_id: str) -> dict:
    """Access and parse a JSON secret."""
    raw = get_secret(project_id, secret_id)
    return json.loads(raw)

def create_secret(project_id: str, secret_id: str, value: str, labels: dict = None) -> str:
    """Create a new secret with an initial version."""
    client = secretmanager.SecretManagerServiceClient()
    parent = f"projects/{project_id}"

    secret_config = {
        "replication": {"automatic": {}},
    }
    if labels:
        secret_config["labels"] = labels

    secret = client.create_secret(
        request={"parent": parent, "secret_id": secret_id, "secret": secret_config}
    )

    client.add_secret_version(
        request={"parent": secret.name, "payload": {"data": value.encode("UTF-8")}}
    )
    return secret.name

def rotate_secret(project_id: str, secret_id: str, new_value: str) -> str:
    """Add a new version to rotate the secret."""
    client = secretmanager.SecretManagerServiceClient()
    parent = f"projects/{project_id}/secrets/{secret_id}"

    version = client.add_secret_version(
        request={"parent": parent, "payload": {"data": new_value.encode("UTF-8")}}
    )
    return version.name

def list_secrets(project_id: str, filter_str: str = "") -> list:
    """List all secrets in a project."""
    client = secretmanager.SecretManagerServiceClient()
    parent = f"projects/{project_id}"

    secrets = []
    for secret in client.list_secrets(request={"parent": parent, "filter": filter_str}):
        secrets.append({
            "name": secret.name.split("/")[-1],
            "created": secret.create_time.isoformat(),
            "labels": dict(secret.labels),
        })
    return secrets

# Usage
creds = get_json_secret("my-project", "db-credentials")
connection_string = (
    f"postgresql://{creds['username']}:{creds['password']}"
    f"@{creds['host']}:{creds['port']}/mydb"
)

Go

package main

import (
    "context"
    "fmt"
    "log"

    secretmanager "cloud.google.com/go/secretmanager/apiv1"
    secretmanagerpb "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb"
)

func getSecret(projectID, secretID, version string) (string, error) {
    ctx := context.Background()
    client, err := secretmanager.NewClient(ctx)
    if err != nil {
        return "", fmt.Errorf("failed to create client: %w", err)
    }
    defer client.Close()

    name := fmt.Sprintf("projects/%s/secrets/%s/versions/%s", projectID, secretID, version)
    result, err := client.AccessSecretVersion(ctx, &secretmanagerpb.AccessSecretVersionRequest{
        Name: name,
    })
    if err != nil {
        return "", fmt.Errorf("failed to access secret: %w", err)
    }

    return string(result.Payload.Data), nil
}

func main() {
    secret, err := getSecret("my-project", "db-password", "latest")
    if err != nil {
        log.Fatalf("Error: %v", err)
    }
    fmt.Printf("Secret: %s\n", secret)
}

Node.js

const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');

const client = new SecretManagerServiceClient();

async function getSecret(projectId, secretId, version = 'latest') {
  const name = `projects/${projectId}/secrets/${secretId}/versions/${version}`;
  const [response] = await client.accessSecretVersion({ name });
  return response.payload.data.toString('utf8');
}

async function main() {
  const password = await getSecret('my-project', 'db-password');
  console.log(`Secret retrieved, length: ${password.length}`);
}

main().catch(console.error);

Secret Rotation with Cloud Functions

"""cloud_function_rotation.py - Triggered by Pub/Sub on secret rotation events."""

import functions_framework
from google.cloud import secretmanager
import secrets
import string

@functions_framework.cloud_event
def rotate_secret(cloud_event):
    """Handle secret rotation events from Pub/Sub."""
    data = cloud_event.data
    secret_name = data.get("name", "")

    if "db-password" not in secret_name:
        print(f"Skipping non-DB secret: {secret_name}")
        return

    client = secretmanager.SecretManagerServiceClient()

    alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
    new_password = ''.join(secrets.choice(alphabet) for _ in range(32))

    parent = "/".join(secret_name.split("/")[:4])
    client.add_secret_version(
        request={
            "parent": parent,
            "payload": {"data": new_password.encode("UTF-8")},
        }
    )
    print(f"Rotated secret: {parent}")

Rotation Schedule with Cloud Scheduler

# Create a Pub/Sub topic for rotation events
gcloud pubsub topics create secret-rotation

# Configure secret to publish rotation events
gcloud secrets update db-password \
  --add-topics="projects/my-project/topics/secret-rotation" \
  --event-types="SECRET_ROTATE"

# Set up rotation schedule
gcloud secrets update db-password \
  --next-rotation-time="2025-04-01T00:00:00Z" \
  --rotation-period="2592000s"  # 30 days

Terraform Configuration

resource "google_secret_manager_secret" "db_password" {
  project   = var.project_id
  secret_id = "db-password"

  replication {
    auto {}
  }

  labels = {
    env  = "production"
    team = "platform"
  }

  rotation {
    next_rotation_time = "2025-04-01T00:00:00Z"
    rotation_period    = "2592000s"
  }

  topics {
    name = google_pubsub_topic.secret_rotation.id
  }
}

resource "google_secret_manager_secret_version" "db_password" {
  secret      = google_secret_manager_secret.db_password.id
  secret_data = var.db_password
}

resource "google_secret_manager_secret_iam_member" "app_accessor" {
  project   = var.project_id
  secret_id = google_secret_manager_secret.db_password.secret_id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.app.email}"
}

Troubleshooting

ProblemCauseSolution
"Secret Manager API not enabled"API not activated in projectRun gcloud services enable secretmanager.googleapis.com
"Permission denied" on accessMissing secretAccessor roleGrant roles/secretmanager.secretAccessor on the specific secret
Workload Identity not workingK8s SA not bound to GCP SAVerify annotation on K8s SA; check IAM binding with workloadIdentityUser
"Secret version is in DISABLED state"Version was disabledEnable with gcloud secrets versions enable VERSION --secret=SECRET
High latency on secret accessNo client-side cachingCache secrets in memory with TTL; use CSI driver for GKE
CMEK decrypt failsKMS key permissions missingGrant roles/cloudkms.cryptoKeyEncrypterDecrypter to Secret Manager SA
Rotation function not triggeredPub/Sub topic not configuredVerify topic is attached to secret; check Cloud Function subscription

Best Practices

  • Use Workload Identity for GKE instead of exported service account keys
  • Implement IAM least-privilege at the individual secret level, not project level
  • Enable audit logging for all secret access (Cloud Audit Logs)
  • Use secret versions for safe rollback during rotation issues
  • Set expiration dates or TTLs on temporary secrets
  • Integrate with Cloud KMS for customer-managed encryption keys
  • Use labels consistently for organization and automation
  • Monitor secret access patterns with Cloud Monitoring
  • Implement rotation schedules for all long-lived credentials
  • Use conditional IAM bindings to restrict access by resource name pattern

Related Skills

  • hashicorp-vault - Multi-cloud secrets
  • gcp-gke - GKE integration
  • aws-secrets-manager - AWS secret management
  • azure-keyvault - Azure secret management

Related skills

FAQ

How do GKE workloads read secrets?

Via Workload Identity binding a Kubernetes service account to a Google service account, or the Secrets Store CSI driver.

How is least-privilege access enforced?

With IAM bindings scoped to specific secrets or versions using conditions.

Securitysecrets

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.