SSH to EC2 Through AWS Systems Manager Session Manager

AWS Systems Manager (SSM) Session Manager can proxy full SSH sessions — including TCP port forwarding — to EC2 instances over its encrypted control channel. The security payoff: the instance needs no inbound ports at all. The SSM agent dials out to the SSM service, so security groups and NACLs can deny all ingress while operators (and, if IAM is loose, attackers) still get an interactive shell. SSH runs inside the SSM tunnel, adding IAM-mediated access control and CloudTrail/Session-Manager audit logging on top of normal sshd auth.

Prerequisites

  1. Target instance runs the SSM agent (v2.3.672.0 or later for SSH sessions) with an instance profile allowing SSM core actions
  2. Target runs sshd — but it does not need to be network-exposed; fully firewalled hosts work
  3. Caller holds an SSH key for a local user (e.g. ec2-user) — SSM replaces the transport, not SSH authentication
  4. Local machine has the AWS CLI plus the Session Manager plugin (v1.1.23.0+)
  5. IAM permission ssm:StartSession on both the instance ARN and the AWS-StartSSHSession document ARN:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "ssm:StartSession",
            "Resource": [
                "arn:aws:ec2:$REGION:$ACCOUNT_ID:instance/$INSTANCE_ID",
                "arn:aws:ssm:*:*:document/AWS-StartSSHSession"
            ]
        }
    ]
}

In practice, also grant ssm:TerminateSession / ssm:ResumeSession scoped to the caller’s own session ARNs, and scope Resource to tagged instances rather than *.

The ProxyCommand pattern

AWS documents an ~/.ssh/config stanza that transparently tunnels SSH for instance-ID hostnames:

# SSH over Session Manager
Host i-* mi-*
    ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
    User ec2-user

Or one-shot on the command line:

ssh -o ProxyCommand="sh -c \"aws --region $REGION ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'\"" ec2-user@$TARGET_INSTANCE_ID

Everything that speaks SSH rides along: scp, sftp, ssh -L/-R port forwards, VS Code Remote-SSH. Port forwarding without SSH is also available natively via aws ssm start-session --document-name AWS-StartPortForwardingSession.

Security considerations

  • Blast radius shifts to IAM: compromise of AWS credentials with ssm:StartSession on * is equivalent to shell access across the fleet — treat that action like iam:PassRole in reviews. MITRE cloud matrix maps this under valid-account remote-service usage.
  • Audit: enable session logging to S3/CloudWatch; every StartSession is in CloudTrail. Compare with the opacity of direct SSH to an open 22.
  • Endpoint exposure: agents in private subnets need either NAT or VPC interface endpoints for ssm, ssmmessages, and ec2messages — a misconfigured endpoint policy is a common breakage (and a control point).
  • For containers rather than instance OS shells, the sibling mechanism is ECS Exec, built on the same SSM messages channel.

Sources

Related: aws-ecs-exec, aws-sigv4-api-flooding, windows-remote-management