tessl install tessl/golang-cloud-google-com--go--secretmanager@1.16.1Go Client Library for Google Cloud Secret Manager API - stores sensitive data such as API keys, passwords, and certificates
Identity and Access Management (IAM) controls who can access your secrets. The Secret Manager client provides methods to manage IAM policies and test permissions.
func (c *Client) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error)Sets the access control policy on the specified secret. Replaces any existing policy.
Request Type:
type SetIamPolicyRequest struct {
Resource string
Policy *Policy
UpdateMask *fieldmaskpb.FieldMask
}Fields:
Resource - Required. The resource name of the secret in format projects/*/secrets/*Policy - Required. The IAM policy to setUpdateMask - Optional. A FieldMask specifying which fields to updateExample - Grant access to a user:
import iampb "cloud.google.com/go/iam/apiv1/iampb"
policy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{
"user:alice@example.com",
"serviceAccount:my-service@my-project.iam.gserviceaccount.com",
},
},
{
Role: "roles/secretmanager.secretVersionManager",
Members: []string{
"user:bob@example.com",
},
},
},
}
req := &iampb.SetIamPolicyRequest{
Resource: "projects/my-project/secrets/my-api-key",
Policy: policy,
}
updatedPolicy, err := client.SetIamPolicy(ctx, req)
if err != nil {
log.Fatalf("failed to set IAM policy: %v", err)
}
fmt.Printf("Updated policy with %d bindings\n", len(updatedPolicy.Bindings))Example - Add a condition to a binding:
import (
"google.golang.org/genproto/googleapis/type/expr"
)
policy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{
"user:alice@example.com",
},
Condition: &expr.Expr{
Title: "Expires in 2025",
Description: "Access expires at the end of 2025",
Expression: "request.time < timestamp('2025-12-31T23:59:59Z')",
},
},
},
}
req := &iampb.SetIamPolicyRequest{
Resource: "projects/my-project/secrets/my-api-key",
Policy: policy,
}
updatedPolicy, err := client.SetIamPolicy(ctx, req)func (c *Client) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error)Gets the access control policy for a secret. Returns an empty policy if the secret does not have an explicit policy set.
Request Type:
type GetIamPolicyRequest struct {
Resource string
Options *GetPolicyOptions
}Fields:
Resource - Required. The resource name of the secret in format projects/*/secrets/*Options - Optional. Options for getting the policyExample:
req := &iampb.GetIamPolicyRequest{
Resource: "projects/my-project/secrets/my-api-key",
}
policy, err := client.GetIamPolicy(ctx, req)
if err != nil {
log.Fatalf("failed to get IAM policy: %v", err)
}
fmt.Printf("Policy version: %d\n", policy.Version)
for i, binding := range policy.Bindings {
fmt.Printf("Binding %d:\n", i)
fmt.Printf(" Role: %s\n", binding.Role)
fmt.Printf(" Members: %v\n", binding.Members)
if binding.Condition != nil {
fmt.Printf(" Condition: %s\n", binding.Condition.Expression)
}
}Example - Get policy and add a member:
// Get current policy
getReq := &iampb.GetIamPolicyRequest{
Resource: "projects/my-project/secrets/my-api-key",
}
policy, err := client.GetIamPolicy(ctx, getReq)
if err != nil {
log.Fatalf("failed to get policy: %v", err)
}
// Find or create binding for the role
var binding *iampb.Binding
for _, b := range policy.Bindings {
if b.Role == "roles/secretmanager.secretAccessor" {
binding = b
break
}
}
if binding == nil {
binding = &iampb.Binding{
Role: "roles/secretmanager.secretAccessor",
Members: []string{},
}
policy.Bindings = append(policy.Bindings, binding)
}
// Add new member
newMember := "user:charlie@example.com"
binding.Members = append(binding.Members, newMember)
// Update policy
setReq := &iampb.SetIamPolicyRequest{
Resource: "projects/my-project/secrets/my-api-key",
Policy: policy,
}
updatedPolicy, err := client.SetIamPolicy(ctx, setReq)
if err != nil {
log.Fatalf("failed to update policy: %v", err)
}
fmt.Printf("Added member: %s\n", newMember)func (c *Client) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error)Returns permissions that a caller has for the specified secret. If the secret does not exist, this will return an empty set of permissions.
Request Type:
type TestIamPermissionsRequest struct {
Resource string
Permissions []string
}Fields:
Resource - Required. The resource name of the secret in format projects/*/secrets/*Permissions - Required. The set of permissions to checkResponse Type:
type TestIamPermissionsResponse struct {
Permissions []string
}Fields:
Permissions - A subset of TestIamPermissionsRequest.permissions that the caller is allowedExample:
req := &iampb.TestIamPermissionsRequest{
Resource: "projects/my-project/secrets/my-api-key",
Permissions: []string{
"secretmanager.secrets.get",
"secretmanager.secrets.update",
"secretmanager.versions.access",
},
}
resp, err := client.TestIamPermissions(ctx, req)
if err != nil {
log.Fatalf("failed to test permissions: %v", err)
}
fmt.Printf("Granted permissions: %v\n", resp.Permissions)
// Check specific permission
hasAccessPermission := false
for _, perm := range resp.Permissions {
if perm == "secretmanager.versions.access" {
hasAccessPermission = true
break
}
}
if hasAccessPermission {
fmt.Println("User can access secret versions")
} else {
fmt.Println("User cannot access secret versions")
}func (c *Client) IAM(name string) *iam.HandleReturns a handle to inspect and change permissions of the resource indicated by the given secret name. The handle provides a more ergonomic interface for IAM operations.
Example:
import "cloud.google.com/go/iam"
handle := client.IAM("projects/my-project/secrets/my-api-key")
// Get current policy
policy, err := handle.Policy(ctx)
if err != nil {
log.Fatalf("failed to get policy: %v", err)
}
// Add a member to a role
policy.Add("user:dave@example.com", "roles/secretmanager.secretAccessor")
// Update the policy
if err := handle.SetPolicy(ctx, policy); err != nil {
log.Fatalf("failed to set policy: %v", err)
}
fmt.Println("Successfully updated IAM policy")Example - Test permissions using handle:
handle := client.IAM("projects/my-project/secrets/my-api-key")
permissions := []string{
"secretmanager.secrets.get",
"secretmanager.versions.access",
}
allowed, err := handle.TestPermissions(ctx, permissions)
if err != nil {
log.Fatalf("failed to test permissions: %v", err)
}
fmt.Printf("Allowed permissions: %v\n", allowed)Secret Manager provides predefined roles for common access patterns:
Full access to all Secret Manager resources.
Permissions:
Example:
policy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.admin",
Members: []string{
"user:admin@example.com",
},
},
},
}Read access to secret versions (the actual secret data).
Permissions:
secretmanager.versions.access - Access secret version payloadssecretmanager.versions.get - Get secret version metadatasecretmanager.versions.list - List secret versionssecretmanager.secrets.get - Get secret metadatasecretmanager.secrets.list - List secretsExample:
policy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{
"serviceAccount:my-app@my-project.iam.gserviceaccount.com",
},
},
},
}Manage secret versions without accessing secret data.
Permissions:
secretmanager.versions.accessExample:
policy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.secretVersionManager",
Members: []string{
"user:rotation-bot@example.com",
},
},
},
}Read-only access to secret metadata (not secret data).
Permissions:
secretmanager.versions.accessExample:
policy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.viewer",
Members: []string{
"group:auditors@example.com",
},
},
},
}secretmanager.secrets.create - Create new secretssecretmanager.secrets.delete - Delete secretssecretmanager.secrets.get - Get secret metadatasecretmanager.secrets.list - List secretssecretmanager.secrets.update - Update secret metadatasecretmanager.secrets.getIamPolicy - Get IAM policysecretmanager.secrets.setIamPolicy - Set IAM policysecretmanager.versions.access - Access secret version datasecretmanager.versions.add - Add new secret versionssecretmanager.versions.destroy - Destroy secret versionssecretmanager.versions.disable - Disable secret versionssecretmanager.versions.enable - Enable secret versionssecretmanager.versions.get - Get secret version metadatasecretmanager.versions.list - List secret versionsGrant only the minimum permissions needed:
// Good: Application only needs to read secrets
policy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{
"serviceAccount:app@my-project.iam.gserviceaccount.com",
},
},
},
}
// Bad: Application granted admin access
policy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.admin",
Members: []string{
"serviceAccount:app@my-project.iam.gserviceaccount.com",
},
},
},
}Applications should use service accounts instead of user credentials:
policy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{
"serviceAccount:web-app@my-project.iam.gserviceaccount.com",
"serviceAccount:worker@my-project.iam.gserviceaccount.com",
},
},
},
}Grant temporary access using IAM conditions:
import "google.golang.org/genproto/googleapis/type/expr"
policy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{
"user:contractor@example.com",
},
Condition: &expr.Expr{
Title: "Temporary access",
Description: "Access expires on January 31, 2025",
Expression: "request.time < timestamp('2025-01-31T23:59:59Z')",
},
},
},
}Use different secrets for different environments:
// Production secret - strict access
prodPolicy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{
"serviceAccount:prod-app@my-project.iam.gserviceaccount.com",
},
},
},
}
prodReq := &iampb.SetIamPolicyRequest{
Resource: "projects/my-project/secrets/api-key-prod",
Policy: prodPolicy,
}
client.SetIamPolicy(ctx, prodReq)
// Development secret - broader access
devPolicy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{
"serviceAccount:dev-app@my-project.iam.gserviceaccount.com",
"group:developers@example.com",
},
},
},
}
devReq := &iampb.SetIamPolicyRequest{
Resource: "projects/my-project/secrets/api-key-dev",
Policy: devPolicy,
}
client.SetIamPolicy(ctx, devReq)Log IAM policy changes for security auditing:
// Get current policy for audit log
oldPolicy, err := client.GetIamPolicy(ctx, &iampb.GetIamPolicyRequest{
Resource: "projects/my-project/secrets/my-api-key",
})
// Update policy
newPolicy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{"user:new-user@example.com"},
},
},
}
updatedPolicy, err := client.SetIamPolicy(ctx, &iampb.SetIamPolicyRequest{
Resource: "projects/my-project/secrets/my-api-key",
Policy: newPolicy,
})
// Log the change
log.Printf("IAM policy updated for secret my-api-key")
log.Printf("Old bindings: %v", oldPolicy.Bindings)
log.Printf("New bindings: %v", updatedPolicy.Bindings)IAM members can be specified in various formats:
policy := &iampb.Policy{
Bindings: []*iampb.Binding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{
// Individual user
"user:alice@example.com",
// Service account
"serviceAccount:my-service@my-project.iam.gserviceaccount.com",
// Google group
"group:developers@example.com",
// Google Workspace domain
"domain:example.com",
// All authenticated users
"allAuthenticatedUsers",
// All users (public access - use with caution!)
"allUsers",
},
},
},
}Warning: Never use allUsers for secrets containing sensitive data. This grants public access to anyone on the internet.