Tuesday, October 21, 2025

AWS Systems Manager Parameter Store (SSM PS) Hierarchy | Deep Dive.


A deep dive into AWS Systems Manager (SSM) Parameter Store hierarchy.

Overview:

  •        How AWS Systems Manager (SSM) Parameter Store hierarchy enables structured secrets storage & configuration management.
  •        How twtech can leverage AWS Systems Manager (SSM) Parameter Store hierarchy for environmental isolation, access control, automation, and scaling.

 Breakdown:

  •        The concept: Parameter Hierarchy,
  •        Parameter Naming Rules & Structure,
  •        Why Hierarchy Matters,
  •        Hierarchical Access: Path Queries & Recursion,
  •        Access Control by Hierarchy,
  •        Example Hierarchical Designs,
  •        Hierarchical Retrieval Patterns in Code,
  •        Hierarchy and CloudFormation,
  •        Hierarchy for Multi-Account Strategy,
  •        Best Practices for Hierarchical Design,
  •        Common Pitfalls,
  •        Example Hierarchical Strategy (Recommended),
  •        twtech-insights.

1. The concept: Parameter Hierarchy

AWS SSM Parameter Store organizes parameters hierarchically, similar to a directory structure.
Each parameter name is a
path, separated by slashes (/):

/<environment>/<application>/<component>/<key>

Example:

/prod/web/api/db/password
/dev/web/api/db/password
/shared/logging/level

This hierarchy is purely logical — it helps you organize, isolate, and secure your configuration data.

 2. Parameter Naming Rules & Structure

Feature

Description

Separator

/ (forward slash). Think of folders/subfolders.

Root

Always starts with a slash /

Max Depth

Up to 15 levels deep.

Max Name Length

1011 characters total.

Allowed Characters

a-zA-Z0-9_.-/

Case-sensitive

Yes/Prod/DB /prod/db.

 3. Why Hierarchy Matters

a. Environment Segregation

Separate configs by environment:

/dev/...
/qa/...
/prod/...

