Skip to content
Back to skills

Gcp Secret Manager

ASecurity

Secure secrets in Google Cloud Secret Manager. Configure IAM policies, integrate with GKE, and manage secret versions. Use when managing secrets in GCP environments.

  • 17 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 4, 2026
devopsjavascriptpythongojavabashsqlnodeexpresskubernetesaws

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 4, 2026

npx -y skills add gabrielmoreira/agent-skills-mirror --skill gcp-secret-manager --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gcp Secret Manager?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gcp Secret Manager
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/gabrielmoreira-gcp-secret-manager/badge)](https://www.skillsdirectory.com/skills/gabrielmoreira-gcp-secret-manager)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gcp-secret-manager
description: Secure secrets in Google Cloud Secret Manager. Configure IAM policies, integrate with GKE, and manage secret versions. Use when managing secrets in GCP environments.
license: MIT
metadata:
  author: devops-skills
  version: "1.0"
---

# 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

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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

```yaml
# 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

```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

```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

```javascript
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

```python
"""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

```bash
# 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

```hcl
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

| Problem | Cause | Solution |
|---------|-------|----------|
| "Secret Manager API not enabled" | API not activated in project | Run `gcloud services enable secretmanager.googleapis.com` |
| "Permission denied" on access | Missing `secretAccessor` role | Grant `roles/secretmanager.secretAccessor` on the specific secret |
| Workload Identity not working | K8s SA not bound to GCP SA | Verify annotation on K8s SA; check IAM binding with `workloadIdentityUser` |
| "Secret version is in DISABLED state" | Version was disabled | Enable with `gcloud secrets versions enable VERSION --secret=SECRET` |
| High latency on secret access | No client-side caching | Cache secrets in memory with TTL; use CSI driver for GKE |
| CMEK decrypt fails | KMS key permissions missing | Grant `roles/cloudkms.cryptoKeyEncrypterDecrypter` to Secret Manager SA |
| Rotation function not triggered | Pub/Sub topic not configured | Verify 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](../hashicorp-vault/) - Multi-cloud secrets
- [gcp-gke](../../../infrastructure/cloud-gcp/gcp-gke/) - GKE integration
- [aws-secrets-manager](../aws-secrets-manager/) - AWS secret management
- [azure-keyvault](../azure-keyvault/) - Azure secret management

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…