AWS for DevOps — SSM Run Command

2 minute read

11.5 — SSM Run Command

Run Command lets you execute commands on one or hundreds of EC2 instances remotely — without SSH. Think of it as “SSH at scale with logging.”

Real-World Analogy

Run Command is like a company-wide PA announcement system. Instead of walking to each office (SSHing into each server) to deliver a message (run a command), you speak once and every office hears it. Plus, each office sends back a confirmation of what happened.

How Run Command Works

  ┌──────────┐    send-command    ┌──────────┐
  │  DevOps  │───────────────────→│SSM Service│
  │ Engineer │                    └─────┬─────┘
  └──────────┘                          │
                                        │ SSM Agent
                            ┌───────────┼───────────┐
                            ▼           ▼           ▼
                       ┌────────┐  ┌────────┐  ┌────────┐
                       │ EC2-1  │  │ EC2-2  │  │ EC2-3  │
                       └────────┘  └────────┘  └────────┘
                       Results sent back to SSM Service

Running Commands

# Run a command on a single instance
$ aws ssm send-command \
    --instance-ids i-0abc123def456 \
    --document-name AWS-RunShellScript \
    --parameters 'commands=["uptime","df -h","free -m"]'
{
    "Command": {
        "CommandId": "cmd-abc123",
        "Status": "Pending",
        "InstanceIds": ["i-0abc123def456"]
    }
}

# Run on multiple instances using tags
$ aws ssm send-command \
    --targets Key=tag:Environment,Values=production \
    --document-name AWS-RunShellScript \
    --parameters 'commands=["yum update -y --security"]' \
    --comment "Security patch - March 2026"

# Get command results
$ aws ssm get-command-invocation \
    --command-id cmd-abc123 \
    --instance-id i-0abc123def456
{
    "Status": "Success",
    "StandardOutputContent": " 11:16:00 up 45 days,  3:22,  0 users\nFilesystem  Size  Used  Avail  Use%\n/dev/xvda1   20G   8G    12G   40%\n             Mem:  7982  3215  4767",
    "StandardErrorContent": ""
}

Common SSM Documents

Document Purpose Example
AWS-RunShellScript Run shell commands (Linux) uptime, df -h, custom scripts
AWS-RunPowerShellScript Run PowerShell (Windows) Get-Service, system checks
AWS-UpdateSSMAgent Update SSM Agent Keep agent current
AWS-ConfigureAWSPackage Install/uninstall AWS packages Install CloudWatch agent
AWS-ApplyPatchBaseline Apply OS patches Monthly patching

Targeting Strategies

# By instance ID
$ aws ssm send-command \
    --instance-ids i-0abc123 i-0def456 i-0ghi789 \
    --document-name AWS-RunShellScript \
    --parameters 'commands=["hostname"]'

# By tag (recommended)
$ aws ssm send-command \
    --targets Key=tag:Role,Values=web-server \
    --document-name AWS-RunShellScript \
    --parameters 'commands=["systemctl restart nginx"]'

# By tag with multiple values
$ aws ssm send-command \
    --targets Key=tag:Environment,Values=production,staging \
    --document-name AWS-RunShellScript \
    --parameters 'commands=["cat /etc/os-release"]'

Rate Control

Prevent running commands on all instances at once:

# Run on 10 instances at a time, stop if 20% fail
$ aws ssm send-command \
    --targets Key=tag:Environment,Values=production \
    --document-name AWS-RunShellScript \
    --parameters 'commands=["yum update -y"]' \
    --max-concurrency "10" \
    --max-errors "20%"

Practical DevOps Use Cases

Use Case Command
Check disk space across fleet df -h on all instances
Deploy configuration file Write file content via shell script
Restart application systemctl restart myapp on tagged instances
Collect diagnostics top -bn1, netstat -tlnp, journalctl -u myapp --since "1 hour ago"
Security patching yum update -y --security with rate control
Rotate log files logrotate -f /etc/logrotate.d/myapp

Common Mistakes

Mistake Why It Hurts Fix
No rate control on production All instances restart at once Use --max-concurrency and --max-errors
Running commands by instance ID Manual, error-prone Use tags: Key=tag:Role,Values=web-server
Not checking command output Don’t know if it worked Always check with get-command-invocation
Long-running commands with no timeout Commands hang forever Set --timeout-seconds

Quick Reference

Task Command
Run command aws ssm send-command --targets Key=tag:KEY,Values=VAL --document-name AWS-RunShellScript --parameters 'commands=["CMD"]'
Get result aws ssm get-command-invocation --command-id ID --instance-id ID
List commands aws ssm list-commands --max-results 10
Cancel command aws ssm cancel-command --command-id ID
List documents aws ssm list-documents --filters Key=Owner,Values=Amazon

Next → Configuration & Secrets Exercises

Updated: