Skip to main content

Secrets Component

The Secrets component creates Secret Manager secrets for sensitive configuration like database credentials and API keys.

Overview

Secrets Created

SecretContentSource
database-urlPostgreSQL connection stringCloud SQL outputs
redis-urlRedis connection stringMemorystore outputs
backend-configBackend application configurationPulumi config
frontend-configFrontend application configurationPulumi config

Secret Format

Database URL

postgresql://postgres:PASSWORD@ALLOYDB_IP:5432/postgres

Redis URL

redis://:AUTH_STRING@REDIS_HOST:6379

Backend Config

JSON object containing backend application settings:

{
"DATABASE_URL": "postgresql://...",
"DATABASE_POOL_SIZE": "5",
"OPENAI_API_KEY": "sk-...",
"LANGFUSE_ENABLED": "true",
"LANGFUSE_SECRET_KEY": "sk-...",
"LANGFUSE_PUBLIC_KEY": "pk-...",
"ENVIRONMENT": "production",
"API_LOG_LEVEL": "info"
}

Frontend Config

JSON object containing frontend application settings:

{
"NEXT_PUBLIC_API_URL": "https://api.serko-northsky.com",
"NEXT_PUBLIC_FIREBASE_CONFIG": "{...}",
"NEXT_PUBLIC_LOGO_DEV_KEY": "..."
}

Configuration

Secrets are automatically populated from infrastructure outputs:

// Database URL from Cloud SQL
const databaseUrl = pulumi.interpolate`postgresql://postgres:${cloudSql.databasePassword}@${cloudSql.privateIpAddress}:5432/postgres`;

// Redis URL from Memorystore
const redisUrl = pulumi.interpolate`redis://:${memorystore.authString}@${memorystore.host}:${memorystore.port}`;

Outputs

interface SecretsOutputs {
databaseUrlSecretId: string;
redisUrlSecretId: string;
backendConfigSecretId: string;
frontendConfigSecretId: string;
}

Usage in Kubernetes

External Secrets Operator

Use External Secrets Operator to sync secrets to Kubernetes:

# Backend secrets
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: backend-config-external-secret
spec:
refreshInterval: 60s
secretStoreRef:
name: app-secretstore
kind: SecretStore
target:
name: backend-config
creationPolicy: Owner
dataFrom:
- extract:
key: serko-northsky-dev-backend-config
---
# Frontend secrets
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: frontend-config-external-secret
spec:
refreshInterval: 60s
secretStoreRef:
name: app-secretstore
kind: SecretStore
target:
name: frontend-config
creationPolicy: Owner
dataFrom:
- extract:
key: serko-northsky-dev-frontend-config

Direct Access (Application Code)

Access secrets directly using the GCP SDK:

from google.cloud import secretmanager

client = secretmanager.SecretManagerServiceClient()
name = f"projects/{project_id}/secrets/database-url/versions/latest"
response = client.access_secret_version(request={"name": name})
database_url = response.payload.data.decode("UTF-8")

IAM Permissions

Service AccountRolePurpose
app@project.iamsecretmanager.secretAccessorRead secrets
pulumi-infra@project.iamsecretmanager.adminManage secrets

Secret Versioning

Secret Manager automatically versions secrets:

  • Latest: Always points to newest version
  • Version Numbers: Access specific versions
  • Destroy Policy: Old versions retained for audit
# Access latest version
gcloud secrets versions access latest --secret=database-url

# Access specific version
gcloud secrets versions access 3 --secret=database-url

# List all versions
gcloud secrets versions list database-url

Security Considerations

Access Control

  • Secrets are only accessible to authorized service accounts
  • Access is logged in Cloud Audit Logs
  • No secret values in Pulumi state (marked as secret)

Rotation

Implement secret rotation:

  1. Create new secret version
  2. Update application to use new credentials
  3. Disable old secret version
  4. Delete old version after grace period
# Add new version
echo -n "new-password" | gcloud secrets versions add database-url --data-file=-

# Disable old version
gcloud secrets versions disable 1 --secret=database-url

Best Practices

  • Never log secret values
  • Use Workload Identity for access
  • Enable audit logging
  • Rotate credentials regularly
  • Use separate secrets per environment