AWS Session Manager for EC2: Secure Access Without SSH
AWS Session Manager lets you connect to EC2 instances without SSH keys, without open port 22, and without a bastion host. Access is controlled by IAM, every session is tracked by CloudTrail, and the instance never needs an inbound firewall rule. It is the recommended way to access EC2 in production environments.
Session Manager is part of AWS Systems Manager, a broader service for managing fleets of EC2 instances and other managed nodes. You do not need to understand all of Systems Manager to use Session Manager. This page covers everything you need to connect to instances securely.
Session Manager in simple terms
With traditional SSH access, you hold a private key file, the instance holds the matching public key, and you connect through an open inbound port 22 in the security group. The key file is your proof of identity, and distributing it to teammates is a manual, error-prone process.
Session Manager works differently. There is no key file. The SSM Agent (a small background process running on the instance) maintains a persistent outbound connection to the AWS Systems Manager service. When you start a session, AWS verifies your IAM identity, checks whether you are authorized, and routes the interactive shell through that established channel. The connection flows outbound from the agent to AWS. Your session rides it in reverse. No inbound port is ever opened.
SSH is like a physical door key: you hand out copies, hope nobody loses one, and have no record of who entered. Session Manager is like an electronic access card system: your AWS credentials serve as the card, the system logs every entry, and revoking access is instant. Nothing to copy, nothing to lose, and every visit is on record.
Why teams use Session Manager instead of SSH
- No SSH key distribution. Access is granted and revoked by modifying IAM policies, not by copying key files to teammates or rotating authorized_keys files on every instance.
- No inbound port 22. The security group needs zero inbound rules. Eliminating port 22 removes one of the most-scanned attack surfaces on any public EC2 instance.
- IAM-based access control. Session access uses the same IAM model you already use for everything else in AWS: roles, policies, tag conditions, and environment-level scoping.
- Centralized auditing. CloudTrail records every session start and end automatically. With optional configuration, full session content streams to CloudWatch Logs or S3.
- Works for private instances. Instances in private subnets with no public IP can still be reached via Session Manager, as long as the agent can reach SSM endpoints through an internet gateway or through VPC interface endpoints.
SSH is still useful for file transfers with scp or rsync, legacy tooling that requires an SSH connection, or instances that cannot be made SSM-managed. For new workloads and production environments, Session Manager is the better default.
How Session Manager works
When you start a session, this is the sequence:
- You authenticate to AWS with your IAM identity: an IAM user, a role, or an SSO session.
- AWS Systems Manager checks whether your identity has permission to call
ssm:StartSessionon the target instance. - Systems Manager contacts the SSM Agent through the persistent outbound connection the agent maintains to the
ssmmessagesendpoint. - The agent opens an interactive shell on the instance and streams it back through the secure channel to your console or CLI.
- CloudTrail records the
StartSessionevent, including who initiated it, when, and from which IP.
The instance never accepts an inbound connection. The SSM Agent initiated the outbound tunnel; your session is routed back through it. This is why no inbound security group rule is required.
When to use Session Manager
- Admin access to EC2 instances in private subnets that have no public IP
- Production environments where you want zero inbound network exposure
- Developer access scoped by IAM role and environment tags
- Temporary troubleshooting sessions that need a full audit trail
- Port forwarding to private services (databases, internal APIs) without a VPN
- Any team that wants to stop managing SSH key pairs entirely
Session Manager vs SSH vs bastion host
| Factor | Session Manager | Direct SSH | SSH via bastion host |
|---|---|---|---|
| Inbound port 22 required | No | Yes (on target instance) | Yes (on bastion) |
| Key pair management | None (IAM controls access) | Per-instance key pairs | Key pairs on instance and bastion |
| Access control model | IAM policies and tag conditions | authorized_keys on each instance | authorized_keys on each instance |
| Session auditing | CloudTrail (automatic) + optional full content | None by default | None by default |
| Works for private instances | Yes, with SSM endpoints or VPC endpoints | Requires bastion or VPN | Yes |
| Infrastructure to maintain | SSM Agent on instance, IAM profile | Security group rule, key pair | Bastion instance, SG rules, key pairs |
| Best for | Production, private instances, compliance | Simple dev access, file transfers | Legacy setups before Session Manager |
Prerequisites
IAM access, Option A: Default Host Management Configuration
Default Host Management Configuration (DHMC) is an account- and region-level setting in AWS Systems Manager that automatically configures the required IAM permissions for EC2 instances using instance metadata credentials. When DHMC is enabled, instances do not need an explicit IAM instance profile attached for basic SSM connectivity.
Enable DHMC in the Systems Manager console under Fleet Manager > Account settings. This is the simplest path for setting up Session Manager across a new account or fleet.
IAM access, Option B: IAM instance profile on the instance
For per-instance control, attach an IAM role with the AmazonSSMManagedInstanceCore managed policy as an instance profile. This policy grants the SSM Agent permission to register with Systems Manager and participate in sessions.
You can attach the profile at launch time or add it to a running instance. If you add it to a running instance, restart the SSM Agent to pick up the new credentials.
SSM Agent
The SSM Agent is pre-installed on Amazon Linux 2023, Amazon Linux 2, Ubuntu 20.04+, and recent Windows Server AMIs. For other operating systems you install it manually. Check whether it is already running before trying to install it.
Network access to SSM endpoints
The SSM Agent needs outbound HTTPS access to three AWS service endpoints: ssm, ssmmessages, and ec2messages. For instances in public subnets with an internet gateway this works automatically. For instances in private subnets with no internet access, create interface VPC endpoints for all three services. See the PrivateLink overview for how to create interface endpoints.
Local CLI plugin (for CLI sessions only)
To start sessions from the AWS CLI, you also need the Session Manager plugin installed locally. It is a separate binary from the AWS CLI. Without it, aws ssm start-session fails with a cryptic error. Find install instructions for your operating system in the AWS documentation.
Once everything is set up, verify the instance is registered by running aws ssm describe-instance-information. If your instance appears in the output, you are ready to connect. If it does not appear, the agent is not running, the IAM profile is missing, or there is no network path to the SSM endpoints.
How to set it up
Step 1: Check the agent status on the instance
sudo systemctl status amazon-ssm-agentStep 2: Install the agent if it is not present
# Amazon Linux 2023
sudo dnf install -y amazon-ssm-agent
sudo systemctl enable --now amazon-ssm-agent
# Ubuntu (snap-based)
sudo snap install amazon-ssm-agent --classic
sudo systemctl enable --now snap.amazon-ssm-agent.amazon-ssm-agent.serviceStep 3: Create and attach the IAM instance profile (Option B)
# Create the IAM role
aws iam create-role \
--role-name EC2SSMRole \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
# Attach the SSM managed policy
aws iam attach-role-policy \
--role-name EC2SSMRole \
--policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
# Create the instance profile and add the role to it
aws iam create-instance-profile \
--instance-profile-name EC2SSMProfile
aws iam add-role-to-instance-profile \
--instance-profile-name EC2SSMProfile \
--role-name EC2SSMRole
# Attach the profile to a running instance
aws ec2 associate-iam-instance-profile \
--instance-id i-0abc12345def67890 \
--iam-instance-profile Name=EC2SSMProfileStep 4: Verify the instance appears as managed
aws ssm describe-instance-information \
--query "InstanceInformationList[?InstanceId=='i-0abc12345def67890']"If the instance does not appear, work through the three most common causes in order: agent not running, IAM profile missing, and no network path to SSM endpoints.
How to start a session
From the AWS Console
- Open the EC2 console and select your instance.
- Click Connect.
- Choose the Session Manager tab.
- Click Connect.
A browser-based terminal opens immediately. No local tools or plugins needed. This works from any machine that can reach the AWS console.
From the AWS CLI
Requires the AWS CLI and the Session Manager plugin installed locally.
# Start an interactive shell session
aws ssm start-session --target i-0abc12345def67890The session opens as ssm-user. You can sudo to other users as the instance’s sudoers configuration allows.
sh-4.2$ whoami
ssm-user
sh-4.2$ sudo su - ec2-userPort forwarding with Session Manager
Port forwarding lets you tunnel a local port on your machine through a managed EC2 instance to a private service. This is useful for reaching databases, web servers, or admin panels that live inside a VPC but are not exposed to the internet. No extra ports, no VPN required.
Forward to a port on the instance itself
# Forward local port 5432 to PostgreSQL running on the instance
aws ssm start-session \
--target i-0abc12345def67890 \
--document-name AWS-StartPortForwardingSession \
--parameters '{"portNumber":["5432"],"localPortNumber":["5432"]}'
# Now connect locally
psql -h localhost -p 5432 -U myuser -d mydbForward to a private endpoint via the instance
If the service you want to reach is not on the EC2 instance itself (for example, a private RDS cluster in the same VPC), use the AWS-StartPortForwardingSessionToRemoteHost document. This is the most practical pattern for connecting to RDS securely without a VPN or bastion host.
# Forward local port 5433 to a private RDS endpoint, via the managed instance
aws ssm start-session \
--target i-0abc12345def67890 \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{
"host":["mydb.cluster-abc123.us-east-1.rds.amazonaws.com"],
"portNumber":["5432"],
"localPortNumber":["5433"]
}'
# Connect to the RDS cluster as if it were local
psql -h localhost -p 5433 -U dbadmin -d mydbPort-forwarding sessions are not included in full session-content logs, even with CloudWatch or S3 logging configured. CloudTrail still records that the session was started. For a detailed access log of what happened on a database reached this way, rely on the database’s own access logging.
Controlling who can start sessions
ssm:StartSession is effectively shell access to an instance. Anyone who holds that permission has an interactive terminal. Treat it with the same care as SSH key access.
A minimal policy to allow starting and managing sessions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:StartSession",
"ssm:TerminateSession",
"ssm:ResumeSession",
"ssm:DescribeSessions",
"ssm:GetConnectionStatus",
"ssm:DescribeInstanceInformation"
],
"Resource": "*"
}
]
}Scope ssm:StartSession to specific environments using tag conditions. This follows the principle of least privilege and lets you give developers access to staging without touching production:
{
"Effect": "Allow",
"Action": "ssm:StartSession",
"Resource": "arn:aws:ec2:us-east-1:123456789012:instance/*",
"Condition": {
"StringEquals": {
"ssm:resourceTag/Environment": "staging"
}
}
}Operations engineers can have a separate policy scoped to Environment=production. See IAM policy structure for how conditions combine with resource ARNs.
Granting ssm:StartSession on Resource: ”*” without conditions gives shell access to every managed instance in the account. This is the Session Manager equivalent of handing out a master SSH key. Always scope to specific instances or use tag-based conditions before deploying to a shared environment.
Logging, auditing, and important caveats
Session Manager provides two levels of audit capability:
CloudTrail: automatic, no configuration needed
CloudTrail records every StartSession, TerminateSession, and ResumeSession API call, including who called it, from which IP address, and when. This is your baseline audit trail and works without any extra setup.
Full session content: optional, requires configuration
For compliance environments that need a record of every command typed and every output line, configure Session Manager preferences to stream session content to CloudWatch Logs or S3:
aws ssm update-document \
--name "SSM-SessionManagerRunShell" \
--content '{
"schemaVersion": "1.0",
"description": "Regional settings for Session Manager",
"sessionType": "Standard_Stream",
"inputs": {
"s3BucketName": "my-session-logs-bucket",
"s3KeyPrefix": "session-logs/",
"s3EncryptionEnabled": true,
"cloudWatchLogGroupName": "/aws/ssm/sessions",
"cloudWatchEncryptionEnabled": true,
"cloudWatchStreamingEnabled": true
}
}' \
--document-version "$LATEST"Full session-content logging applies to standard interactive shell sessions only. Port-forwarding sessions and sessions tunneled via SSH-over-Session-Manager do not produce command-level logs, even with logging fully configured. CloudTrail records that those sessions occurred, but not what happened inside them.
Auditability is one of the primary reasons teams choose Session Manager over SSH. SSH sessions produce no audit trail by default. Session Manager gives you CloudTrail coverage from day one, and full content logging when you need it.
Common mistakes
- Agent not running. The SSM Agent must be installed and actively running. If the instance never appears in
describe-instance-information, start here: runsystemctl status amazon-ssm-agenton the instance to confirm it is active. - Missing IAM instance profile. The agent can run but cannot register with Systems Manager without an IAM role attached. Attach a role with
AmazonSSMManagedInstanceCoreand restart the agent if you add the profile to a running instance. - No outbound access to SSM endpoints. Private subnets without internet access need interface VPC endpoints for
ssm,ssmmessages, andec2messages. Missing any one of them breaks connectivity silently — the agent will not register. - Forgetting the local CLI plugin. The AWS CLI alone is not enough for
aws ssm start-session. The Session Manager plugin is a separate binary. Without it, the command fails with an error about the plugin not being found. - Overly broad ssm:StartSession permissions. Granting
ssm:StartSessiononResource: ”*”gives shell access to every managed instance in the account. Scope to specific instances or tag conditions in any shared environment. - Assuming port-forwarding sessions are fully logged. Full session-content logging does not apply to port-forwarding sessions. If you are tunneling to a database for compliance reasons, the database’s own access logs become your audit record.
Summary
- Session Manager gives you interactive shell access to EC2 without SSH keys, without port 22, and without a bastion host.
- The SSM Agent on the instance maintains an outbound connection to Systems Manager. Your session travels through that tunnel, so no inbound security group rule is ever needed.
- Access is controlled by IAM. Grant or revoke access by changing policies, not by distributing or rotating key files.
- Prerequisites: SSM Agent running, an IAM instance profile with AmazonSSMManagedInstanceCore (or DHMC enabled at the account level), and network connectivity to SSM endpoints.
- Port forwarding lets you reach private services like RDS without a VPN. Use AWS-StartPortForwardingSessionToRemoteHost for services the instance can reach but you cannot.
- CloudTrail logs session events automatically. Full session-content logging requires additional configuration and does not apply to port-forwarding sessions.
- Treat ssm:StartSession with the same care as SSH access. Scope it to specific instances or tag conditions, not Resource: ”*”.
Frequently asked questions
What is AWS Session Manager?
Session Manager is a feature of AWS Systems Manager that lets you open an interactive shell session on an EC2 instance through the AWS console or CLI, with no SSH keys, no key pairs, and no inbound ports open in the security group. Access is controlled by IAM.
Do I need port 22 open to use Session Manager?
No. Session Manager does not use port 22. The SSM Agent on the instance makes an outbound connection to the Systems Manager service. Your security group needs no inbound rules for Session Manager to work.
Does Session Manager replace SSH completely?
For most use cases, yes. Session Manager is more secure and easier to audit. SSH is still useful when you need file transfer with scp or rsync, or when instances cannot be made SSM-managed due to missing IAM profiles, agents, or outbound access. For new instances, Session Manager is the recommended approach.
Are Session Manager sessions logged?
CloudTrail automatically records every session start and end. With additional configuration, full session content (every command typed and every output line) can be streamed to CloudWatch Logs or S3. One important caveat: port-forwarding sessions and SSH-tunneled sessions do not produce full session-content logs, even with logging enabled.
Can I use Session Manager to reach a private RDS database?
Yes. Port forwarding lets you tunnel a local port through a managed EC2 instance to a private endpoint like an RDS cluster. You connect to localhost on your machine while traffic travels through the Session Manager tunnel to the database. No VPN or bastion host is needed.