Home / AWS

AWSHow-toIntermediate

Transformation: retire bastion hosts and open SSH/RDP ports with SSM Session Manager

Replace jump boxes and inbound port 22/3389 with AWS Systems Manager Session Manager. Set up instance roles and VPC endpoints, enable session logging, use port forwarding for databases and RDP, and close the old ports.

Deepak Bhardwaj2 min read

Applies toAWS Systems Manager Session Manager, SSM Agent, Session Manager plugin for AWS CLI, Linux and Windows EC2, on-prem hybrid nodes

Why

Bastions are internet-facing servers with SSH keys shared among a team. Session Manager gives IAM-controlled access with no inbound ports, full session logs and no keys to rotate.

1. Prerequisites on instances

  • SSM Agent installed and running (pre-installed on Amazon Linux, recent Ubuntu and Windows AMIs).
  • Instance profile with AmazonSSMManagedInstanceCore.
  • Network path to SSM: NAT gateway, or VPC interface endpoints for ssm, ssmmessages and ec2messages in private subnets.
for s in ssm ssmmessages ec2messages; do
  aws ec2 create-vpc-endpoint --vpc-id vpc-0123 --vpc-endpoint-type Interface \
    --service-name com.amazonaws.eu-west-1.$s --subnet-ids subnet-a subnet-b \
    --security-group-ids sg-endpoints --private-dns-enabled
done
aws ssm describe-instance-information --query "InstanceInformationList[].[InstanceId,PingStatus,PlatformName]" --output table

Or enable Default Host Management Configuration so instances get SSM permissions without editing every instance profile.

2. Logging and encryption

Session Manager preferences: stream session logs to CloudWatch Logs and/or S3, encrypt with a KMS key, and set an idle timeout.

3. Control who can connect

{
  "Effect": "Allow",
  "Action": "ssm:StartSession",
  "Resource": [
    "arn:aws:ec2:eu-west-1:111122223333:instance/*",
    "arn:aws:ssm:eu-west-1::document/AWS-StartPortForwardingSessionToRemoteHost"
  ],
  "Condition": { "StringEquals": { "ssm:resourceTag/team": "${aws:PrincipalTag/team}" } }
}

Tag-based conditions let teams reach only their own instances.

4. Daily use

Shell:

aws ssm start-session --target i-0abc123

SSH and SCP over Session Manager (keeps existing tooling):

# ~/.ssh/config
Host i-* mi-*
  ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

Port forwarding to a private RDS database through an instance:

aws ssm start-session --target i-0abc123 \
  --document-name AWS-StartPortForwardingSessionToRemoteHost \
  --parameters '{"host":["orders.cluster-abc.eu-west-1.rds.amazonaws.com"],"portNumber":["5432"],"localPortNumber":["15432"]}'
psql -h localhost -p 15432 -U app orders

RDP to Windows: forward 3389 with AWS-StartPortForwardingSession and connect to localhost:13389, or use Fleet Manager's browser-based RDP.

5. Close the doors

  1. Confirm everyone has used Session Manager successfully for a couple of weeks.
  2. Remove inbound 22/3389 rules from all security groups:
aws ec2 describe-security-groups --filters Name=ip-permission.from-port,Values=22 \
  --query "SecurityGroups[].[GroupId,GroupName]" --output table
  1. Terminate bastion hosts; remove their Elastic IPs and key pairs.
  2. Add an AWS Config rule (restricted-ssh) to catch new open SSH rules.

Checklist

  • SSM Agent and permissions on every instance; endpoints in private subnets
  • Session logging to CloudWatch/S3 with KMS
  • IAM policies scoped by tags
  • Port forwarding documented for DB and RDP access
  • Inbound 22/3389 removed; bastions terminated