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.

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.
When SSH is still the right tool

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:

  1. You authenticate to AWS with your IAM identity: an IAM user, a role, or an SSO session.
  2. AWS Systems Manager checks whether your identity has permission to call ssm:StartSession on the target instance.
  3. Systems Manager contacts the SSM Agent through the persistent outbound connection the agent maintains to the ssmmessages endpoint.
  4. The agent opens an interactive shell on the instance and streams it back through the secure channel to your console or CLI.
  5. CloudTrail records the StartSession event, 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

FactorSession ManagerDirect SSHSSH via bastion host
Inbound port 22 requiredNoYes (on target instance)Yes (on bastion)
Key pair managementNone (IAM controls access)Per-instance key pairsKey pairs on instance and bastion
Access control modelIAM policies and tag conditionsauthorized_keys on each instanceauthorized_keys on each instance
Session auditingCloudTrail (automatic) + optional full contentNone by defaultNone by default
Works for private instancesYes, with SSM endpoints or VPC endpointsRequires bastion or VPNYes
Infrastructure to maintainSSM Agent on instance, IAM profileSecurity group rule, key pairBastion instance, SG rules, key pairs
Best forProduction, private instances, complianceSimple dev access, file transfersLegacy 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.

Quick check

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-agent

Step 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.service

Step 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=EC2SSMProfile

Step 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

  1. Open the EC2 console and select your instance.
  2. Click Connect.
  3. Choose the Session Manager tab.
  4. 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-0abc12345def67890

The 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-user

Port 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 mydb

Forward 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 mydb
Logging caveat for port forwarding

Port-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.

Do not do this in production

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"
Port forwarding sessions are not fully logged

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

  1. Agent not running. The SSM Agent must be installed and actively running. If the instance never appears in describe-instance-information, start here: run systemctl status amazon-ssm-agent on the instance to confirm it is active.
  2. Missing IAM instance profile. The agent can run but cannot register with Systems Manager without an IAM role attached. Attach a role with AmazonSSMManagedInstanceCore and restart the agent if you add the profile to a running instance.
  3. No outbound access to SSM endpoints. Private subnets without internet access need interface VPC endpoints for ssm, ssmmessages, and ec2messages. Missing any one of them breaks connectivity silently — the agent will not register.
  4. 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.
  5. Overly broad ssm:StartSession permissions. Granting ssm:StartSession on Resource: ”*” gives shell access to every managed instance in the account. Scope to specific instances or tag conditions in any shared environment.
  6. 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.

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.

Last verified: 1 April 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.