mirror of
https://github.com/Sea-Haven-Industries/engineering-handbook.git
synced 2026-09-30 23:13:14 +00:00
Some checks failed
ci / ci / ci (push) Has been cancelled
Add a standalone ci workflow so handbook changes get an automated gate. The job is named literally "ci / ci" to emit the exact status context the org main-branch-protection ruleset requires. - markdownlint-cli2 (.markdownlint-cli2.jsonc): MD013/MD060/MD040 relaxed as noisy docs-style rules; fixed 3 MD032 blank-line-around-list issues. - lychee link check (lychee.toml): internal + external links, tolerates 429.
69 lines
1.9 KiB
Markdown
69 lines
1.9 KiB
Markdown
# Secrets and Configuration
|
|
|
|
## The Boundary
|
|
|
|
There is a strict separation between sensitive and non-sensitive configuration. No gray areas.
|
|
|
|
## AWS Secrets Manager
|
|
|
|
Use Secrets Manager for **all** sensitive values:
|
|
|
|
- API access tokens and keys
|
|
- Signing values used for request verification
|
|
- Webhook URLs that act as implicit authentication
|
|
- Database connection strings with embedded passwords
|
|
- Any value that would be dangerous if leaked
|
|
|
|
When in doubt about whether something qualifies as sensitive, treat it as sensitive.
|
|
|
|
### Naming Convention
|
|
|
|
```
|
|
stack-name/value-name
|
|
```
|
|
|
|
Examples:
|
|
|
|
- `my-stack/slack-signing`
|
|
- `my-stack/stripe-key`
|
|
|
|
## SSM Parameter Store
|
|
|
|
Use Parameter Store **only** for non-sensitive configuration:
|
|
|
|
- Feature flags
|
|
- Endpoint URLs (public, non-authenticated)
|
|
- Schedule expressions
|
|
- Channel IDs and non-sensitive identifiers
|
|
|
|
## Lambda Pattern
|
|
|
|
1. Store the sensitive value in Secrets Manager
|
|
2. Grant the function's IAM role `secretsmanager:GetSecretValue` scoped to only the values it needs
|
|
3. Read the value on cold start via the AWS SDK
|
|
4. Cache it in a module-level variable so subsequent invocations reuse it
|
|
|
|
```python
|
|
import boto3
|
|
import json
|
|
|
|
_client = boto3.client('secretsmanager')
|
|
_cached = None
|
|
|
|
def get_config():
|
|
global _cached
|
|
if _cached is None:
|
|
resp = _client.get_secret_value(SecretId='my-stack/config')
|
|
_cached = json.loads(resp['SecretString'])
|
|
return _cached
|
|
|
|
def handler(event, context):
|
|
config = get_config()
|
|
# use config values
|
|
```
|
|
|
|
## What NOT to Do
|
|
|
|
- **Never use Lambda environment variables for sensitive values.** Even with `NoEcho` CloudFormation parameters, the values end up as plaintext in the Lambda console and are readable by anyone with `GetFunctionConfiguration` access.
|
|
- **Never commit `.env` files** containing real values to a repository.
|
|
- **Never store sensitive values** in Notion, Slack messages, or other plaintext documents.
|