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:
- The AWS SSM Agent creates an environment variable named
SSM_parameter-name
containing your parameter value. - Your commands can then reference this environment variable instead of directly inserting the parameter value.
- 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:
{{parameterName}}
: This syntax allows you to reference a parameter by its name.$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:
- Always use environment variable interpolation: Set
interpolationType: ENV_VAR
or string parameters used in command execution. - Implement input validation: Use
allowedPattern
to restrict parameter values to safe patterns. - Handle legacy systems: Include fallback logic for older AWS Systems Manager (SSM) Agent versions.
- Escape special characters: Properly escape special characters when using parameter values in commands.
- 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.