The attacker gains a gap in command-level visibility, not anonymous access. Session Manager does not record the SSH commands or their output, even where ordinary Session Manager shell sessions are logged. Session API calls remain auditable, and host telemetry can still reveal activity. This requires both existing Session Manager access and Secure Shell (SSH) credentials accepted by the instance; the tunnel does not replace either authorization check.[1][2][3]
SSH transport and session logging
Session Manager normally provides administrative access without requiring inbound management ports or a bastion host. With SSH, it transports an independently encrypted SSH connection inside its Transport Layer Security (TLS) channel. IAM authorizes the Session Manager connection, while the managed node’s SSH server separately authenticates the operating-system account and key.[1:1]
Session Manager can send shell commands and output to S3 or CloudWatch Logs, but it cannot provide this recording for SSH or port-forwarding sessions.[2:1] A missing SSH transcript therefore does not establish that someone disabled logging.
For a fleet that uses both shell and SSH access, requiring Session Manager does not guarantee command recording. Host SSH authentication logs and process telemetry can still show activity, provided they are collected. Without those records, CloudTrail can identify who requested the tunnel but cannot reconstruct commands run through it.
flowchart TB
A([AWS session requester]) -->|Session API request| S[Session Manager]
S -->|Management channel| N[Managed EC2 node]
U([SSH account]) -->|Separate authentication| N
S -->|API activity| C[CloudTrail]
N -->|Where collected| H[Host authentication and process telemetry]
class A,U principal
class S,N,C,H awsResource
Run the SSH through Session Manager proof of concept
This example assumes SSH is running on a managed EC2 instance, SSM Agent 2.3.672.0 or later is installed, and the local machine has the AWS CLI, Session Manager plugin, and a private key accepted for the target operating-system account. The AWS identity needs ssm:StartSession on both the instance and AWS-StartSSHSession document, plus ssmmessages:OpenDataChannel on its Session Manager sessions.[1:2]
The proxy command starts AWS-StartSSHSession for the instance ID and SSH port. The Session Manager plugin carries the SSH connection over the resulting data channel.
Add the Session Manager proxy to ~/.ssh/config:
Host i-* mi-*
ProxyCommand sh -c "aws ssm start-session --region '<region>' --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
Connect to the instance ID instead of an IP address:
ssh -i '<private-key>' '<os-user>@<instance-id>'
If the SSH server accepts the account and key, the resulting shell establishes host access through Session Manager. The commands demonstrate the transport and authentication path; they do not test logging behavior. AWS documentation, rather than the successful connection, establishes that Session Manager does not provide transcripts for SSH sessions.[2:2]
Detecting unexpected SSH sessions
Investigate both identities: the AWS principal that requested the session and the operating-system account used over SSH. A familiar host account does not establish that the AWS caller was an approved administrator.
Start with an AWS identity and node that do not normally appear together, or a session document outside the node’s approved administration policy. Use the session ID to find the owner, target, document, times, and status in Session Manager inventory. These fields are not guaranteed to appear in every CloudTrail event.[4]
| Event source | Event name | Detection value |
|---|---|---|
ssm.amazonaws.com |
StartSession |
Attributes a session request; inspect errors, target, and document where recorded. Acceptance is not proof of SSH authentication. |
ssm.amazonaws.com |
ResumeSession |
Identifies a request to resume an existing session; reconcile its session ID and current state. |
ssm.amazonaws.com |
TerminateSession |
Identifies a termination request; establish the resulting state rather than inferring it from the event name. |
These are management API events, not command transcripts. AWS documents their CloudTrail and EventBridge monitoring. Actions inside a session, including an ordinary shell exit, need not make a corresponding session API call, so the absence of TerminateSession does not establish that a connection remains active.[3:1][5]
A StartSession record can supply the AWS identity, node, document, and session ID. This trimmed example shows those fields, not SSH commands or proof of an SSH login. Failed requests can have null request and response fields.[6][7]
{
"eventTime": "<request time>",
"eventSource": "ssm.amazonaws.com",
"eventName": "StartSession",
"awsRegion": "<region>",
"userIdentity": { "arn": "<requesting identity ARN>" },
"requestParameters": {
"target": "<managed node ID>",
"documentName": "<session document name>"
},
"responseElements": { "sessionId": "<session ID>" }
}
Join events on session ID, account, and Region. Use the target and event time to search host records from session start through its recorded end, allowing for clock differences and delayed delivery. If no end state is available, check current Session Manager inventory instead of assuming the session closed.
A returned session ID proves only that AWS allocated a session; Connected proves that the Session Manager transport connected. Neither proves SSH authentication.[8][4:1] Host authentication records confirm the login, while process and application telemetry show subsequent activity. When shared host accounts or concurrent sessions prevent a unique match, report candidate attribution rather than assigning the activity to one AWS requester. Tune the correlation around approved requester-node-document combinations, operating-system accounts, and maintenance periods.
Restricting access and ending active sessions
- Scope
ssm:StartSessionto approved managed nodes and session documents instead of broad resource grants. AWS documents explicit denial of the SSH session document where SSH-over-Session-Manager access is unnecessary. Review effective permissions across attached policies, not only one allowlist.[9][1:3] - Protect customer-managed session documents and their default versions. Restrict
ssm:CreateDocument,ssm:UpdateDocument, andssm:UpdateDocumentDefaultVersionso an approved document name is not treated as permanently approved behavior.[10] - Restrict SSH accounts and credentials, limit operating-system privileges, and collect host authentication and execution evidence. Session Manager transcript settings do not cover SSH, so systems that retain SSH access need host-side telemetry.
- Give incident responders authority to inspect and terminate affected sessions, not just their own. AWS’s end-user policy examples commonly scope termination to the caller’s sessions, which is insufficient for organization-wide response.[9:1]
During containment, restrict the compromised principal’s ability to create or resume sessions and revoke compromised SSH credentials separately from closing the active transport. TerminateSession permanently ends the Session Manager session, closes its data connection, and prevents resumption of that session ID. Confirm Terminated rather than Terminating state and examine the node for resulting changes; closing the connection does not undo earlier commands or remediate the instance.[11][4:2]
References
AWS Systems Manager User Guide, Allow and control permissions for SSH connections through Session Manager. ↩︎ ↩︎ ↩︎ ↩︎
AWS Systems Manager User Guide, Enabling and disabling session logging. ↩︎ ↩︎ ↩︎
AWS Systems Manager User Guide, Logging AWS Systems Manager API calls with CloudTrail. ↩︎ ↩︎
AWS Systems Manager User Guide, Logging session activity. ↩︎
ManagedKube, SSM Session Manager: user login sessions, documented CloudTrail record for a custom shell-session document. ↩︎
detection.wiki, AWS Systems Manager: StartSession. ↩︎
AWS Systems Manager API Reference, StartSession. ↩︎
AWS Systems Manager User Guide, Additional sample IAM policies for Session Manager. ↩︎ ↩︎
AWS Service Authorization Reference, Actions, resources, and condition keys for AWS Systems Manager. ↩︎
AWS Systems Manager API Reference, TerminateSession. ↩︎