AWS Resolvers¶
When running applications on AWS, you often need to fetch configuration from AWS services like SSM Parameter Store, CloudFormation stacks, or S3 buckets. HoloConf provides AWS-specific resolvers to make this seamless.
Installation¶
AWS resolvers are distributed separately to keep the core library lean:
AWS resolvers are automatically discovered when you import holoconf:
SSM Parameter Store¶
AWS Systems Manager Parameter Store is perfect for storing configuration and secrets. Let's see how to use it.
First, let's try to reference an SSM parameter:
Automatic Decryption¶
SSM parameters are automatically decrypted if they use AWS KMS encryption. You don't need to do anything special:
HoloConf automatically calls SSM with WithDecryption=true, so you get the decrypted value.
Automatic Sensitivity Detection¶
SSM SecureString parameters are automatically marked as sensitive and redacted in dumps:
import holoconf
config = holoconf.Config.load("config.yaml")
# Sensitive values are automatically redacted
print(config.to_yaml(redact=True))
# password: '[REDACTED]'
# But you can still access the actual value
password = config.password
print(f"Password length: {len(password)}")
# Password length: 20
If you want to override sensitivity detection, you can do so explicitly:
# Force sensitivity even for String parameters
debug_token: ${ssm:/myapp/dev/token,sensitive=true}
# Disable sensitivity for SecureString (not recommended!)
public_value: ${ssm:/myapp/public-key,sensitive=false}
Handling Missing Parameters¶
What happens if a parameter doesn't exist?
Provide a default for optional parameters:
Now if the parameter doesn't exist, it uses 30 instead of erroring.
Cross-Region Parameters¶
By default, SSM parameters are fetched from your configured AWS region. To fetch from a different region:
# Fetch from us-west-2, even if default region is us-east-1
west_config: ${ssm:/shared/config,region=us-west-2}
AWS Secrets Manager Integration¶
SSM provides a special path prefix to access Secrets Manager:
# Access Secrets Manager secret via SSM
db_creds: ${ssm:/aws/reference/secretsmanager/myapp/db-credentials}
This is convenient because you can use the same resolver for both SSM Parameter Store and Secrets Manager.
Authentication and Credentials¶
SSM resolvers use the standard AWS credential chain:
- Environment variables (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY) - AWS profile from
~/.aws/credentials - IAM instance profile (when running on EC2)
- ECS task role (when running in ECS)
To use a specific profile:
Or set the environment variable:
CloudFormation Outputs¶
When you deploy infrastructure with CloudFormation, you often need to reference stack outputs in your application configuration. The cfn resolver makes this easy.
Let's say you have a CloudFormation stack called myapp-infrastructure with these outputs:
DatabaseEndpoint- The database hostCacheEndpoint- The Redis cache hostApiUrl- The API endpoint
Reference them in your config:
database:
host: ${cfn:myapp-infrastructure.DatabaseEndpoint}
cache:
host: ${cfn:myapp-infrastructure.CacheEndpoint}
api:
url: ${cfn:myapp-infrastructure.ApiUrl}
Syntax¶
The CloudFormation resolver uses this syntax:
For example:
This fetches the ApiEndpoint output from the myapp-prod stack.
Handling Missing Stacks or Outputs¶
What if the stack doesn't exist?
Or if the output key doesn't exist:
Provide a default for optional outputs:
Cross-Region Stacks¶
To reference a stack in a different region:
S3 Objects¶
For larger configuration files or shared team configurations, you can store them in S3 and reference them with the s3 resolver.
Let's say you have a shared configuration file in S3:
Reference it in your config:
Automatic Format Detection¶
S3 objects are automatically parsed based on file extension:
.json- Parsed as JSON.yaml,.yml- Parsed as YAML.txt,.pem, or no extension - Returned as plain text
# Parses as JSON
api_config: ${s3:my-bucket/config/api.json}
# Parses as YAML
db_config: ${s3:my-bucket/config/database.yaml}
# Returns as plain text
certificate: ${s3:my-bucket/certs/server.pem}
S3 URI Syntax¶
You can use either format:
# Without s3:// prefix (recommended)
config: ${s3:my-bucket/path/to/file.json}
# With s3:// prefix (also works)
config: ${s3:s3://my-bucket/path/to/file.json}
Both work identically.
Handling Missing Objects¶
What if the S3 object doesn't exist?
Provide a default:
Versioned Objects¶
To fetch a specific version of an S3 object:
This is useful for:
- Rolling back to a previous configuration
- Ensuring consistent config across deployments
- Auditing configuration changes
Authentication and Permissions¶
S3 resolvers use the same AWS credential chain as SSM resolvers. Your credentials need these permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::my-config-bucket/*"
}
]
}
AWS Authentication Summary¶
All AWS resolvers (ssm, cfn, s3) use the standard AWS credential chain:
-
Environment variables:
-
AWS profile from
~/.aws/credentials: -
IAM instance profile (when running on EC2)
-
ECS task role (when running in ECS/Fargate)
-
IRSA (IAM Roles for Service Accounts) (when running in EKS)
You can also specify region and profile per-resolver:
# Different regions for different parameters
east_db: ${ssm:/myapp/db-host,region=us-east-1}
west_db: ${ssm:/myapp/db-host,region=us-west-2}
# Different profiles for different accounts
prod_config: ${ssm:/prod/config,profile=prod-account}
shared_config: ${ssm:/shared/config,profile=shared-account}
Performance Considerations¶
Caching¶
AWS resolvers cache values for the lifetime of the Config object to avoid repeated API calls:
To get fresh values, reload the config:
Lazy Resolution¶
Like all resolvers, AWS resolvers are lazy - they only execute when you access the value:
This means you only pay for the API calls you actually need.
Batch Optimization¶
For SSM parameters, consider using parameter hierarchies to reduce API calls:
# Instead of many individual parameters:
db_host: ${ssm:/myapp/prod/db/host}
db_port: ${ssm:/myapp/prod/db/port}
db_name: ${ssm:/myapp/prod/db/name}
# Store as structured data in one parameter:
database: ${ssm:/myapp/prod/database}
Then store a JSON value in SSM:
aws ssm put-parameter \
--name /myapp/prod/database \
--type SecureString \
--value '{"host":"prod-db.example.com","port":5432,"name":"myapp"}'
One API call instead of three!
Quick Reference¶
| Resolver | Syntax | Description | Example |
|---|---|---|---|
ssm |
${ssm:/path} |
SSM Parameter Store | ${ssm:/myapp/prod/db-password} |
cfn |
${cfn:Stack.Output} |
CloudFormation output | ${cfn:myapp-stack.DatabaseEndpoint} |
s3 |
${s3:bucket/key} |
S3 object content | ${s3:my-bucket/config.json} |
All AWS resolvers support:
default=value- Fallback if not foundsensitive=true/false- Override sensitivity detectionregion=name- Override AWS region
SSM additionally supports:
profile=name- AWS profile for credentials- Automatic access to Secrets Manager via
/aws/reference/secretsmanager/prefix
S3 additionally supports:
version_id=id- Fetch specific object version
What You've Learned¶
You now understand:
- Installing and registering AWS resolvers
- Fetching parameters from SSM Parameter Store with
${ssm:/path} - Automatic decryption and sensitivity detection for SSM
- Referencing CloudFormation stack outputs with
${cfn:Stack.Output} - Including S3 object content with
${s3:bucket/key} - Cross-region and cross-account access
- AWS authentication and credential chain
- Caching and performance optimization
Next Steps¶
- Custom Resolvers - Write your own resolvers for custom data sources
- Core Resolvers - Environment variables, file includes, HTTP fetching
See Also¶
- ADR-002 Resolver Architecture - Technical design
- ADR-019 Resolver Extension Packages - Extension architecture
- FEAT-007 AWS Resolvers - Full specification