Home / AWS

AWSHow-toBeginner

Introduction to AWS Systems Manager Parameter Store: store config and secrets, read them from EC2, Lambda and ECS

Create String, StringList and SecureString parameters, organise them by path, control access with IAM, and read them from scripts, Lambda and ECS task definitions, plus when to use Secrets Manager instead.

Deepak Bhardwaj4 min read

Applies toAWS Systems Manager Parameter Store (standard and advanced tiers), AWS KMS, AWS CLI v2, boto3

What Parameter Store is for

Parameter Store is a key-value store for configuration: database hostnames, feature flags, API endpoints and small secrets. It keeps values out of code and AMIs, gives you versioning, and controls access with IAM.

Type Use for Encrypted
String Plain config (db.example.internal) No
StringList Comma-separated list (a,b,c) No
SecureString Passwords, tokens Yes, with KMS

Standard tier is free for up to 10,000 parameters and 4 KB values; advanced tier allows bigger values and parameter policies (expiry) at a cost. Check the current limits and pricing page before relying on numbers.

Step 1: Name parameters by path

Use a hierarchy so you can grant access and fetch by prefix:

/app1/prod/db/host
/app1/prod/db/password
/app1/prod/feature/new-checkout
/app1/dev/db/host

Step 2: Create parameters

aws ssm put-parameter --name /app1/prod/db/host \
  --type String --value "app1-prod.cluster-xyz.ap-south-1.rds.amazonaws.com"

aws ssm put-parameter --name /app1/prod/db/password \
  --type SecureString --value 'S3cure-Value' \
  --key-id alias/app1-prod

aws ssm put-parameter --name /app1/prod/feature/new-checkout \
  --type String --value "false" \
  --tags Key=app,Value=app1 Key=env,Value=prod

Leaving out --key-id uses the AWS managed key alias/aws/ssm. A customer managed key lets you control who can decrypt via the key policy, and is required for cross-account reads.

Update an existing value with --overwrite; each update creates a new version:

aws ssm put-parameter --name /app1/prod/feature/new-checkout --value "true" --overwrite
aws ssm get-parameter-history --name /app1/prod/feature/new-checkout \
  --query 'Parameters[].[Version,Value,LastModifiedDate]' --output table

Tip

Avoid putting secret values on the command line on shared hosts; they end up in shell history. Use --value file://secret.txt and delete the file, or create SecureStrings from your IaC tool with the value from a secure pipeline variable.

Step 3: Read parameters

# One value
aws ssm get-parameter --name /app1/prod/db/host --query Parameter.Value --output text

# A SecureString, decrypted
aws ssm get-parameter --name /app1/prod/db/password --with-decryption \
  --query Parameter.Value --output text

# Everything under a path
aws ssm get-parameters-by-path --path /app1/prod --recursive --with-decryption \
  --query 'Parameters[].[Name,Value]' --output table

# A specific version
aws ssm get-parameter --name /app1/prod/feature/new-checkout:3

From Python (Lambda or EC2)

import boto3
ssm = boto3.client("ssm")

def load_config(prefix="/app1/prod"):
    cfg, token = {}, None
    while True:
        kwargs = {"Path": prefix, "Recursive": True, "WithDecryption": True}
        if token:
            kwargs["NextToken"] = token
        resp = ssm.get_parameters_by_path(**kwargs)
        for p in resp["Parameters"]:
            cfg[p["Name"].removeprefix(prefix + "/")] = p["Value"]
        token = resp.get("NextToken")
        if not token:
            return cfg

CONFIG = load_config()   # load once per container, not per request

Loading once outside the handler avoids hitting the API on every invocation. For Lambda, the AWS Parameters and Secrets Lambda Extension adds a local cache if you need refreshes without redeploying.

From an ECS task definition

"secrets": [
  { "name": "DB_PASSWORD", "valueFrom": "arn:aws:ssm:ap-south-1:111122223333:parameter/app1/prod/db/password" }
]

The task execution role needs ssm:GetParameters on that ARN and kms:Decrypt on the key.

Step 4: IAM access by path

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["ssm:GetParameter", "ssm:GetParameters", "ssm:GetParametersByPath"],
      "Resource": "arn:aws:ssm:ap-south-1:111122223333:parameter/app1/prod/*"
    },
    {
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "arn:aws:kms:ap-south-1:111122223333:key/<key-id>"
    }
  ]
}

Note the ARN has no slash between parameter and the path, because the path already starts with /.

Common errors

Error Cause Fix
ParameterNotFound Wrong name, wrong region, or a version that doesn't exist Check --region and exact path (case-sensitive)
AccessDeniedException on GetParameter IAM resource ARN doesn't match the path Fix ARN pattern
AccessDeniedException ... kms:Decrypt Role can read the parameter but not decrypt Allow kms:Decrypt in IAM and key policy
ThrottlingException Many callers polling at startup Cache values; raise throughput setting; use GetParametersByPath

Parameter Store or Secrets Manager?

Need Use
Plain config, flags, endpoints Parameter Store
Small secrets, no rotation required Parameter Store SecureString
Automatic rotation (RDS, Redshift, custom Lambda) Secrets Manager
Cross-region secret replication Secrets Manager

Prevent problems later

  • Agree on a path convention (/<app>/<env>/<component>/<key>) before teams invent their own.
  • Manage parameters in Terraform/CloudFormation, but keep secret values out of state files where you can.
  • Alert on PutParameter and DeleteParameter for /*/prod/* paths through CloudTrail and EventBridge.
  • Use a customer managed KMS key per environment so you can revoke decrypt access cleanly.