GCP Secret Manager
The gcpsm package provides a fig.SecretProvider backed by Google Cloud Secret Manager.
Installation
go get github.com/zoobzio/fig/gcpsm
Quick Start
import (
"context"
"log"
"github.com/zoobzio/fig"
"github.com/zoobzio/fig/gcpsm"
)
type Config struct {
DBPassword string `secret:"database-password"`
APIKey string `secret:"api-key"`
}
func main() {
ctx := context.Background()
provider, err := gcpsm.New(ctx, "my-project-id")
if err != nil {
log.Fatal(err)
}
var cfg Config
if err := fig.LoadContext(ctx, &cfg, provider); err != nil {
log.Fatal(err)
}
}
Configuration
Authentication
The provider uses Application Default Credentials (ADC):
GOOGLE_APPLICATION_CREDENTIALSenvironment variable- User credentials from
gcloud auth application-default login - Attached service account (GCE, Cloud Run, GKE)
Project ID
The project ID is required:
provider, err := gcpsm.New(ctx, "my-project-id")
Get project ID from metadata server (on GCP):
import "cloud.google.com/go/compute/metadata"
projectID, _ := metadata.ProjectID()
provider, _ := gcpsm.New(ctx, projectID)
Key Format
Keys follow the format secret-name or secret-name:json-field:
Plain Text Secrets
// Secret name: api-key
// Value: sk_live_12345
APIKey string `secret:"api-key"`
JSON Secrets
// Secret name: database-credentials
// Value: {"username": "admin", "password": "secret"}
DBUser string `secret:"database-credentials:username"`
DBPassword string `secret:"database-credentials:password"`
Creating Secrets
# Create secret
gcloud secrets create api-key --replication-policy="automatic"
# Add version
echo -n "sk_live_12345" | gcloud secrets versions add api-key --data-file=-
# JSON secret
echo -n '{"username":"admin","password":"secret"}' | \
gcloud secrets versions add database-credentials --data-file=-
API Reference
New
func New(ctx context.Context, project string, opts ...Option) (*Provider, error)
Creates a provider using Application Default Credentials.
Parameters:
ctx— context for credential discoveryproject— GCP project IDopts— optional configuration
Returns: (*Provider, error) — error if credentials cannot be found.
Options
WithHTTPClient
func WithHTTPClient(client *http.Client) Option
Sets a custom HTTP client. Useful for testing or custom transport configuration.
Close
func (p *Provider) Close() error
No-op, retained for interface compatibility. The provider uses HTTP/1.1 and doesn't require cleanup.
Secret Versions
The provider always fetches the latest version. For specific versions, implement a wrapper:
type VersionedProvider struct {
inner *gcpsm.Provider
version string // e.g., "1", "2", or "latest"
}
func (p *VersionedProvider) Get(ctx context.Context, key string) (string, error) {
// Modify key to include version
versionedKey := fmt.Sprintf("%s@%s", key, p.version)
// Would require modifying gcpsm to support this
return p.inner.Get(ctx, key)
}
IAM Permissions
Required role: roles/secretmanager.secretAccessor
gcloud secrets add-iam-policy-binding api-key \
--member="serviceAccount:my-service@my-project.iam.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"
Or at project level:
gcloud projects add-iam-policy-binding my-project \
--member="serviceAccount:my-service@my-project.iam.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"
Workload Identity (GKE)
For GKE with Workload Identity:
# Create KSA
kubectl create serviceaccount my-app
# Bind to GSA
gcloud iam service-accounts add-iam-policy-binding \
my-service@my-project.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:my-project.svc.id.goog[default/my-app]"
# Annotate KSA
kubectl annotate serviceaccount my-app \
iam.gke.io/gcp-service-account=my-service@my-project.iam.gserviceaccount.com
The provider automatically uses the workload identity when running in GKE.
Error Handling
The provider returns fig.ErrSecretNotFound when:
- The secret doesn't exist
- The secret version doesn't exist
- The requested JSON field doesn't exist
- The JSON field is not a string
Other errors (network, permissions) are returned as-is.
Regional vs Global Replication
The provider works with both replication policies. The latest version is fetched regardless of replication strategy.
For multi-region applications, consider using automatic replication:
gcloud secrets create my-secret --replication-policy="automatic"
Next Steps
- Secret Providers Guide — implementing custom providers
- HashiCorp Vault — Vault integration
- AWS Secrets Manager — AWS integration