-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
Problem
Currently, secrets defined in .sc/stacks/<parent-stack>/secrets.yaml are available globally to all environments. This creates challenges:
- Security: Production secrets (API keys, passwords) shouldn't be accessible in dev/staging
- Isolation: Some secrets should only exist in specific environments
- Naming: Same secret name (e.g.,
DATABASE_PASSWORD) needs different values per environment while services expect a consistent name
Example of the Problem
# Current: .sc/stacks/devops/secrets.yaml
values:
DATABASE_PASSWORD: "prod-password-123" # Available everywhere - wrong for dev/staging
STRIPE_API_KEY: "sk_live_xxx" # Production key exposed to all envs
SLACK_WEBHOOK: "https://hooks.slack.com/..." # Maybe OK to shareA developer deploying to staging inadvertently gets access to production secrets.
Proposed Solution
Add a secrets section to server.yaml that controls per-environment secret availability and mapping.
Syntax
# .sc/stacks/devops/server.yaml
schemaVersion: 1.0
secrets:
inheritAll: false # Default: true (backwards compatible)
environments:
staging:
include:
# null (~) means "use same key from secrets.yaml"
SLACK_WEBHOOK: ~
# Reference another key in secrets.yaml
DATABASE_PASSWORD: "${secret:DATABASE_PASSWORD_STAGING}"
STRIPE_API_KEY: "${secret:STRIPE_TEST_KEY}"
# Literal value (no ${secret:} wrapper)
LOG_LEVEL: "debug"
ENABLE_PROFILING: "true"
production:
include:
SLACK_WEBHOOK: ~
DATABASE_PASSWORD: "${secret:DATABASE_PASSWORD_PROD}"
STRIPE_API_KEY: "${secret:STRIPE_LIVE_KEY}"
DATADOG_API_KEY: ~
LOG_LEVEL: "warn"
resources:
staging:
template: stack-per-app
# ...
production:
template: stack-per-app
# ...secrets.yaml (encrypted):
values:
DATABASE_PASSWORD_PROD: "super-secret-prod-password"
DATABASE_PASSWORD_STAGING: "staging-password-123"
STRIPE_LIVE_KEY: "sk_live_xxx"
STRIPE_TEST_KEY: "sk_test_yyy"
SLACK_WEBHOOK: "https://hooks.slack.com/..."
DATADOG_API_KEY: "dd-api-xxx"Syntax Reference
| Pattern | Type | Description |
|---|---|---|
SECRET_NAME: ~ |
Reference | Use value of SECRET_NAME from secrets.yaml |
NAME: "${secret:KEY}" |
Mapped Reference | Expose as NAME, fetch value from KEY in secrets.yaml |
NAME: "value" |
Literal | Expose as NAME with hardcoded value |
Behavior
| Setting | Description |
|---|---|
inheritAll: true (default) |
All secrets.yaml values available in all envs (current behavior) |
inheritAll: false |
Only explicitly listed secrets available per environment |
exclude: [names] |
Block specific secrets (only with inheritAll: true) |
Example with Exclusions
secrets:
inheritAll: true # Start with all secrets
environments:
staging:
exclude:
- DATADOG_API_KEY # Not needed in staging
- STRIPE_LIVE_KEY # Security: no prod keys in staging
override:
STRIPE_API_KEY: "${secret:STRIPE_TEST_KEY}"
production:
# Gets everything, no overrides neededService Usage (No Changes)
Client configurations remain unchanged:
# client.yaml
stacks:
production:
parent: company/devops
secrets:
DB_PASS: "${secret:DATABASE_PASSWORD}" # Resolves to prod value
STRIPE: "${secret:STRIPE_API_KEY}" # Resolves to live key# Same client.yaml deployed to staging
stacks:
staging:
parent: company/devops
secrets:
DB_PASS: "${secret:DATABASE_PASSWORD}" # Resolves to staging value
STRIPE: "${secret:STRIPE_API_KEY}" # Resolves to test keyValidation
sc validate should:
- Warn if a secret referenced in client.yaml isn't available for target environment
- Error if
${secret:KEY}references a non-existent key in secrets.yaml - Warn about unused secrets in secrets.yaml
Migration
- Backwards compatible: Without
secretssection, all secrets available everywhere - Opt-in: Teams adopt incrementally
- No client changes: Existing service configs work without modification
Benefits
- Secret values stay encrypted in secrets.yaml
- Mapping logic in version-controlled server.yaml
- Supports both references and literals
- No changes to service configurations
- Clear separation of environments
- Backwards compatible
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels