Every Security Specialty candidate knows the slogan: close port 22 and delete the bastion. The exam, however, is not satisfied with the slogan. It wants you to know which of AWS’s four administrative-access paths closes the port, which one still needs an SSH key, which one records every keystroke, which one silently records nothing, and which IAM condition key makes each path least-privilege. Those details are exactly what the current exam guide asks for. Skill 3.2.5 of the AWS Certified Security - Specialty (SCS-C03) guide reads, verbatim: “Configure secure administrative access to compute resources (for example, Systems Manager Session Manager, EC2 Instance Connect).” Amazon EC2 is listed in scope “including EC2 Image Builder, EC2 Instance Connect”, and AWS Systems Manager is in scope under Management and Governance.
A quick note on exam versions, because it affects how you should read older material: AWS retired SCS-C02 in December 2025 and the live exam is SCS-C03. The compute-hardening content carried over almost unchanged (the SCS-C02 guide phrased the same idea as “secure remote access methods, for example SSH and RDP over Systems Manager Session Manager”), so everything in this article applies to both blueprints. If you are still orienting yourself, the SCS-C02 vs SCS-C03 comparison and the full Security Specialty exam guide cover the domain-level changes.
This article is the deep dive the infrastructure security domain guide deliberately skips. It assumes you already know what a security group is and focuses on the mechanics the exam actually tests: how each access path authenticates, what network state it needs, what it logs, which condition keys scope it, and the traps AWS likes to hide in a scenario.
The threat model behind “no inbound port 22”
Start with why the exam cares. A classic administrative path to a Linux instance is an SSH daemon listening on port 22, reachable through a security group rule, authenticated by a long-lived key pair that lives on laptops and in CI systems. Every element of that sentence is an attack surface:
- The open port is reachable by anyone who can route to it. Even when the source is restricted to a corporate CIDR, the daemon itself is exposed to protocol-level vulnerabilities and brute-force noise.
- The long-lived key is a shared secret. It is copied, forgotten, and rarely rotated. When an engineer leaves, nobody is sure which instances still trust their key.
- The bastion host that fronts private instances is a server you have to patch, harden, monitor and scale. It also concentrates risk: compromise the bastion and you have a foothold in every subnet it can reach.
- The audit trail is whatever the instance’s own logging captures. If the attacker has root, they can edit it.
The four AWS mechanisms below each remove some of those elements. The exam tests whether you know which elements each one removes, because the right answer depends on which element the scenario complains about.
The four access paths at a glance
| Access path | Inbound security-group rule needed? | Public IP needed? | SSH key pair needed? | What authenticates you | Session content logged by AWS? | Protocol seen by the instance |
|---|---|---|---|---|---|---|
| Session Manager | No (agent connects outbound on 443) | No | No | IAM identity, checked by the Session Manager service | Yes for standard shell sessions (S3, CloudWatch Logs, CloudTrail for API calls); no for SSH and port-forwarding sessions | Agent-mediated shell, not SSH |
| EC2 Instance Connect (public path) | Yes, port 22 from your IP or the AWS-managed EIC prefix list | Yes (or private connectivity you built yourself) | No persistent key; a one-time key is pushed for 60 seconds | IAM authorizes the key push (ec2-instance-connect:SendSSHPublicKey), then normal SSH | API call in CloudTrail only; session content not recorded | SSH |
| EC2 Instance Connect Endpoint | Yes, but only from the endpoint’s security group or VPC range | No | Optional: your own key with any AMI, or the EIC one-time key push | IAM authorizes the tunnel (ec2-instance-connect:OpenTunnel), then SSH or RDP | OpenTunnel calls (success and failure) in CloudTrail; session content not recorded | SSH or RDP over a TCP tunnel |
| Bastion host | Yes, on the bastion (22) and on targets (22 from the bastion’s security group) | Yes, on the bastion | Yes | Whatever you configure on the bastion | Whatever you configure on the bastion | SSH hop |
A fifth tool, the EC2 Serial Console, is not an administrative-access path at all. It is an out-of-band break-glass console that bypasses the VPC, and it has its own section below because the exam uses it as a distractor.
Session Manager internals
How a session actually flows
AWS Systems Manager Session Manager gives you an interactive shell or a tunnel to a managed node through the SSM Agent’s outbound connection. The sequence the exam expects you to be able to narrate:
- The user calls
ssm:StartSessionfrom the console, the EC2 console, or the AWS CLI with the Session Manager plugin installed. - The service authenticates the IAM identity, evaluates the IAM policy, checks the session preferences (timeouts, logging, encryption, Run As) and sends a message to the SSM Agent on the node.
- The agent, which already maintains an outbound HTTPS connection, opens a bidirectional data channel to the
ssmmessagesendpoint. Traffic between client and node is TLS-encrypted and the create-connection request is SigV4-signed. - Commands and output stream over that channel. Nothing listens on the instance, so no inbound rule is required and the instance does not need a public IP.
The prerequisites that fall out of this design are the ones scenarios probe:
- SSM Agent version 2.3.68.0 or later for basic sessions; 2.3.539.0 or later for KMS session encryption; 3.0.222.0 or later for port forwarding and SSH sessions; 3.0.284.0 or later for streaming logs to CloudWatch Logs; 3.1.1374.0 or later for port forwarding to a remote host.
- Outbound HTTPS (443) from the node to
ssm.<region>.amazonaws.com,ssmmessages.<region>.amazonaws.comandec2messages.<region>.amazonaws.com. For instances with no internet route, create interface VPC endpoints for those three services. “Private subnet, no NAT, must use Session Manager” is answered by interface endpoints, not by an internet gateway. - Instance permissions. Either an instance profile carrying
AmazonSSMManagedInstanceCore(plus S3, CloudWatch Logs and KMS permissions if you enable those features), or the account-level Default Host Management Configuration, which lets Systems Manager manage every EC2 instance in a Region through theAWSSystemsManagerDefaultEC2InstanceManagementRolewithout an instance profile. Default Host Management Configuration requires IMDSv2 and SSM Agent 3.2.582.0 or later, and it is activated per Region. The IMDSv2 dependency is a nice bridge to the IMDSv2 deep dive: the agent reads its role credentials from instance metadata, so disabling IMDS breaks Session Manager.
The ssm-user account and Run As
Starting with SSM Agent 2.3.50.0, the agent creates a local account called ssm-user and gives it root or administrator rights: it is added to /etc/sudoers.d/ssm-agent-users on Linux and macOS (ssm-user ALL=(ALL) NOPASSWD:ALL) and to the Administrators group on Windows. On agent 2.3.612.0 and later, the account is created the first time a session starts on the node. By default, every session runs as this account.
The exam tests two ways to change that:
- Remove sudo from
ssm-user. Overwrite the sudoers file (Run Command withAWS-RunShellScriptis the documented way:echo "#User rules for ssm-user" > /etc/sudoers.d/ssm-agent-users). Sessions still work, but the operator is no longer root. - Turn on Run As support (Linux and macOS only). Session Manager then authenticates sessions as a named OS user instead of
ssm-user. The lookup order is: first theSSMSessionRunAstag on the IAM user or role, then the OS user name in the account’s Session Manager preferences. If the OS account does not exist on the node, the session fails. Run As does not fall back tossm-user, and it does not support therootaccount. The recommended pattern is tagging IAM entities so different teams land in different OS users, which also makes OS-level audit logs attributable.
Session preferences the exam quotes numbers from
| Preference | Default | Range or behaviour | Why it matters on the exam |
|---|---|---|---|
| Idle session timeout | 20 minutes | 1 to 60 minutes. Keyboard input, window resizes and reconnects reset the timer | ”Sessions left open overnight” questions. Note that activity, not just commands, resets the timer |
| Maximum session duration | None | 1 to 1,440 minutes (24 hours) | “Hard limit regardless of activity” questions. Pair it with idle timeout |
| KMS encryption of session data | Off | Symmetric KMS key; adds a layer on top of TLS. The user needs kms:GenerateDataKey; the node needs kms:Decrypt. Supported for Standard_Stream, InteractiveCommands and NonInteractiveCommands session types | Missing either permission makes sessions fail to start. Also required to reset passwords through Fleet Manager |
| Run As | Off | SSMSessionRunAs tag, then account-level user name; Linux/macOS only; no root; no fallback | Attributable OS identity and least privilege |
| Shell profiles | None | Commands, environment variables and working directory run at session start | Enforce a restricted shell, umask, or banner |
| S3 logging | Off | Per-session log to a bucket, optionally KMS-encrypted; the node needs s3:PutObject and KMS rights | Archival of what operators typed and saw |
| CloudWatch Logs logging | Off | Continuous streaming (agent 3.0.284.0 or later) or upload at session end | Near-real-time detection on operator commands |
Two logging details are heavily tested. First, logging is not available for sessions that use SSH or port forwarding, because Session Manager is only a tunnel for that traffic; the content is encrypted end to end inside the tunnel. A question that says “the security team needs a transcript of everything the operator ran” is answered by a standard shell session with S3 or CloudWatch logging, and is wrong for the SSH-over-Session-Manager pattern. Second, session logs capture both input and output, so AWS documents stty -echo; read passwd; stty echo; to keep secrets out of the transcript, and recommends the screen utility be installed on Linux nodes to avoid truncated logs. CloudTrail separately records the StartSession, ResumeSession and TerminateSession API calls, and EventBridge can fire on session start and end for SNS notifications or automated responses.
Session types and documents
Every session runs a Session document. The account-level preferences live in a document called SSM-SessionManagerRunShell (session type Standard_Stream), which is why user policies reference that document ARN. The other AWS-provided documents define the non-shell session types:
# Interactive shell (uses SSM-SessionManagerRunShell preferences)
aws ssm start-session --target i-0abc123def456
# Local port 56789 -> port 80 on the instance
aws ssm start-session --target i-0abc123def456 \
--document-name AWS-StartPortForwardingSession \
--parameters '{"portNumber":["80"],"localPortNumber":["56789"]}'
# Tunnel through the instance to a remote host that is NOT an SSM node (RDS, AD, etc.)
aws ssm start-session --target i-0abc123def456 \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"host":["mydb.cluster-xyz.us-east-1.rds.amazonaws.com"],"portNumber":["3306"],"localPortNumber":["3306"]}'
The remote-host variant is the exam’s answer to “developers need to reach a private RDS instance from laptops without a bastion or VPN”. The EC2 instance acts as the tunnel endpoint, and the remote host needs no agent at all.
SSH over Session Manager uses the AWS-StartSSHSession document through an SSH ProxyCommand:
# ~/.ssh/config
Host i-* mi-*
ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
User ec2-user
Three facts about this pattern are exam gold: you still need a key pair that the instance trusts (you connect as the key’s OS user, not as ssm-user), the instance’s port 22 stays closed in the security group because the tunnel terminates inside the agent, and no session logging happens. It gives you SCP file copies and native SSH tooling at the cost of the transcript.
Finally, InteractiveCommands and NonInteractiveCommands session types let you write a custom Session document that runs a single command (for example, tailing a specific log file). This is how you grant an operator “run exactly this and nothing else” access.
Least-privilege IAM for Session Manager
The user-side policy has four moving parts. AWS’s quickstart end-user policy is the template:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ssm:StartSession",
"Resource": [
"arn:aws:ec2:us-east-1:111122223333:instance/*",
"arn:aws:ssm:us-east-1:111122223333:document/SSM-SessionManagerRunShell"
],
"Condition": {
"StringLike": { "ssm:resourceTag/Environment": ["prod-web"] }
}
},
{
"Effect": "Allow",
"Action": "ssmmessages:OpenDataChannel",
"Resource": "arn:aws:ssm:*:*:session/${aws:userid}-*"
},
{
"Effect": "Allow",
"Action": ["ssm:TerminateSession", "ssm:ResumeSession"],
"Resource": "arn:aws:ssm:*:*:session/${aws:userid}-*"
},
{
"Effect": "Allow",
"Action": ["ssm:DescribeSessions", "ssm:GetConnectionStatus", "ssm:DescribeInstanceProperties", "ec2:DescribeInstances"],
"Resource": "*"
}
]
}
Read it the way the exam reads it:
ssm:StartSessionon instance ARNs withssm:resourceTag/<key>scopes which nodes a user may reach. Multiple tag conditions are ANDed, so “both tags must be present” is natural.ssm:StartSessionon the document ARN scopes which session type. GrantingSSM-SessionManagerRunShellbut notAWS-StartPortForwardingSessionorAWS-StartSSHSessionforbids tunnels and SSH. An explicitDenyonarn:aws:ssm:*:*:document/AWS-StartSSHSessionis the documented way to block SSH-over-Session-Manager for a group. Because the CLI can also start a session with no document argument, AWS provides thessm:SessionDocumentAccessCheckcondition key; setting it totrueonssm:StartSessionforces the document permission check even when the caller omits--document-name.- Session ARNs built from
${aws:userid}-*let a user resume or end only their own sessions. For federated identities, AWS also stamps every session with the system tagsaws:ssmmessages:session-idandaws:ssmmessages:target-id, which you can match in assm:resourceTagcondition onssm:TerminateSession. ssm:SendCommandsneaks into the EC2-console variant of the policy only because the console may need to update an old agent through Run Command first.
The administrator-side policy adds ssm:CreateDocument, ssm:UpdateDocument and ssm:GetDocument on SSM-SessionManagerRunShell, because editing preferences is editing that document. Locking preferences down means denying those actions to everyone except the security team. The same principle covers Default Host Management Configuration: AWS publishes an SCP that denies ssm:UpdateServiceSetting, ssm:ResetServiceSetting and iam:PassRole on the default role to anyone without an administrator principal tag.
For a broader treatment of the operational side of Systems Manager (Run Command, Patch Manager, Fleet Manager), the Systems Manager operations guide covers what this article skips.
EC2 Instance Connect: IAM-authorized SSH, 60 seconds at a time
EC2 Instance Connect (EIC) keeps SSH as the protocol but replaces the long-lived key with a one-time key authorized by IAM. The mechanism:
- The user calls
ec2-instance-connect:SendSSHPublicKeywith a freshly generated public key, an instance ID and an OS user name. The console does this for you and generates the key pair in the browser; with the CLI you can runaws ec2-instance-connect ssh --instance-id i-..., or push the key yourself and use any SSH client. - The service writes the public key into the instance’s metadata, where it remains for 60 seconds.
- On the instance, the EIC package has configured
sshdwithAuthorizedKeysCommand /opt/aws/bin/eic_run_authorized_keys %u %fandAuthorizedKeysCommandUser ec2-instance-connect. When the SSH connection arrives,sshdruns that command, which fetches the key from metadata and authenticates the session. - Every
SendSSHPublicKeycall is recorded in CloudTrail, so you can audit who connected to which instance as which user, even though SSH itself is not a logged session.
What the exam wants you to notice:
- The security group still needs port 22 open. For CLI or SSH-client use, the source is your IP range. For the browser-based client, the connection originates from the EC2 Instance Connect service, so the inbound rule must allow the AWS-managed prefix list
com.amazonaws.<region>.ec2-instance-connect(and theipv6variant for IPv6). A scenario where “the console says connection failed but SSH from a laptop works” is a missing prefix-list rule. - The instance needs a public IPv4 or IPv6 address and an internet route, unless you have built private connectivity (VPN, Direct Connect, peering) or you use EC2 Instance Connect Endpoint.
- The package must be installed. It is preinstalled on AL2023 standard AMIs, Amazon Linux 2 (2.0.20190618 or later), Ubuntu 20.04 or later, and recent macOS images; it can be installed on CentOS Stream 8/9, RHEL 8/9, older Ubuntu, and the AL2023 minimal and ECS-optimized AMIs. If
sshdalready has a customAuthorizedKeysCommand, the installer leaves it alone and EIC does not work. - It is Linux and macOS only. Windows instances use RDP, which EIC does not do (but EC2 Instance Connect Endpoint does).
- IAM scoping uses
ec2:osuserto pin the OS user (for exampleec2-userorubuntu), instance ARNs oraws:ResourceTagconditions to pin instances, andec2:DescribeInstancesfor console use (ec2:DescribeVpcstoo when connecting over IPv6). Without a resource restriction, anyone withSendSSHPublicKeycan reach every instance in the account. - No additional cost, available in all commercial Regions, not supported in Local Zones.
EIC fixes the key-management problem and nothing else: the port is still open, the daemon is still exposed, and the session content is not recorded. It is also the AWS-recommended way to harden a bastion if you must keep one, because the bastion no longer holds any static keys.
EC2 Instance Connect Endpoint: the managed bastion
EC2 Instance Connect Endpoint (EICE) is what AWS built so you can reach private instances over SSH or RDP without a public IP, without an internet gateway and without a bastion. The docs describe it as an identity-aware TCP proxy: the EC2 Instance Connect Endpoint Service establishes a private tunnel from your computer to the endpoint using your IAM credentials, authenticates and authorizes the request, and only then forwards TCP into your VPC.
Mechanically:
- You create one endpoint in a subnet. AWS provisions a network interface there (through a service-linked role) which becomes the entry point. Any instance in any subnet whose route table allows traffic from the endpoint’s subnet is reachable.
- The client runs
aws ec2-instance-connect ssh --instance-id i-...(which combines the tunnel with an EIC key push), oraws ec2-instance-connect open-tunnel --instance-id i-... --remote-port 22 --local-port 2222and points any SSH or RDP client at the local port. If you bring your own key pair, any Linux AMI works; otherwise the instance needs the EIC package for the one-time key. - Windows instances are reachable on 3389 the same way, which is the clean answer to “RDP to a private Windows instance without a bastion”.
The IAM model is the richest of the four paths and the exam knows it:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "TunnelOnlyToSSHInAppSubnet",
"Effect": "Allow",
"Action": "ec2-instance-connect:OpenTunnel",
"Resource": "arn:aws:ec2:us-east-1:111122223333:instance-connect-endpoint/eice-0123456789abcdef0",
"Condition": {
"NumericEquals": { "ec2-instance-connect:remotePort": "22" },
"NumericLessThanEquals": { "ec2-instance-connect:maxTunnelDuration": "1800" },
"IpAddress": {
"ec2-instance-connect:privateIpAddress": "10.0.1.0/24",
"aws:SourceIp": "203.0.113.0/24"
}
}
},
{
"Sid": "OneTimeKey",
"Effect": "Allow",
"Action": "ec2-instance-connect:SendSSHPublicKey",
"Resource": "arn:aws:ec2:us-east-1:111122223333:instance/*",
"Condition": { "StringEquals": { "ec2:osuser": "ec2-user" } }
},
{
"Sid": "Describe",
"Effect": "Allow",
"Action": ["ec2:DescribeInstances", "ec2:DescribeInstanceConnectEndpoints"],
"Resource": "*"
}
]
}
The three endpoint-specific condition keys:
ec2-instance-connect:remotePortrestricts the destination port. Allow 22 for Linux fleets, 3389 for Windows fleets, nothing else.ec2-instance-connect:privateIpAddressrestricts the destination to a single IP or a CIDR, which is how you keep a team inside its own subnet.ec2-instance-connect:maxTunnelDurationcaps the tunnel at 1 to 3,600 seconds (the default and maximum is one hour). If the policy sets a value below 3,600, the caller must pass--max-tunnel-durationon the command line. Note the trap: the tunnel’s lifetime is independent of the caller’s credentials. Expired IAM credentials do not cut the tunnel; only the duration does.
Creation permissions are separate (ec2:CreateInstanceConnectEndpoint, ec2:CreateNetworkInterface, ec2:CreateTags, ec2:ModifyInstanceConnectEndpoint, iam:CreateServiceLinkedRole) and can be scoped by ec2:SubnetID, so a platform team can own endpoints while application teams only get OpenTunnel.
Security groups and client IP preservation
The endpoint has its own security group. Inbound rules on it are irrelevant (traffic arrives from the EICE service regardless), so who may connect is purely an IAM question. What matters is:
- The endpoint’s security group must allow outbound to the targets: reference the instance security group, or allow the VPC CIDR on port 22/3389.
- The instance’s security group must allow inbound from the endpoint: referencing the endpoint’s security group works whether client IP preservation is on or off, and is the recommended pattern because it means “only the endpoint can SSH here”.
- Client IP preservation decides what source address the instance sees. Off (the default), the source is the endpoint network interface’s private IP, so an IP-based inbound rule must allow the VPC range. On, the source is the client’s real public IP, so the inbound rule must allow the client range; the instance must be in the same VPC as the endpoint; it works only on IPv4 endpoints (not dual-stack or IPv6); it fails on a short list of legacy instance types (C1, CG1, CG2, G1, HI1, M1, M2, M3, T1); and it is not supported through a transit gateway. The exam uses this as a troubleshooting question: “connections fail only after enabling client IP preservation” points at one of those constraints or at an inbound rule that still allows only the VPC CIDR.
Quotas and limits that show up in questions
| Limit | Value |
|---|---|
| Endpoints per VPC and per subnet | 1 (delete and recreate to move it to another AZ) |
| Concurrent connections per endpoint | 20 |
| Maximum tunnel duration | 3,600 seconds, lower by IAM condition |
| Traffic profile | Management traffic only; high-volume transfers are throttled |
| Address families | IPv4, IPv6 or dual-stack; the endpoint’s type must match the instance’s address |
| Pricing | No charge for the endpoint; standard cross-AZ data transfer applies when the target is in another AZ |
| Logging | OpenTunnel success and failure in CloudTrail; no session content |
Compare the two Instance Connect siblings carefully: EIC (public) authorizes a key; EICE authorizes a TCP tunnel. EIC needs a public address and an open port from your IP; EICE needs neither. Both leave SSH as the protocol and neither records what you typed. When a scenario needs a transcript, both lose to Session Manager.
When a bastion host is still the answer
The exam rarely rewards building a bastion, but it does test whether you know how to run one correctly when a constraint forces it (a third-party appliance that cannot run SSM Agent, a compliance rule mandating a jump host, or tooling that depends on raw SSH with agent forwarding). The hardening checklist AWS expects:
- Place the bastion in a public subnet with its own security group allowing 22 only from the corporate range, and make every private instance’s security group allow 22 only from the bastion’s security group (security-group referencing, never the subnet CIDR).
- Prefer
ProxyJump(ssh -J bastion target) over SSH agent forwarding, so the private key never leaves the laptop and a compromised bastion cannot reuse the agent. - Put EC2 Instance Connect on the bastion so it holds no static keys, and scope
SendSSHPublicKeyto the bastion’s instance ARN. - Keep it stateless and disposable: an Auto Scaling group of one, built from a hardened AMI (EC2 Image Builder, Skill 3.2.1), patched by Patch Manager, with no application data on it.
- Capture OS-level session logs (for example
scriptorauditd) to CloudWatch Logs, and alarm on new SSH logins.
Then recognize that EC2 Instance Connect Endpoint is the managed replacement for exactly this design, and Session Manager removes the need for SSH at all. If the scenario does not state a constraint that forces SSH, the bastion is the distractor.
EC2 Serial Console: break-glass, not administration
The EC2 Serial Console attaches you to an instance’s virtual serial port, independent of networking. It exists for the moment an instance will not boot, has a broken sshd_config or a bad firewall rule, or has lost its network configuration. Because the connection is outside the VPC, security groups and network ACLs do not apply to it, which is why it is locked down three times over:
- Account level, per Region: disabled by default; enable with
aws ec2 enable-serial-console-access, or centrally through an Organizations declarative policy (then individual accounts cannot flip the setting themselves). - IAM level:
ec2-instance-connect:SendSerialConsoleSSHPublicKeyon specific instance ARNs or withaws:ResourceTagmatched againstaws:PrincipalTag. The action name tells you the mechanism: an ephemeral SSH public key is pushed to the serial console service, as with EIC. - OS level: on Linux you need a password-based OS user to log in at the console (AWS AMIs ship without one), so part of the setup is
sudo passwd <user>while you still have normal access. On Windows, granting serial console access is equivalent to granting administrator rights.
Serial console sessions persist across reboot and stop, which is what makes them useful for watching boot messages. The exam distractor pattern: an operator wants routine access without opening ports, and one answer is “enable the EC2 Serial Console”. That is wrong. Routine access is Session Manager or an Instance Connect Endpoint; the serial console is the fire extinguisher.
Decision table: requirement to answer
| Scenario requirement | Best answer | Why not the others |
|---|---|---|
| Interactive admin shell with no inbound ports, no public IP, no SSH keys | Session Manager | EIC needs port 22 and a public address; EICE still uses SSH |
| Full transcript of operator commands for auditors | Session Manager standard session with S3 or CloudWatch Logs logging | SSH and port-forwarding sessions are not logged; EIC/EICE never log content |
| Private instance has no internet access and no NAT but must use Session Manager | Interface VPC endpoints for ssm, ssmmessages, ec2messages | NAT or IGW widens exposure unnecessarily |
| Manage every instance in a Region without touching instance profiles | Default Host Management Configuration | Requires IMDSv2 and agent 3.2.582.0 or later |
| Operators must not be root during sessions | Remove sudo from ssm-user, or turn on Run As with SSMSessionRunAs tags | Run As never uses root and never falls back to ssm-user |
| Developers need a private RDS endpoint from laptops without a bastion | AWS-StartPortForwardingSessionToRemoteHost through an SSM-managed instance | The database needs no agent |
| Team needs native SSH/SCP tooling but port 22 must stay closed | SSH over Session Manager (AWS-StartSSHSession ProxyCommand) | Accept that these sessions are not logged |
| Block one team from tunnelling or SSH while allowing shells | Deny ssm:StartSession on the AWS-StartPortForwardingSession / AWS-StartSSHSession document ARNs; add ssm:SessionDocumentAccessCheck | Instance-level conditions do not distinguish session types |
| Browser-based SSH from the EC2 console works on a laptop but fails in the console | Inbound 22 from the com.amazonaws.<region>.ec2-instance-connect prefix list | Console traffic comes from the service, not the user’s IP |
| SSH or RDP to private instances in a VPC with no IGW, no agent | EC2 Instance Connect Endpoint | Session Manager needs the agent and outbound reachability; a bastion needs a public IP |
| Limit tunnel users to port 22 in one subnet for 30 minutes | ec2-instance-connect:OpenTunnel with remotePort, privateIpAddress, maxTunnelDuration conditions | Security groups cannot express per-user limits |
| Instance stopped responding to SSH after a bad firewall change | EC2 Serial Console (account enabled, IAM granted, OS user with a password) | Nothing network-based will work |
| Centrally forbid serial console access in all member accounts | Declarative policy (or SCP denying ec2:EnableSerialConsoleAccess) | Per-account settings can be re-enabled locally |
IAM condition keys cheat sheet
| Access path | Primary action | Scope which targets | Scope how | Scope who-as |
|---|---|---|---|---|
| Session Manager | ssm:StartSession | Instance ARNs, ssm:resourceTag/<key> | Document ARN (SSM-SessionManagerRunShell, AWS-StartSSHSession, AWS-StartPortForwardingSession), ssm:SessionDocumentAccessCheck | SSMSessionRunAs tag on the principal (Run As) |
| Session ownership | ssm:TerminateSession, ssm:ResumeSession, ssmmessages:OpenDataChannel | arn:aws:ssm:*:*:session/${aws:userid}-* | ssm:resourceTag/aws:ssmmessages:session-id and target-id | n/a |
| EC2 Instance Connect | ec2-instance-connect:SendSSHPublicKey | Instance ARNs, aws:ResourceTag/<key> | n/a (SSH follows) | ec2:osuser |
| EC2 Instance Connect Endpoint | ec2-instance-connect:OpenTunnel | Endpoint ARN, ec2-instance-connect:privateIpAddress | ec2-instance-connect:remotePort, ec2-instance-connect:maxTunnelDuration, aws:SourceIp | ec2:osuser on the companion SendSSHPublicKey |
| EC2 Serial Console | ec2-instance-connect:SendSerialConsoleSSHPublicKey | Instance ARNs, aws:ResourceTag = aws:PrincipalTag | Account-level ec2:EnableSerialConsoleAccess or declarative policy | OS password |
Scenario drill
| Scenario wording | What it is really asking | Answer |
|---|---|---|
”Operators connect with Session Manager, but the SOC cannot see what they ran. Sessions are started with ssh -i key ec2-user@i-....” | Logging gap for SSH sessions | Switch to standard shell sessions; enable S3/CloudWatch logging; deny the AWS-StartSSHSession document |
| ”A session must end after 15 minutes of inactivity and never exceed 8 hours.” | Idle vs maximum duration | Idle timeout 15 (range 1 to 60); maximum session duration 480 (range 1 to 1,440) |
| “After enabling KMS encryption of session data, no one can start sessions.” | Two-sided KMS permissions | Users need kms:GenerateDataKey; instance roles need kms:Decrypt; agent must be 2.3.539.0 or later |
| ”Instances in an isolated subnet show as not managed.” | Agent cannot reach endpoints | Interface endpoints for ssm, ssmmessages, ec2messages; agent 2.3.68.0 or later |
| ”After disabling IMDS for hardening, Session Manager stopped working.” | Agent credentials come from IMDS | Keep IMDS on, enforce IMDSv2 instead |
| ”Each operator must appear in OS logs under their own account; nobody may be root.” | Run As | Enable Run As, tag principals with SSMSessionRunAs, create matching OS users; Run As refuses root |
| ”Junior admins may only tail one log file.” | Interactive command document | Custom Session document with InteractiveCommands session type; grant ssm:StartSession on that document only |
| ”A user terminated a colleague’s session.” | Session ownership | Scope ssm:TerminateSession to session/${aws:userid}-* or the aws:ssmmessages:session-id tag |
| ”Console-based EC2 Instance Connect fails; CLI works.” | Prefix-list rule | Allow 22 inbound from com.amazonaws.<region>.ec2-instance-connect |
”Users with SendSSHPublicKey can reach every instance.” | Missing resource scope | Restrict by instance ARN or aws:ResourceTag, and pin ec2:osuser |
| ”Pushed key works for 60 seconds then stops.” | Expected behaviour | EIC keys live in metadata for 60 seconds by design; re-push for each connection |
| ”RDP to private Windows instances without a bastion or public IPs.” | EICE supports 3389 | Instance Connect Endpoint with remotePort 3389 |
”Policy sets maxTunnelDuration to 900 but connections are refused.” | Required CLI flag | Pass --max-tunnel-duration 900 (or less) when the policy value is below 3,600 |
| ”Client IP preservation enabled; instances in a peered VPC stopped accepting connections.” | Preservation constraints | Same-VPC only, IPv4 only, not through transit gateway; or reference the endpoint SG instead of IP ranges |
| ”Need a second endpoint in another AZ of the same VPC.” | Quota | One endpoint per VPC; delete and recreate, or accept cross-AZ transfer charges |
”Instance unreachable after a sshd_config typo; must recover without snapshotting.” | Serial console | Enable account access, grant SendSerialConsoleSSHPublicKey, use the password-based user set earlier |
| ”Prevent any account in the organization from enabling the serial console.” | Central control | Declarative policy for the serial console setting, or SCP denying ec2:EnableSerialConsoleAccess |
Common mistakes
- Assuming Session Manager logs everything. It logs standard shell sessions only. SSH and port-forwarding sessions pass through the tunnel unrecorded. Many candidates lose a point here.
- Confusing EC2 Instance Connect with EC2 Instance Connect Endpoint. The first pushes a 60-second key and needs a public address plus an open port; the second is a TCP proxy that needs neither. Only the endpoint supports RDP.
- Opening port 22 for Session Manager. It is never required. If a scenario’s “fix” adds an inbound rule for Session Manager, it is wrong.
- Forgetting the instance side of permissions. Session logging to S3 or CloudWatch and KMS session encryption need permissions on the instance role, not only on the user.
- Treating Run As as a fallback. When Run As is on and the OS user is missing, the session fails; it does not revert to
ssm-user. - Expecting the IAM session to end the tunnel. EICE tunnels last until
maxTunnelDuration, regardless of credential expiry. - Reaching for the serial console as an access method. It bypasses security groups and NACLs by design and must stay a break-glass tool.
- Disabling IMDS instead of enforcing IMDSv2. SSM Agent, and therefore Session Manager, depends on the instance role delivered through metadata.
Practice until the discriminator jumps out
Security Specialty questions in this area are never titled “Session Manager question”. They describe an auditor, a compliance deadline, a stopped instance or a developer’s laptop, and bury the discriminating phrase (“transcript”, “no public IP”, “RDP”, “60 seconds”, “inactivity”, “will not boot”) in the middle of a paragraph. Getting fast at spotting that phrase takes repetition against realistically worded scenarios. Sailor.sh’s AWS Certified Security - Specialty Mock Exam Bundle includes eight full-length mock exams whose infrastructure-security and incident-response scenarios are written in that indirect style, with explanations that walk through why Session Manager, an Instance Connect Endpoint, a hardened bastion or the serial console is the best fit for the stated requirement. The compute-access content carried straight from SCS-C02 into SCS-C03, so the drills remain on-blueprint. Pair the mocks with the Security Specialty practice questions, the 30-day study plan and the IAM deep dive for the policy-evaluation logic these condition keys depend on.
Frequently Asked Questions
Does Session Manager require port 22 or 3389 to be open?
No. The SSM Agent initiates an outbound HTTPS connection to the Systems Manager endpoints, and the session rides that channel. You can remove all inbound rules from the security group and still start sessions. The instance also does not need a public IP as long as it can reach the ssm, ssmmessages and ec2messages endpoints, through NAT or interface VPC endpoints.
What is the difference between EC2 Instance Connect and EC2 Instance Connect Endpoint?
EC2 Instance Connect pushes a one-time SSH public key into instance metadata for 60 seconds, after which normal SSH takes place; it needs port 22 reachable from the client and a public address or private connectivity. EC2 Instance Connect Endpoint is an identity-aware TCP proxy that AWS provisions as a network interface in your subnet; it tunnels SSH or RDP to private instances with no public IP and no internet gateway, authorized by ec2-instance-connect:OpenTunnel. The two are often used together: the endpoint provides the path, the one-time key provides the login.
Why are my SSH-over-Session-Manager sessions missing from the S3 logs?
Because Session Manager only acts as a tunnel for SSH and port-forwarding sessions. The SSH traffic is encrypted inside the TLS channel, so the service cannot see or record it. Standard shell sessions (the Standard_Stream session type) are the ones that produce transcripts. If a transcript is a requirement, use standard sessions and consider denying the AWS-StartSSHSession document.
How do I stop Session Manager users from being root?
Either overwrite /etc/sudoers.d/ssm-agent-users so that ssm-user no longer has NOPASSWD:ALL, or enable Run As and tag each IAM user or role with SSMSessionRunAs set to a non-root OS user that exists on the node. Run As does not support root and does not fall back to ssm-user when the named user is missing.
Can an EC2 Instance Connect Endpoint reach instances in another VPC?
The endpoint reaches any subnet in its own VPC whose route table allows traffic from the endpoint’s subnet. With client IP preservation turned off, you can route through peering or a transit gateway, but client IP preservation requires the instance to be in the same VPC and does not work through a transit gateway. There is a quota of one endpoint per VPC and per subnet, and each endpoint supports 20 concurrent connections.
Is the EC2 Serial Console a replacement for Session Manager?
No. The serial console is an out-of-band troubleshooting path that ignores security groups and network ACLs. It is disabled by default at the account level, must be granted per user through ec2-instance-connect:SendSerialConsoleSSHPublicKey, and requires a password-based OS user on Linux. Use it when an instance cannot be reached any other way, and govern it centrally with a declarative policy or an SCP.
Which of these should I expect on the SCS-C03 exam?
Skill 3.2.5 names Session Manager and EC2 Instance Connect explicitly, and the in-scope list calls out EC2 Instance Connect under Amazon EC2. Expect scenario questions that make you choose between those two, the Instance Connect Endpoint and a bastion, plus troubleshooting questions on VPC endpoints, KMS permissions, logging gaps and IAM condition keys.
Conclusion
Administrative access is a solved problem on AWS, but only if you can match the mechanism to the requirement. Session Manager removes ports, keys and bastions and gives you transcripts, timeouts, Run As and KMS encryption, with the one caveat that SSH and port-forwarding sessions are not logged. EC2 Instance Connect keeps SSH but turns the key into a 60-second, IAM-authorized token. EC2 Instance Connect Endpoint turns the bastion into a managed, IAM-governed TCP proxy for SSH and RDP with precise remotePort, privateIpAddress and maxTunnelDuration controls. A bastion host remains for the rare case that forces raw SSH, and the serial console waits for the day the network is broken. Learn where each one authenticates, what each one needs from the network, and what each one writes to the log, and Skill 3.2.5 becomes some of the most predictable points on the exam.