AWS Cloud Operations Blog

AWS Systems Manager Run Command now supports interpolating parameters into environment variables

Introduction

Today we are introducing an important enhancement to AWS Systems Manager (SSM) Documents environment variable interpolation when processing parameters. This feature, now available in schema version 2.2 with AWS Systems Manager Agent v3.3.2746.0 or later, simplifies document execution by ensuring parameter values are treated as literal strings, eliminating unexpected behavior and streamlining your automation processes.

When building automation scripts, secure parameter handling is essential for maintaining robust and reliable systems. By following best practices for parameter validation and using enhanced security features, you can effectively manage dynamic inputs while protecting your applications from unintended command execution.

By interpolating parameters into environment variables, SSM documents can now safely handle parameters by converting them into environment variables before execution. This approach significantly reduces the risk of command injection by allowing parameters to be treated as data, not code.

While traditional approaches often rely on complex regular expressions for input validation—which can be challenging to create, maintain, and debug—environment variable interpolation provides a streamlined and effective solution. By handling parameters as environment variables, you get built-in protection against command injection without having to craft perfect regex patterns for every possible input scenario.

How It Works

When you set the interpolationType parameter to ENV_VAR in your AWS Systems Manager (SSM) document:

  1. The AWS SSM Agent creates an environment variable named SSM_parameter-name containing your parameter value.
  2. Your commands can then reference this environment variable instead of directly inserting the parameter value.
  3. This prevents special characters in the parameter from being interpreted by the shell.

Implementation Examples

Example of a simple secure command execution

schemaVersion: '2.2'
description: An example document.
parameters:
  Message:
    type: String
    description: "Message to be printed"
    default: Hello
    interpolationType: ENV_VAR
    allowedPattern: "^[a-zA-Z0-9_/.-]+$"
mainSteps:
  - action: aws:runShellScript
    name: printMessage
    precondition:
      StringEquals:
        - platformType
        - Linux
    inputs:
      runCommand:
        - echo {{Message}}

Note: In the runCommand section of the AWS Systems Manager (SSM) document, you can directly utilize parameter references using either of the following syntax formats:

  1. {{parameterName}}: This syntax allows you to reference a parameter by its name.
  2. $SSM_parameterName: This syntax also allows you to reference a parameter by its name, but using the $SSM_ prefix.

Example of using parameters in interpreted languages

schemaVersion: '2.2'
description: 'Secure Python script execution'
parameters:
  inputData:
    type: String
    description: 'Input data for processing'
    interpolationType: 'ENV_VAR'
mainSteps:
  - action: aws:runPowerShellScript
    name: runPython
    inputs:
      runCommand:
        - |
          python3 -c '
          import os
          import json
          # Safely access parameter through environment variable
          input_data = os.environ.get("SSM_inputData", "")
          # Process the data
          try:
              processed_data = json.loads(input_data)
              print(f"Successfully processed: {processed_data}")
          except json.JSONDecodeError:
              print("Invalid JSON input")

Example of using fallback logic

For environments running older AWS Systems Manager (SSM) Agent versions, you can implement a fallback logic:

schemaVersion: '2.2'
description: 'Backwards compatible secure parameter handling'
parameters:
  userInput:
    type: String
    description: 'User input to process'
    interpolationType: 'ENV_VAR'
    allowedPattern: '^[a-zA-Z0-9_\-. ]+$'
mainSteps:
  - action: aws:runShellScript
    name: processInput
    inputs:
      runCommand:
        - |
          # Handle both modern and legacy agent versions
          if [ -z "${SSM_userInput+x}" ]; then
            # Legacy agent - fall back to direct parameter reference
            export SSM_userInput="{{userInput}}"
          fi
          # Process the input securely
          echo "Processing input: $SSM_userInput"

Security Best Practices

To improve security when working with AWS Systems Manager (SSM) documents:

  1. Always use environment variable interpolation: Set interpolationType: ENV_VAR or string parameters used in command execution.
  2. Implement input validation: Use allowedPattern to restrict parameter values to safe patterns.
  3. Handle legacy systems: Include fallback logic for older AWS Systems Manager (SSM) Agent versions.
  4. Escape special characters: Properly escape special characters when using parameter values in commands.
  5. Limit parameter scope: Use the most restrictive parameter patterns possible for your use case.

Important considerations: While environment variable interpolation significantly improves security by preventing parameter injection at the document level, it’s important to understand its limitations.

This solution specifically targets top-level escapes where code execution is not expected. However, it cannot prevent command execution if your scripts explicitly use evaluation constructs such as eval statements, backticks (`command`), or $(command) syntax in bash.