→ Makes it easy to grant access to dev teams only under /dev/*.

b. Application or Service Segregation

Each app gets its own tree:

/prod/payment/api/key
/prod/payment/db/password
/prod/analytics/s3/bucket

c. Cross-Account or Shared Resources

Store reusable parameters under /shared/ or /global/.

d. Least Privilege IAM Control

# IAM policies can restrict access to parameter paths:

{
  "Effect": "Allow",
  "Action": ["ssm:GetParameter", "ssm:GetParametersByPath"],
  "Resource": "arn:aws:ssm:us-east-2:acccountID:parameter/prod/payment/*"
}

e. Automation with GetParametersByPath

Instead of fetching each parameter one by one:

aws ssm get-parameters-by-path --path "/prod/web/api" --with-decryption

→ Returns all configs for that service/environment at once.

 4. Hierarchical Access: Path Queries & Recursion

SSM Parameter Store supports:

  •         Non-recursive queries – only direct children under a given path.
  •         Recursive queries – includes all sub-paths.

Example:

Parameters:

/prod/web/api/db/password
/prod/web/api/db/host
/prod/web/frontend/url

Command:

aws ssm get-parameters-by-path --path "/prod/web/api" --recursive

→ Returns both db/password and db/host.

 5. Access Control by Hierarchy

Hierarchical paths integrate tightly with IAM policies, tags, and KMS key policies for security isolation.

Example: Policy for Dev Environment

{
  "Effect": "Allow",
  "Action": ["ssm:GetParameter", "ssm:GetParametersByPath"],
  "Resource": "arn:aws:ssm:us-east-1:123456789012:parameter/dev/*"
}

Example: Policy for Shared Read Access

{
  "Effect": "Allow",
  "Action": "ssm:GetParameter",
  "Resource": "arn:aws:ssm:us-east-1:123456789012:parameter/shared/*"
}

Combine with KMS Key Policies

twtech can encrypt /prod/* parameters with one CMK and /dev/* with another, ensuring data boundaries even at encryption layer.

 6. Example Hierarchical Designs

Pattern 1: Environment-Centric

/dev/app1/db/username
/dev/app1/db/password
/prod/app1/db/username
/prod/app1/db/password

 Use case: Simpler for teams that deploy the same app across multiple stages.

Pattern 2: Service-Centric

/app1/dev/db/username
/app1/dev/db/password
/app1/prod/db/username
/app1/prod/db/password

 Use case: Better if each app manages its own pipeline and lifecycle.

Pattern 3: Shared Config Pattern

/shared/logging/level
/shared/audit/s3/bucket
/prod/app1/...
/prod/app2/...

 Use case: Central governance configs for multiple systems.

Pattern 4: Cross-Account / Multi-Region

Combine hierarchy naming with region identifiers:

/us-east-2/prod/app1/db/endpoint
/us-west-1/prod/app1/db/endpoint

 Use case: Multi-region redundancy or AWS Organization-level deployment.

7. Hierarchical Retrieval Patterns in Code

# Python Example (Recursive Fetch)

import boto3
ssm = boto3.client('ssm')
params = ssm.get_parameters_by_path(
    Path='/prod/web/api',
    Recursive=True,
    WithDecryption=True
)
config = {p['Name']: p['Value'] for p in params['Parameters']}
print(config)

twtech can then map the structure dynamically to its application’s configuration model.

 8. Hierarchy and CloudFormation

twtech can reference hierarchical SSM parameters directly in CloudFormation:

Plaintext Example:

EnvironmentName: {{resolve:ssm:/prod/web/api/env}}

Encrypted Example:

DBPassword: {{resolve:ssm-secure:/prod/web/api/db/password:1}}

twtech can parameterize your stack templates by simply switching the base path:

Parameters:
  EnvPath:
    Type: String
    Default: /prod
Resources:
  MyLambda:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          DB_PASSWORD: {{resolve:ssm-secure:${EnvPath}/web/api/db/password}}

 9. Hierarchy for Multi-Account Strategy

In multi-account setups (Dev, QA, Prod), you can:

  •         Use consistent parameter paths across accounts.
  •         Manage replication via AWS Lambda or EventBridge.
  •         Encrypt per-account with its own KMS CMK.
  •         Grant central read access (e.g., audit account).

Example:

/organization/dev/app1/...
/organization/qa/app1/...
/organization/prod/app1/...

This makes it easy for pipelines to promote parameters across stages.

 10. Best Practices for Hierarchical Design

  • Define a global naming convention (enforced by IaC).
  • Use short, predictable prefixes (e.g. /prod, /shared).
  • Tag parameters with environment, owner, app name.
  •  Grant IAM least privilege using parameter/path/*.
  • Use customer-managed CMKs per environment or app.
  • Avoid duplicate parameters — use /shared/ for common configs.
  • Automate creation via CloudFormation or Terraform.
  • Leverage versioning — e.g. promote version N from /dev/... to /prod/....

 Common Pitfalls

   Flat parameter names — makes access control impossible.
   Mixing secrets and config in the same path.
   Using the same KMS key for all paths.
   Hardcoding environment names in code (instead of path prefix injection).
   Ignoring case sensitivity/Prod/prod.

 Example Hierarchical Strategy (Recommended)

/<organization>/<environment>/<application>/<component>/<key>

Example:

/acme/dev/web/api/url
/acme/dev/web/api/key
/acme/prod/web/api/url
/acme/prod/web/api/key
/acme/shared/monitoring/endpoint

→ Provides clean separation, consistent naming, and scalable IAM policies.

twtech-insights

Here’s a production-ready AWS CloudFormation template that builds a secure SSM Parameter Store hierarchy for /dev, /qa, and /prod — complete with:

  • Environment-specific SSM parameters (SecureString)
  • Dedicated KMS keys per environment
  • Granular IAM roles (read-only access scoped by parameter path)
  • Tagging and parameter hierarchy enforcement

# CloudFormation Template: ssm-hierarchy-with-kms-roles.yaml

AWSTemplateFormatVersion: '2010-09-09'

Description: >

  SSM Parameter Store hierarchy with KMS encryption and IAM access roles for /dev, /qa, /prod.

Parameters:

  OrgPrefix:

    Type: String

    Default: acme

    Description: twtech Prefix for hierarchical parameter naming (e.g., /acme/dev/...).

  SSMParameterValue:

    Type: String

    Default: twtechValue

    Description: Example value stored in SecureString parameters.

Resources:

  #############################################

  # KMS Keys (one per environment)

  #############################################

  DevKmsKey:

    Type: AWS::KMS::Key

    Properties:

      Description: KMS key for /twtech dev SSM parameters

      EnableKeyRotation: true

      KeyPolicy:

        Version: "2012-10-17"

        Statement:

          - Sid: twtechAllowRootAccountAccess

            Effect: Allow

            Principal:

              AWS: !Sub arn:aws:iam::${AWS::AccountId}:root

            Action: "kms:*"

            Resource: "*"

      Tags:

        - Key: Environment

          Value: dev

  QaKmsKey:

    Type: AWS::KMS::Key

    Properties:

      Description: KMS key for /twtech qa SSM parameters

      EnableKeyRotation: true

      KeyPolicy:

        Version: "2012-10-17"

        Statement:

          - Sid: twtechAllowRootAccountAccess

            Effect: Allow

            Principal:

              AWS: !Sub arn:aws:iam::${AWS::AccountId}:root

            Action: "kms:*"

            Resource: "*"

      Tags:

        - Key: Environment

          Value: qa

  ProdKmsKey:

    Type: AWS::KMS::Key

    Properties:

      Description: KMS key for /twtech prod SSM parameters

      EnableKeyRotation: true

      KeyPolicy:

        Version: "2012-10-17"

        Statement:

          - Sid: twtechAllowRootAccountAccess

            Effect: Allow

            Principal:

              AWS: !Sub arn:aws:iam::${AWS::AccountId}:root

            Action: "kms:*"

            Resource: "*"

      Tags:

        - Key: Environment

          Value: prod

  #############################################

  # Example SSM Parameters

  #############################################

  DevParameterExample:

    Type: AWS::SSM::Parameter

    Properties:

      Name: !Sub "/${OrgPrefix}/dev/app/config/value"

      Type: SecureString

      Value: twtechRef SSMParameterValue

      KeyId: twtechRef DevKmsKey

      Tags:

        Environment: dev

        Application: app

  QaParameterExample:

    Type: AWS::SSM::Parameter

    Properties:

      Name: !Sub "/${OrgPrefix}/qa/app/config/value"

      Type: SecureString

      Value: twtechRef SSMParameterValue

      KeyId: twtechRef QaKmsKey

      Tags:

        Environment: qa

        Application: app

  ProdParameterExample:

    Type: AWS::SSM::Parameter

    Properties:

      Name: !Sub "/${OrgPrefix}/prod/app/config/value"

      Type: SecureString

      Value: twtechRef SSMParameterValue

      KeyId: twtechRef ProdKmsKey

      Tags:

        Environment: prod

        Application: app

  #############################################

  # IAM Roles (Scoped Read-Only Access)

  #############################################

  DevReadRole:

    Type: AWS::IAM::Role

    Properties:

      RoleName: !Sub "${OrgPrefix}-dev-ssm-read-role"

      AssumeRolePolicyDocument:

        Version: "2012-10-17"

        Statement:

          - Effect: Allow

            Principal:

              AWS: !Sub arn:aws:iam::${AWS::AccountId}:root

            Action: sts:AssumeRole

      Policies:

        - PolicyName: twtechDevSSMReadPolicy

          PolicyDocument:

            Version: "2012-10-17"

            Statement:

              - Effect: Allow

                Action:

                  - ssm:GetParameter

                  - ssm:GetParameters

                  - ssm:GetParametersByPath

                Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${OrgPrefix}/dev/*

              - Effect: Allow

                Action: kms:Decrypt

                Resource: !GetAtt DevKmsKey.Arn

      Tags:

        - Key: Environment

          Value: dev

  QaReadRole:

    Type: AWS::IAM::Role

    Properties:

      RoleName: !Sub "${OrgPrefix}-qa-ssm-read-role"

      AssumeRolePolicyDocument:

        Version: "2012-10-17"

        Statement:

          - Effect: Allow

            Principal:

              AWS: !Sub arn:aws:iam::${AWS::AccountId}:root

            Action: sts:AssumeRole

      Policies:

        - PolicyName: twtechQaSSMReadPolicy

          PolicyDocument:

            Version: "2012-10-17"

            Statement:

              - Effect: Allow

                Action:

                  - ssm:GetParameter

                  - ssm:GetParameters

                  - ssm:GetParametersByPath

                Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${OrgPrefix}/qa/*

              - Effect: Allow

                Action: kms:Decrypt

                Resource: !GetAtt QaKmsKey.Arn

      Tags:

        - Key: Environment

          Value: qa

  ProdReadRole:

    Type: AWS::IAM::Role

    Properties:

      RoleName: !Sub "${OrgPrefix}-prod-ssm-read-role"

      AssumeRolePolicyDocument:

        Version: "2012-10-17"

        Statement:

          - Effect: Allow

            Principal:

              AWS: !Sub arn:aws:iam::${AWS::AccountId}:root

            Action: sts:AssumeRole

      Policies:

        - PolicyName: twtechProdSSMReadPolicy

          PolicyDocument:

            Version: "2012-10-17"

            Statement:

              - Effect: Allow

                Action:

                  - ssm:GetParameter

                  - ssm:GetParameters

                  - ssm:GetParametersByPath

                Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${OrgPrefix}/prod/*

              - Effect: Allow

                Action: kms:Decrypt

                Resource: !GetAtt ProdKmsKey.Arn

      Tags:

        - Key: Environment

          Value: prod

 Outputs:

  DevSSMPath:

    Description: Base SSM path for dev environment

    Value: !Sub "/${OrgPrefix}/dev/"

  QaSSMPath:

    Description: Base SSM path for qa environment

    Value: !Sub "/${OrgPrefix}/qa/"

  ProdSSMPath:

    Description: Base SSM path for prod environment

    Value: !Sub "/${OrgPrefix}/prod/"

  DevReadRoleArn:

    Description: IAM Role ARN for dev SSM read access

    Value: !GetAtt DevReadRole.Arn

  QaReadRoleArn:

    Description: IAM Role ARN for qa SSM read access

    Value: !GetAtt QaReadRole.Arn

  ProdReadRoleArn:

    Description: IAM Role ARN for prod SSM read access

    Value: !GetAtt ProdReadRole.Arn

 What This Stack Provides

Component

Description

KMS Keys

Separate CMKs for /dev, /qa, /prod — full key rotation, independent policies.

SSM Parameters

SecureString entries with hierarchical naming: /acme/dev/..., /acme/qa/..., /acme/prod/....

IAM Roles

Environment-scoped roles with read-only access (both SSM and KMS).

Tags

Environments, applications, and key associations tagged for governance.

 Deployment

# bash

aws cloudformation deploy \

  --template-file twtech-ssm-hierarchy-with-kms-roles.yaml \

  --stack-name twtech-ssm-hierarchy-stack \

  --capabilities CAPABILITY_NAMED_IAM

 Next Steps (Optional Enhancements)

  • Add Parameter Policies (expiration or rotation reminders).
  • Extend to cross-account KMS grants for shared environments.
  • Add EventBridge rule to replicate parameters across accounts.
  • Integrate with CodePipeline or Terraform to populate configs dynamically.


twtech -insights

A production-ready AWS CloudFormation template that builds a secure SSM Parameter Store hierarchy for /dev, /qa, and /prod into a multi-account version, (where /dev, /qa, and /prod are within separate AWS accounts) using AWS Organizations + KMS grants + cross-account IAM roles

# Multi-account-ssm-parameter-hierarchy-stackset· yaml

AWSTemplateFormatVersion: '2010-09-09'

Description: >-

  StackSet template to create a secure SSM Parameter Store hierarchy per-environment

  (/dev, /qa, /prod) in a *member* AWS account. Designed to be deployed via

  CloudFormation StackSets from a management (org) account.

  Features:

    - KMS CMK per-account with least-privileged key policy to allow a central

      access role to use the key.

    - IAM role in the member account that the central account can assume to

      access SSM parameters in this account under the environment prefix.

    - Optional Lambda-backed custom resource that issues a KMS Grant so the

      central principal can use the key without changing the key policy often.

    - Creates a sample secure parameter under the environment prefix (encrypted

      with the CMK).

Parameters:

  EnvironmentName:

    Type: String

    Description: Environment name (dev, qa, prod)

    AllowedValues: [dev, qa, prod]

  CentralAccountId:

    Type: String

    Description: AWS Account ID of the central/security/account that will access parameters

  CentralAccessRoleName:

    Type: String

    Description: IAM role name in the central account that will assume the cross-account role in this member account

    Default: CentralSSMAccessRole

  CreateKMSGrant:

    Type: String

    AllowedValues: [true, false]

    Default: true

    Description: Whether to create a KMS Grant via a Lambda custom resource for the central principal. Use `true` for dynamic grant creation.

  ParameterSampleValue:

    Type: String

    Description: A sample value to store under the environment prefix (secure string)

    NoEcho: true

    Default: "SampleSecretValue"

Mappings: {}

Resources:

  # ----------------------------- KMS key for this account -----------------------------

  EnvKmsKey:

    Type: AWS::KMS::Key

    Properties:

      Description: !Sub "SSM parameter key for ${EnvironmentName} hierarchy"

      KeyPolicy: !Sub |

        {

          "Version":"2012-10-17",

          "Id":"key-default-1",

          "Statement":[

            {

              "Sid":"twtechAllow administration of the key",

              "Effect":"Allow",

              "Principal":{"AWS":"arn:aws:iam::${AWS::AccountId}:root"},

              "Action":"kms:*",

              "Resource":"*"

            },

            {

              "Sid":"twtechAllowCloudFormationToUseKey",

              "Effect":"Allow",

              "Principal":{"Service":"cloudformation.amazonaws.com"},

              "Action":["kms:Encrypt","kms:Decrypt","kms:ReEncrypt*","kms:GenerateDataKey*","kms:DescribeKey"],

              "Resource":"*"

            },

            {

              "Sid":"twtechAllowCentralAccessRole",

              "Effect":"Allow",

              "Principal":{"AWS":"arn:aws:iam::${CentralAccountId}:role/${CentralAccessRoleName}"},

              "Action":["kms:Decrypt","kms:Encrypt","kms:ReEncrypt*","kms:GenerateDataKey*","kms:DescribeKey"],

              "Resource":"*"

            }

          ]

        }

  EnvKmsAlias:

    Type: AWS::KMS::Alias

    Properties:

      AliasName: !Sub "alias/ssm-${EnvironmentName}"

      TargetKeyId: twtechRef EnvKmsKey

  # ----------------------------- Cross-account role -----------------------------

  CentralAssumableRole:

    Type: AWS::IAM::Role

    Properties:

      RoleName: !Sub "SSM-CrossAccount-Access-${EnvironmentName}"

      AssumeRolePolicyDocument:

        Version: '2012-10-17'

        Statement:

          - Effect: Allow

            Principal:

              AWS: !Sub "arn:aws:iam::${CentralAccountId}:root"

            Action: sts:AssumeRole

            Condition: {}

      Description: >-

        Role that the central account uses to assume access into this member account

        for reading/writing SSM parameters under /${EnvironmentName}.

      Policies:

        - PolicyName: twtechSSMAccessForCentral

          PolicyDocument:

            Version: '2012-10-17'

            Statement:

              - Effect: Allow

                Action:

                  - ssm:GetParameter

                  - ssm:GetParametersByPath

                  - ssm:PutParameter

                  - ssm:DeleteParameter

                Resource: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${EnvironmentName}/*"

  # ----------------------------- Sample secure parameter -----------------------------

  SampleSecureParameter:

    Type: AWS::SSM::Parameter

    Properties:

      Name: !Sub "/${EnvironmentName}/sample/secret"

      Type: SecureString

      Value: twtechRef ParameterSampleValue

      KeyId: twtechRef EnvKmsKey

      Tier: Standard

  # ----------------------------- Lambda to create KMS grant -----------------------------

  KMGrantLambdaRole:

    Type: AWS::IAM::Role

    Properties:

      RoleName: !Sub "KMSGrantLambdaRole-${EnvironmentName}-${AWS::StackName}"

      AssumeRolePolicyDocument:

        Version: '2012-10-17'

        Statement:

          - Effect: Allow

            Principal:

              Service: lambda.amazonaws.com

            Action: sts:AssumeRole

      ManagedPolicyArns:

        - arn:aws:iam::aws:policy/service-role/twtechAWSLambdaBasicExecutionRole

      Policies:

        - PolicyName: twtechKMSGrantCreatePolicy

          PolicyDocument:

            Version: '2012-10-17'

            Statement:

              - Effect: Allow

                Action:

                  - kms:CreateGrant

                  - kms:ListGrants

                  - kms:RetireGrant

                  - kms:RevokeGrant

                  - kms:DescribeKey

                Resource: !Ref EnvKmsKey

  KMGrantLambda:

    Type: AWS::Lambda::Function

    Condition: CreateKMSGrantCondition

    Properties:

      Handler: index.handler

      Runtime: python3.9

      Role: !GetAtt KMGrantLambdaRole.Arn

      Timeout: 60

      MemorySize: 128

      Description: Creates a KMS Grant that allows the central access role to use the CMK

      Code:

        ZipFile: |

          import json

          import boto3

          import cfnresponse

          import os

          kms = boto3.client('kms')

          def handler(event, context):

              physical_id = 'KMSGrant-{}-{}'.format(os.environ.get('ENV'), context.log_stream_name)

              props = event.get('ResourceProperties', {})

              key_id = props.get('KeyId')

              grantee_principal = props.get('GranteePrincipal')

              try:

                  if event['RequestType'] in ('Create','Update'):

                      grant = kms.create_grant(KeyId=key_id,

                                              GranteePrincipal=grantee_principal,

                                              Operations=['Encrypt','Decrypt','GenerateDataKey','GenerateDataKeyWithoutPlaintext','DescribeKey'],

                                              Name='CFNGrant')

                      # return GrantId as part of physical resource id

                      physical_id = grant['GrantId']

                      cfnresponse.send(event, context, cfnresponse.SUCCESS, {'GrantId':grant['GrantId']}, physical_id)

                  elif event['RequestType'] == 'Delete':

                      # try to revoke grants with matching Name 'CFNGrant' or using GrantId if we stored it

                      # CloudFormation will pass the PhysicalResourceId we returned on Create

                      grant_id = event.get('PhysicalResourceId')

                      try:

                          kms.revoke_grant(KeyId=key_id, GrantId=grant_id)

                      except Exception:

                          # best-effort

                          pass

                      cfnresponse.send(event, context, cfnresponse.SUCCESS, {}, physical_id)

              except Exception as e:

                  cfnresponse.send(event, context, cfnresponse.FAILED, {'Message':str(e)}, physical_id)

      Environment:

        Variables:

          ENV: !Ref EnvironmentName

  KMGrantCustomResource:

    Type: Custom::CreateKMSGrant

    Condition: CreateKMSGrantCondition

    Properties:

      ServiceToken: !GetAtt KMGrantLambda.Arn

      KeyId: !Ref EnvKmsKey

      GranteePrincipal: !Sub "arn:aws:iam::${CentralAccountId}:role/${CentralAccessRoleName}"

Conditions:

  CreateKMSGrantCondition: !Equals [ !Ref CreateKMSGrant, "true" ]

Outputs:

  KmsKeyArn:

    Description: ARN of the KMS key used to encrypt SSM parameters in this account

    Value: !GetAtt EnvKmsKey.Arn

  CrossAccountRoleArn:

    Description: ARN of the role to be assumed by the central account to access SSM parameters in this account

    Value: !GetAtt CentralAssumableRole.Arn

  SampleParameterName:

    Description: The sample secure parameter created for this environment

    Value: !Ref SampleSecureParameter

# End of template

What !Sub Does

# !Sub stands for Fn::Sub, short for “Substitute
# !Sub allows you to embed variables (like parameter values, resource names, or pseudo parameters) inside a string.

# What !Ref Does

# !Ref (short for Ref function) returns a value that depends on what you’re referencing:

No comments:

Post a Comment

Amazon EventBridge | Overview.

Amazon EventBridge - Overview. Scope: Intro, Core Concepts, Key Benefits, Link to official documentation, Insights. Intro: Amazon EventBridg...