AWS Systems Manager Parameter Store serves as the foundational service for storing configuration values, feature flags, database connection strings, and other runtime settings within the AWS ecosystem. Unlike the Secrets Manager service, which is engineered specifically for sensitive credentials that require automatic rotation and cross-account sharing, Parameter Store is designed for broader utility. It handles both sensitive and non-sensitive configuration data with a simpler architecture and a more favorable cost structure, particularly given that the standard tier is free. Terraform provides the necessary infrastructure-as-code capability to define these parameters programmatically, ensuring version control and consistent deployment across disparate environments. This approach allows teams to manage application configuration as code, deploy changes reliably, and integrate parameter values into other infrastructure resources seamlessly.
Architectural Context and Service Comparison
Understanding the distinction between Parameter Store and Secrets Manager is critical for architectural decision-making. Both services store configuration values, but they are designed for different use cases based on operational requirements and cost considerations.
| Feature | Parameter Store | Secrets Manager |
|---|---|---|
| Primary Use Case | Plain configuration values (endpoints, flags, ports) | Credentials requiring automatic rotation |
| Cost Structure | Standard tier is free; Advanced tier incurs costs | $0.40 per secret per month |
| Encryption | KMS for SecureString types | KMS for all types |
| Rotation | Manual or via automation | Automatic and scheduled |
| Sharing | Cross-account via SCP or resource policies | Native cross-account sharing |
Many engineering teams adopt a hybrid model, utilizing Parameter Store for general configuration items such as API endpoints, environment names, and feature flags, while reserving Secrets Manager for database credentials and API keys that must be rotated on a schedule. This strategy optimizes cost while maintaining appropriate security postures for different data classes. When selecting the service, consider whether the data requires native rotation or if it remains static for extended periods. For static data, Parameter Store is often the superior choice due to its lower latency and cost efficiency.
Provider Requirements and Versioning
Before defining parameters, the Terraform configuration must declare the necessary provider versions and dependencies. The AWS provider version significantly impacts the available features and stability of the aws_ssm_parameter resource.
```terraform
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
```
For organizations utilizing community-maintained wrapper modules, such as terraform-aws-modules/ssm-parameter/aws, specific version constraints apply. The recommended module versions require Terraform version >= 1.11 and AWS provider version >= 6.28. These dependencies ensure compatibility with the latest AWS API features and Terraform language constructs. It is essential to align the provider version in the root module with the requirements defined in any child modules to prevent version conflicts during initialization.
Basic Parameter Types: String and StringList
The most common parameter type is String, which stores plain text data. This type is suitable for environment names, URLs, and feature flags. The resource definition includes the parameter name, type, value, and optional metadata such as descriptions and tags.
```terraform
Simple string parameter for environment name
resource "awsssmparameter" "app_environment" {
name = "/myapp/production/environment"
type = "String"
value = "production"
description = "Application environment name"
tags = {
Environment = "production"
Service = "myapp"
}
}
Parameter for a configuration URL
resource "awsssmparameter" "apiendpoint" {
name = "/myapp/production/apiendpoint"
type = "String"
value = "https://api.example.com/v2"
description = "External API endpoint URL"
tags = {
Environment = "production"
Service = "myapp"
}
}
Feature flag as a parameter
resource "awsssmparameter" "featurenewui" {
name = "/myapp/production/features/newuienabled"
type = "String"
value = "true"
description = "Feature flag for the new UI design"
tags = {
Environment = "production"
ManagedBy = "terraform"
}
}
```
The StringList type is utilized for storing comma-separated values, which is particularly useful for lists of allowed IP addresses (CIDR blocks), feature flag targets, or enabled regions. Unlike the String type, the value must be a single string containing comma-separated items.
```terraform
A list of allowed CIDR blocks
resource "awsssmparameter" "allowedcidrs" {
name = "/myapp/production/network/allowedcidrs"
type = "StringList"
value = "10.0.0.0/16,172.16.0.0/12,192.168.0.0/16"
description = "Comma-separated list of allowed CIDR blocks"
}
A list of enabled regions
resource "awsssmparameter" "enabled_regions" {
name = "/myapp/production/regions"
type = "StringList"
value = "us-east-1,us-west-2,eu-west-1"
description = "Regions where the application is deployed"
}
```
Using StringList allows applications to retrieve the list as a structured object rather than parsing a raw string, reducing the likelihood of configuration errors in client code.
SecureString Parameters and Encryption Management
Sensitive data such as database passwords, API keys, and tokens must be stored as SecureString parameters. These parameters are encrypted using AWS Key Management Service (KMS). By default, SecureString parameters use the AWS managed key aws/ssm, but they can be encrypted with a customer-managed KMS key for stricter compliance requirements.
```terraform
Encrypted parameter using the default AWS managed key
resource "awsssmparameter" "db_password" {
name = "/myapp/production/database/password"
type = "SecureString"
value = "change-me-in-console"
description = "Production database password"
tags = {
Environment = "production"
Sensitive = "true"
}
lifecycle {
ignore_changes = [value]
}
}
```
A critical security consideration when storing secrets in Terraform is that the parameter value ends up in the Terraform state file. For many organizations, this is an unacceptable security risk. A common pattern to mitigate this is to create the parameter with a placeholder value in Terraform and then update the actual value manually or through a separate secrets management workflow.
```terraform
Create with placeholder, update manually after
resource "awsssmparameter" "apikey" {
name = "/myapp/production/externalapi_key"
type = "SecureString"
value = "placeholder-update-after-creation"
description = "API key for the external payment service"
lifecycle {
ignore_changes = [value]
}
}
```
By setting ignore_changes = [value] in the lifecycle block, Terraform prevents overwriting the value if it is changed manually in the AWS Console or via another automation tool. This ensures that the source of truth for the secret remains the AWS service, not the Terraform state.
When a custom KMS key is required, the key_id attribute specifies the KMS key ID or ARN. This is crucial for organizations that enforce encryption key rotation or require specific key policies for data isolation.
| Attribute | Description |
|---|---|
type |
Must be SecureString for encryption |
key_id |
KMS key ID or ARN for custom encryption |
value |
The secret data to be encrypted |
lifecycle |
Configure ignore_changes to prevent state overwrite |
Advanced Configuration and Wrapper Modules
For complex deployments managing multiple parameters, the terraform-aws-modules/ssm-parameter/aws module offers a wrapper interface that reduces boilerplate code. This module supports features such as value type guessing, ignoring value changes, and managing resources with less repetition.
The module accepts a locals block containing a map of parameters, allowing for dynamic creation of multiple resources. The following configuration demonstrates the creation of String, SecureString, and StringList parameters within a single module call.
```terraform
locals {
parameters = {
# String
"stringsimple" = {
value = "stringvalue123"
}
"string" = {
type = "String"
value = "string_value123"
tier = "Intelligent-Tiering"
allowed_pattern = "[a-z0-9_]+"
}
# SecureString
"secure" = {
type = "SecureString"
value = "secret123123!!!"
tier = "Advanced"
description = "My awesome password!"
}
"secure_encrypted_true" = {
secure_type = true
value = "secret123123!!!"
key_id = "c938de44-1c09-4c91-89fd-b5881f06f317"
}
# StringList
"list_as_autoguess_type" = {
values = ["item1", "item2"]
}
}
}
module "ssm_params" {
source = "terraform-aws-modules/ssm-parameter/aws"
name = "my-parameter-group"
parameters = local.parameters
}
```
The wrapper module provides several attributes for fine-tuning behavior:
| Attribute | Description | Default |
|---|---|---|
create |
Whether to create the SSM Parameter | true |
data_type |
Data type (text, aws:ssm:integration, aws:ec2:image) |
null |
description |
Description of the parameter | null |
ignore_value_changes |
Whether to ignore changes in value | false |
allowed_pattern |
Regular expression to validate the value | null |
overwrite |
Overwrite existing parameter | null |
The data_type attribute is particularly relevant for AMI IDs, where the value must be in the aws:ec2:image format. The allowed_pattern attribute enforces value validity using regular expressions, providing an additional layer of configuration integrity.
Data Sources and Resource Integration
Terraform can read existing SSM parameters to reference their values in other resources. This is useful for referencing parameters created by other Terraform configurations or manually.
```terraform
Read an existing parameter
data "awsssmparameter" "vpcid" {
name = "/infrastructure/production/vpcid"
}
Use the parameter value in other resources
resource "awssecuritygroup" "app" {
nameprefix = "myapp-"
vpcid = data.awsssmparameter.vpc_id.value
}
Read a SecureString parameter (the value will be decrypted)
data "awsssmparameter" "dbpassword" {
name = "/myapp/production/database/password"
withdecryption = true
}
```
The with_decryption flag is essential when reading SecureString parameters. When set to true, the AWS provider decrypts the value using KMS, making it available for use in other resources. If this flag is omitted, the value remains encrypted and cannot be used directly.
Tier Selection and Pricing Considerations
SSM Parameter Store offers two pricing tiers: Standard and Advanced. The choice of tier impacts the number of requests allowed per second and the parameter size limit.
- Standard Tier: This tier is free for basic usage. It allows up to 3,000 requests per 1,000 parameters per second. It is suitable for most application configuration needs where high-throughput reads are not a bottleneck.
- Advanced Tier: This tier incurs costs but offers higher throughput and larger parameter sizes. It is necessary for applications that require high-frequency reads or store large configuration blocks.
The tier attribute in the wrapper module allows specifying the tier explicitly. For example, setting tier = "Intelligent-Tiering" or tier = "Advanced" ensures the parameter is provisioned with the correct performance characteristics. If not specified, the default is typically Standard, which is cost-effective for the majority of use cases.
Conclusion
AWS Systems Manager Parameter Store, when managed through Terraform, provides a robust and cost-effective mechanism for managing application configuration. The distinction between Standard and Advanced tiers, along with the choice between Parameter Store and Secrets Manager, must be aligned with operational requirements and cost constraints. Terraform's ability to define parameters as code ensures consistency and version control, while the use of SecureString and KMS encryption addresses security needs for sensitive data.
For teams managing large numbers of parameters, the wrapper module terraform-aws-modules/ssm-parameter/aws offers a streamlined approach, reducing code complexity and supporting features like value pattern validation and type guessing. However, for simple deployments, direct use of the aws_ssm_parameter resource provides greater transparency and control.
When dealing with secrets, the risk of storing values in the Terraform state file must be mitigated. Employing the lifecycle ignore_changes block allows teams to maintain control over secret values outside of Terraform, ensuring that the AWS service remains the source of truth. By integrating data sources, teams can dynamically reference parameter values in other infrastructure components, creating a cohesive and manageable configuration landscape. This combination of simplicity, security, and flexibility makes Parameter Store a vital component of modern AWS infrastructure management.