For instance, even with interpolation enabled, a script containing eval "$SSM_userInput" would still execute any commands contained in that parameter. When your scripts intentionally evaluate expressions, you must implement additional validation layers specific to your use case to maintain security.

Integrating with AWS Systems Manager (SSM) parameter store

For frequently used parameters, we recommend storing them in parameter tore and referencing them in your documents:

schemaVersion: '2.2'
description: runShellScript with command strings stored as Parameter Store parameter
parameters:
  commands:
    type: StringList
    description: "(Required) The commands to run on the instance."
    default: ["{{ ssm:myShellCommands }}"]
    interpolationType: ENV_VAR
mainSteps:
  - action: aws:runShellScript
    name: runShellScriptDefaultParams
    inputs:
      runCommand: "{{ commands }}"

How to update existing AWS SSM documents using Amazon Q

If you have existing SSM documents that needs to be update to use environment variable interpolation, you can leverage Amazon Q to automate this process.

Step 1: Install Amazon Q
Available in VS Code, JetBrains IDEs, or as a standalone application.

Step 2: Sign In
Use your AWS Builder ID or IAM Identity Center credentials.

Step 3: Open Your SSM Document
Load the AWS Systems Manager (SSM) document you want to update in the IDE.

Step 4: Use Our Prompt
Copy the prompt from our GitHub repository and paste it into the Amazon Q chat panel and hit Return to see updated AWS Systems Manager (SSM) document.

Note: The GitHub repository also includes sample AWS Systems Manager (SSM) documents showing before and after transformations.

Examples of using AWS-RunPatchBaseline document with variable interpolation

For example, here’s a code snippet of an older AWS-RunPatchBaseline.json document where parameters resolution happens by replacing {{ParameterName}} with actual values:

"try:",

"    import common_startup_entrance",

"    common_startup_entrance.execute(\"os_selector\", \"PatchLinux\", \"{{SnapshotId}}\",\\",

 "            \"{{Operation}}\", \"{{InstallOverrideList}}\", \\",

 "            \"{{RebootOption}}\", \"{{BaselineOverride}}\", \"{{AssociationId}}\")",

Now here’s a code snippet of new AWS-RunPatchBaseline.json document where we are checking for environment variables and then referencing these environment variables instead of directly inserting the parameter values:

"# Checking if env variables are set",

"",

"if [[ -z \"${SSM_AssociationId}\"]]; then",

"   export SSM_AssociationId = \"{{AssociationId}}\"",

"fi-,

"",

"if [[ -z \"${SSM_BaselineOverride}\"]]; then",

"   export SSM_BaselineOverride = \"{{BaselineOverride}}\"",

"fi",

"",

"if [[ -z \"${SSM_InstallOverrideList}\"]]; then",

"   export SSM_InstallOverrideList = \"{{InstallOverrideList}}\"",

"fi",

"",

"if [[ -z \"${SSM_SnapshotId}\"]]; then",

"   export SSM_SnapshotId = \"{{SnapshotId}}\"",

"fi",

"",
"try:",

"    import common_startup_entrance",

"    common_startup_entrance.execute(\"os_selector\", \"PatchLinux\", os.environ.get['SSM_SnapshotId'],\\",

"            \"{{Operation}}\", os.environ.get['SSM_InstallOverrideList'], \\",

"            \"{{RebootOption}}\", os.environ.get['SSM_BaselineOverride'], os.environ.get['SSM_AssociationId'])",

Conclusion

Environment variable interpolation in AWS Systems Manager (SSM) Documents simplifies automation workflows. By implementing this feature, you can help protect your systems against command injection vulnerabilities while maintaining the flexibility and power of AWS Systems Manager (SSM) documents. You should consider updating the AWS Systems Manager Agent to v3.3.2746.0 or later to leverage parameter interpolation. For more information, visit AWS Systems Manager Documentation.

Rizwan Mohammed

Rizwan Mohammed

Rizwan Mohammed is a Senior Technical Account Manager at AWS helping Enterprise customers adopt AWS services, build new architectures, and optimize their current implementations. With specializations in Cloud Operations and Microsoft workloads, he has a passion for enhancing operational excellence for customers.

Ravindra Kori

Ravindra Kori

Ravindra Kori is a Sr. Solutions Architect and GenAI ambassador at AWS based in Arlington, specializing in Cloud Operations and Serverless technologies. He works extensively with Enterprise and Startup segments, architecting solutions and facilitating AWS modernization and migrations. Outside of work, he finds joy in playing drums and spending quality time with family.