SSM Session Client

SSM Session Client

A single, self-contained binary for AWS SSM Session Manager. Access EC2 instances via shell, native SSH, port forwarding, or RDP β€” without bastion hosts, open inbound ports, or the AWS CLI plugin. Designed for restricted enterprise environments where installing the AWS CLI or Session Manager plugin is not an option.

πŸ–₯️

Interactive Shell

Full terminal access to your instances via SSM. Supports ANSI colours and virtual terminal processing on Windows.

πŸ”’

Native SSH β€” No Client Needed

Built-in SSH using Go's crypto library. No external SSH client, no ProxyCommand. Works on Windows out of the box.

πŸ’»

VSCode Remote SSH

Drop-in replacement for the SSH executable in VSCode Remote SSH. Point remote.SSH.path at the binary and connect.

πŸ”€

Port Forwarding

Tunnel TCP traffic to private instances. Multiplexed connections for SSM agents v3.0.196.0+, single-connection fallback for older agents.

πŸ–±οΈ

RDP (Windows targets)

One command opens an RDP tunnel and launches mstsc.exe. Optional automatic password retrieval via the EC2 API.

πŸ”

PrivateLink Support

Override SSM, SSM Messages, EC2, STS, and KMS endpoints. Works in VPN/Direct Connect environments where AWS PrivateLink replaces public endpoints.

πŸ”‘

EC2 Instance Connect

Push an ephemeral public key via the EC2 Instance Connect API β€” no permanent SSH key management needed.

🌐

AWS Identity Center SSO

Automatic SSO device-code login with optional browser launch. No separate aws sso login step needed.

🏷️

Flexible Target Lookup

Resolve targets by instance ID, EC2 tag, IP address, DNS TXT record, or short aliases defined in your config file.

Why use SSM Session Client instead of the AWS CLI?

Capability AWS CLI + Plugin SSM Session Client
Interactive shell accessβœ“βœ“
SSH ProxyCommandβœ“βœ“
Native SSH (no external client)βœ—βœ“
VSCode Remote SSH replacementβœ—βœ“
EC2 Instance Connect integrationβœ—βœ“
Custom SSM Messages endpointβœ—βœ“
Works in AppLocker/AirLock environmentsβœ—βœ“ (single binary)
Built-in SSO loginRequires separate aws sso loginβœ“ built-in
Target lookup by tag / IP / DNSβœ—βœ“
RDP tunneling with auto passwordβœ—βœ“ (Windows)
VPC endpoint overridesβœ—βœ“

How it works

SSM Session Client uses the AWS SSM StartSession API to create an encrypted WebSocket tunnel to your EC2 instance via the SSM Messages service. All traffic flows through AWS β€” no inbound firewall rules, no bastion hosts, no VPN to the instances themselves.

Access is controlled by IAM policy, not by distributing SSH keys. You grant (or revoke) access to an instance with a policy change, and every session is logged by AWS CloudTrail.

In environments where only AWS PrivateLink endpoints are reachable (VPN or Direct Connect), the ssmmessages-endpoint flag replaces the public StreamUrl returned by StartSession with your private endpoint. This is the primary feature that makes SSM Session Client useful in air-gapped or restricted networks.

Built for restricted enterprise environments

In many enterprise environments, application whitelisting and endpoint security tools prevent users from installing or running the AWS CLI, Python, or the Session Manager plugin. SSM Session Client is a single, statically compiled Go binary with zero runtime dependencies β€” it runs anywhere a standard executable is allowed.

Tested and used in environments protected by:

  • Microsoft AppLocker β€” the binary can be deployed to an approved path and whitelisted by publisher or hash rule
  • Airlock Digital β€” approved as a single file, no additional libraries or interpreters to trust
  • ManageEngine / Endpoint Central β€” no installer, no registry changes, no service dependencies
  • CrowdStrike, Carbon Black, SentinelOne β€” no child processes to spawn (unlike the AWS CLI which invokes Python and the plugin)

Because it ships as one file with everything built in β€” SSH client, SSM data channel, WebSocket transport, SSO login β€” there is nothing extra to install, configure, or get approved by your security team. Copy the binary, set your AWS credentials, and connect.

This also makes SSM Session Client ideal for complex network environments where AWS service endpoints are only reachable via VPN or Direct Connect through AWS PrivateLink. The ssmmessages-endpoint flag lets you override the public StreamUrl with your private VPC endpoint, keeping all session traffic within your private network.

Install

SSM Session Client is a single binary with no runtime dependencies. Download the binary for your platform, make it executable, and add it to your PATH.

macOS

# Download the latest binary
curl -fsSL \
  https://github.com/alexbacchin/ssm-session-client/releases/latest/download/ssm-session-client-darwin-arm64 \
  -o /usr/local/bin/ssm-session-client

# Make it executable
chmod +x /usr/local/bin/ssm-session-client

# Verify
ssm-session-client --version
# Download the latest binary
curl -fsSL \
  https://github.com/alexbacchin/ssm-session-client/releases/latest/download/ssm-session-client-darwin-amd64 \
  -o /usr/local/bin/ssm-session-client

# Make it executable
chmod +x /usr/local/bin/ssm-session-client

# Verify
ssm-session-client --version
macOS Gatekeeper: The first time you run the binary, macOS may block it as an unidentified developer. Run the following command to remove the quarantine flag, then try again:

xattr -d com.apple.quarantine /usr/local/bin/ssm-session-client

Linux

sudo curl -fsSL \
  https://github.com/alexbacchin/ssm-session-client/releases/latest/download/ssm-session-client-linux-amd64 \
  -o /usr/local/bin/ssm-session-client

sudo chmod +x /usr/local/bin/ssm-session-client

ssm-session-client --version
sudo curl -fsSL \
  https://github.com/alexbacchin/ssm-session-client/releases/latest/download/ssm-session-client-linux-arm64 \
  -o /usr/local/bin/ssm-session-client

sudo chmod +x /usr/local/bin/ssm-session-client

ssm-session-client --version
sudo curl -fsSL \
  https://github.com/alexbacchin/ssm-session-client/releases/latest/download/ssm-session-client-linux-386 \
  -o /usr/local/bin/ssm-session-client

sudo chmod +x /usr/local/bin/ssm-session-client

ssm-session-client --version
# For ARMv7 (Raspberry Pi 3/4, most modern ARM boards)
sudo curl -fsSL \
  https://github.com/alexbacchin/ssm-session-client/releases/latest/download/ssm-session-client-linux-arm7 \
  -o /usr/local/bin/ssm-session-client

# For ARMv6 (Raspberry Pi Zero/1)
# Replace "arm7" with "arm6" in the URL above

sudo chmod +x /usr/local/bin/ssm-session-client

ssm-session-client --version

Windows

# Download to a folder already on your PATH (e.g. C:\tools)
$url = "https://github.com/alexbacchin/ssm-session-client/releases/latest/download/ssm-session-client-windows-amd64.exe"
Invoke-WebRequest -Uri $url -OutFile "C:\tools\ssm-session-client.exe"

# Verify
ssm-session-client --version
$url = "https://github.com/alexbacchin/ssm-session-client/releases/latest/download/ssm-session-client-windows-arm64.exe"
Invoke-WebRequest -Uri $url -OutFile "C:\tools\ssm-session-client.exe"

ssm-session-client --version
Windows binaries are code-signed. If Windows Defender SmartScreen warns about the binary, click More infoRun anyway. The binary is signed with a trusted certificate.

No OpenSSH required. The ssh-direct command and the VSCode Remote SSH integration use a built-in Go SSH client β€” you do not need to install the Windows Optional Feature "OpenSSH Client".

Optional: AWS Session Manager Plugin

The AWS Session Manager Plugin is not required. ssm-session-client handles all SSM functionality natively, including KMS-encrypted sessions. No additional software is needed.

If the plugin is installed, ssm-session-client can optionally use it (controlled by the --ssm-session-plugin flag). Install instructions: Install the Session Manager plugin for the AWS CLI.

Code Signing Certificate

Windows binaries are signed with an Authenticode code signing certificate. This allows enterprise security tools to verify the publisher and integrity of the binary. The certificate details below can be used to create whitelisting rules in AppLocker, Airlock Digital, and other endpoint security products.

PropertyValue
SubjectCN=Alex Bacchin, O=github.com/alexbacchin, C=AU
IssuerCN=Alex Bacchin, O=github.com/alexbacchin, C=AU
Serial Number1B:B7:DA:54:2F:FA:C2:4E:A4:F3:9C:A5:71:D2:F6:EF:4E:EE:EC:D3
Valid From21 February 2026
Valid To20 February 2029
Key AlgorithmRSA 4096-bit
Signature AlgorithmSHA-256 with RSA
Key UsageDigital Signature
Extended Key UsageCode Signing
SHA-256 Fingerprint75:89:E4:12:77:43:A6:9D:01:91:75:E0:B7:19:B9:FE:A7:7B:B4:5F:08:C5:35:55:41:7F:5F:B3:F2:F0:9B:6B
SHA-1 Fingerprint51:EC:2D:E1:25:26:AE:25:AF:DB:BC:10:4D:11:53:FD:4A:DC:18:27
Subject Key IdentifierA3:46:9A:84:7D:7E:6C:69:9D:F1:48:55:6D:6E:D9:92:92:65:92:74

AppLocker β€” Publisher Rule

Create a publisher rule in your AppLocker EXE policy that allows binaries signed by this certificate. In Group Policy Editor:

  1. Navigate to Computer Configuration → Windows Settings → Security Settings → Application Control Policies → AppLocker → Executable Rules
  2. Right-click → Create New Rule → select Publisher
  3. Browse to the signed ssm-session-client.exe binary
  4. Set the slider to Publisher level to allow any binary signed by O=github.com/alexbacchin, CN=Alex Bacchin

Alternatively, use a File Hash rule with the SHA-256 hash of the specific release binary.

Airlock Digital

Add the binary by certificate fingerprint or file hash. Use the SHA-256 fingerprint above to create a trusted publisher rule, or add the specific binary hash from the release checksums file.

Verifying the Signature

On Windows, right-click the .exePropertiesDigital Signatures tab to inspect the certificate. From PowerShell:

# View the Authenticode signature
Get-AuthenticodeSignature .\ssm-session-client.exe

# Detailed certificate info
(Get-AuthenticodeSignature .\ssm-session-client.exe).SignerCertificate | Format-List

Configuration

ssm-session-client reads its configuration from three sources, in order of precedence (highest first):

  1. Command-line flags β€” highest priority, override everything
  2. Environment variables β€” prefix SSC_ (e.g. SSC_AWS_REGION)
  3. YAML config file β€” lowest priority, supplies defaults

AWS Credentials

ssm-session-client uses the standard AWS SDK credential chain. No special configuration is needed beyond what you would set up for the AWS CLI. Refer to the AWS documentation: Authentication and access credentials for the AWS CLI.

Common methods:

  • Named profiles in ~/.aws/credentials and ~/.aws/config
  • Environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
  • EC2 instance metadata / ECS task role
  • AWS Identity Center (SSO) β€” see SSO Login below

Configuration Options

Description Config file / Flag Environment variable AWS SDK variable
Config file pathconfigSSC_CONFIGβ€”
Log level (debug, info, warn, error)log-levelSSC_LOG_LEVELβ€”
AWS profile nameaws-profileSSC_AWS_PROFILEAWS_PROFILE
AWS regionaws-regionSSC_AWS_REGIONAWS_REGION / AWS_DEFAULT_REGION
Trigger SSO login flow (true/false)sso-loginSSC_SSO_LOGINβ€”
Open browser for SSO (true/false)sso-open-browserSSC_SSO_OPEN_BROWSERβ€”
STS endpoint overridests-endpointSSC_STS_ENDPOINTAWS_ENDPOINT_URL_STS
EC2 endpoint overrideec2-endpointSSC_EC2_ENDPOINTAWS_ENDPOINT_URL_EC2
SSM endpoint overridessm-endpointSSC_SSM_ENDPOINTAWS_ENDPOINT_URL_SSM
SSM Messages WebSocket endpointssmmessages-endpointSSC_SSMMESSAGES_ENDPOINTβ€”
HTTP proxy URLproxy-urlSSC_PROXY_URLHTTPS_PROXY
Use Session Manager pluginssm-session-pluginSSC_SSM_SESSION_PLUGINβ€”
Enable auto-reconnectenable-reconnectSSC_ENABLE_RECONNECTβ€”
Max reconnection attemptsmax-reconnectsSSC_MAX_RECONNECTSβ€”
Target aliases (config file only)aliasesβ€”β€”
Target alias (CLI flag, repeatable)--alias name=tag:valβ€”β€”
ssh-direct options (nested under ssh-direct: in config file)
SSH private key file pathssh-direct.ssh-key-fileSSC_SSH_DIRECT_SSH_KEY_FILEβ€”
Skip host key verificationssh-direct.no-host-key-checkSSC_SSH_DIRECT_NO_HOST_KEY_CHECKβ€”
Run a command instead of an interactive shellssh-direct.ssh-exec-commandSSC_SSH_DIRECT_SSH_EXEC_COMMANDβ€”
Push ephemeral key via EC2 Instance Connectssh-direct.instance-connectSSC_SSH_DIRECT_INSTANCE_CONNECTβ€”
Disable Instance Connect even if set in configssh-direct.no-instance-connectSSC_SSH_DIRECT_NO_INSTANCE_CONNECTβ€”
Note: proxy-url only applies to services that do not have a custom endpoint set. ssmmessages-endpoint replaces the StreamUrl returned by StartSession so that the WebSocket connection uses your private endpoint.

Config File

The default config file path is $HOME/.ssm-session-client.yaml (Linux/macOS) or %USERPROFILE%\.ssm-session-client.yaml (Windows).

The file is searched in this order:

  1. Current working directory
  2. User home directory ($HOME / %USERPROFILE%)
  3. Directory containing the ssm-session-client executable

Pass a custom path with --config=/path/to/config.yaml.

Minimal config (AWS profile + region)

aws-profile: my-profile
aws-region: ap-southeast-2

AWS Identity Center SSO Login

ssm-session-client can trigger an AWS SSO device-code login automatically before each session. This eliminates the need to run aws sso login separately.

  1. Configure the AWS CLI for SSO. Follow the AWS guide: Configuring the AWS CLI to use AWS IAM Identity Center. This creates a profile section in ~/.aws/config with sso_start_url, sso_account_id, sso_role_name, and sso_region.
  2. Set aws-profile and sso-login: true in your config file (or pass them as flags/env vars).
  3. (Optional) Set sso-open-browser: true if your machine can open a browser. Otherwise, copy the verification URL printed to the terminal and open it in any browser.

SSO config file example

aws-profile: my-sso-profile
aws-region: ap-southeast-2
sso-login: true
sso-open-browser: true

VPC Endpoints (PrivateLink)

In environments where AWS services are only reachable via AWS PrivateLink (VPN or Direct Connect), you can override each service endpoint individually.

The ssmmessages-endpoint flag is the critical one: the StartSession API always returns a public StreamUrl. This flag replaces that URL with your private VPC endpoint so the WebSocket tunnel stays entirely within your private network.

Config file with VPC endpoint overrides

aws-profile: sandbox
aws-region: us-west-2

# VPC endpoint DNS names (from your VPC endpoint console/outputs)
ec2-endpoint:          vpce-059c3b85db66f8165-mzb6o9nb.ec2.us-west-2.vpce.amazonaws.com
ssm-endpoint:          vpce-06ef6f173680a1306-bt58rzff.ssm.us-west-2.vpce.amazonaws.com
ssmmessages-endpoint:  vpce-0e5e5b0c558a14bf2-r3p6zkdm.ssmmessages.us-west-2.vpce.amazonaws.com
sts-endpoint:          vpce-0877b4abeb479ee06-arkdktlc.sts.us-west-2.vpce.amazonaws.com

# Optional: HTTP proxy for services without a custom endpoint set
proxy-url: http://myproxy:3128
Tip: Required VPC endpoints for full SSM functionality: com.amazonaws.<region>.ssm, com.amazonaws.<region>.ssmmessages, com.amazonaws.<region>.ec2, and com.amazonaws.<region>.sts. See the AWS documentation: Create VPC endpoints.

Target Lookup

All session commands accept a target as the first argument. Targets are resolved using the following chain (first match wins):

PriorityMethodExample inputHow it works
1Instance IDi-0abc1234def56789Passed directly to the SSM API
2AliasdevboxLooks up the alias in your config, queries EC2 by tag β€” errors if more than one match
3EC2 tagName:web-serverQueries EC2 for running instances with tag key=value
4IP address10.0.1.5Queries EC2 by private or public IPv4
5DNS TXT recordweb.example.comResolves the hostname as a DNS TXT record expected to contain the instance ID

Target Aliases

Aliases map a short friendly name to an EC2 tag key + value. They are unique β€” the lookup errors if more than one running instance matches, so the alias always refers to exactly one host.

Define aliases in the config file

aliases:
  devbox:
    tag-name: Name
    tag-value: my-devbox
  prod-web:
    tag-name: Environment
    tag-value: production

Define aliases on the command line (repeatable)

# Single alias on the fly
ssm-session-client shell devbox --alias devbox=Name:my-devbox

# Multiple aliases
ssm-session-client shell prod-web \
  --alias devbox=Name:my-devbox \
  --alias prod-web=Environment:production

CLI aliases override same-named aliases in the config file. Use aliases with any command:

ssm-session-client shell            devbox
ssm-session-client ssh-direct       ec2-user@devbox
ssm-session-client port-forwarding  devbox:443 8443

Automatic Reconnection

ssm-session-client automatically reconnects when a WebSocket connection drops. Configure it with:

  • --enable-reconnect β€” enable/disable (default: true)
  • --max-reconnects β€” maximum attempts before giving up (default: 5, set 0 for unlimited)

Data Channel Encryption

When KMS encryption is enabled for SSM sessions, the data channel is encrypted using AES-256-GCM. Encryption keys are derived from AWS KMS using the GenerateDataKey API, with the session ID and target ID as encryption context.

SSM Session Client has built-in support for KMS-encrypted sessions and does not require the AWS Session Manager plugin. The encryption is handled natively using Go's crypto libraries. If the Session Manager plugin is installed and enabled (ssm-session-plugin: true), it will be used instead, but it is not required.

KMS endpoint: If you are using VPC endpoints, you may also need to configure a KMS VPC endpoint (com.amazonaws.<region>.kms) for the key exchange to succeed within your private network.

Session Modes

Shell

Opens an interactive terminal session on the target instance. Equivalent to aws ssm start-session.

ssm-session-client shell i-0bdb4f892de4bb54c
ssm-session-client shell i-0bdb4f892de4bb54c --config=~/.ssm-session-client.yaml

On Windows, the shell command supports virtual terminal processing with ANSI escape sequences for proper colour and formatting in remote shells.

KMS encryption: KMS-encrypted sessions are supported natively. No Session Manager plugin is required β€” encryption is handled using built-in AES-256-GCM routines. See Data Channel Encryption for details.

IAM reference: Sample IAM policies for Session Manager

SSH (ProxyCommand)

Uses ssm-session-client as an SSH ProxyCommand, forwarding stdio to the SSM data channel. The SSH client (system ssh) handles authentication and encryption. Requires an SSH server on the target instance.

1. Configure SSH

Add to ~/.ssh/config (Linux/macOS) or %USERPROFILE%\.ssh\config (Windows):

Host i-* mi-*
  ProxyCommand ssm-session-client ssh %r@%h --config=~/.ssm-session-client.yaml

2. Automatically configure SSH (optional)

ssm-session-client ssh add-proxy-command ec2-user@i-0bdb4f892de4bb54c

3. Connect

ssh ec2-user@i-0bdb4f892de4bb54c

IAM reference: Enabling SSH connections through Session Manager

SSH Direct (Native SSH Client)

A fully integrated SSH session over SSM using Go's native SSH library. No external SSH client, no ProxyCommand, no SSH server listening on an open port.

# Interactive session
ssm-session-client ssh-direct ec2-user@i-0123456789abcdef0

# With a specific key file
ssm-session-client ssh-direct ec2-user@i-0123456789abcdef0 --ssh-key ~/.ssh/my-key

# Run a single command
ssm-session-client ssh-direct ec2-user@i-0123456789abcdef0 --exec "uptime"

# Using EC2 Instance Connect (no SSH key management needed)
ssm-session-client ssh-direct ec2-user@i-0123456789abcdef0 --instance-connect

# Custom SSH port
ssm-session-client ssh-direct ec2-user@i-0123456789abcdef0:2222

Authentication chain (tried in order)

  1. Ephemeral key via EC2 Instance Connect (when --instance-connect is used)
  2. SSH agent (SSH_AUTH_SOCK)
  3. Private key file (--ssh-key or auto-discovered ~/.ssh/id_ed25519 / ~/.ssh/id_rsa)
  4. Password prompt (interactive)
Host key verification uses Trust-On-First-Use (TOFU): on the first connection the host key is saved to ~/.ssh/known_hosts. Use --no-host-key-check to skip verification (not recommended for production).

Config file example

ssh-direct options live under the ssh-direct: section in the config file:

ssh-direct:
  ssh-key-file: ~/.ssh/id_ed25519   # private key (omit to auto-discover)
  no-host-key-check: false          # set true only in trusted environments
  instance-connect: true            # push ephemeral key via EC2 Instance Connect

VSCode Remote SSH Integration

ssm-session-client can act as the SSH executable for VSCode Remote SSH, eliminating the need for an external SSH client or ProxyCommand setup. This is especially useful on Windows where OpenSSH may not be installed.

  1. Configure the binary path in VSCode. Open Settings (Ctrl+,) and search for remote.SSH.path, or add to settings.json:
    // Linux / macOS
    { "remote.SSH.path": "/usr/local/bin/ssm-session-client" }
    
    // Windows
    { "remote.SSH.path": "C:\\tools\\ssm-session-client.exe" }
  2. Configure your SSH config file (~/.ssh/config or %USERPROFILE%\.ssh\config):
    # A named host mapped to an instance ID
    Host my-server
      HostName i-0123456789abcdef0
      User ec2-user
    
    # Wildcard for all instance IDs
    Host i-*
      User ec2-user
      StrictHostKeyChecking accept-new
  3. Set AWS credentials. Use a config file, environment variables (AWS_PROFILE, AWS_REGION), or the standard credential chain. The ssm-session-client config file is also honoured for VPC endpoint overrides.
  4. Connect. In VSCode, open the Command Palette (Ctrl+Shift+P) β†’ Remote-SSH: Connect to Host… β†’ select your configured host.
How it works: When VSCode invokes the binary with OpenSSH-style flags (-T -o ConnectTimeout=15 -F /path/to/config hostname bash), the binary detects SSH-compat mode, parses the SSH config to resolve the hostname to an EC2 instance ID, and establishes an SSH-over-SSM tunnel using the built-in Go SSH client.

Symlink mode: Alternatively, create a symlink named ssh pointing to ssm-session-client. When invoked as ssh, it always operates in OpenSSH-compat mode.

Supported SSH Flags

When operating in OpenSSH-compat mode (VSCode or symlink), the following SSH flags are recognised:

FlagDescription
-TDisable PTY allocation (used by VSCode)
-tForce PTY allocation
-NNo remote command
-o key=valueSSH options (StrictHostKeyChecking, UserKnownHostsFile, ConnectTimeout, etc.)
-F <config>SSH config file path
-p <port>Remote port
-l <user>Login username
-i <keyfile>Identity file (private key)
-D <port>Dynamic port forwarding (accepted but ignored)
-v / -vv / -vvvVerbosity (maps to log levels)

SSH with EC2 Instance Connect

The instance-connect command combines SSM session tunnelling with EC2 Instance Connect. It pushes an ephemeral SSH public key to the instance before connecting, so no permanent key management is needed. Authentication is controlled by the IAM action ec2-instance-connect:SendSSHPublicKey.

Linux targets only. EC2 Instance Connect is only available for Linux instances. Additionally, the EC2 Instance Connect API endpoint is not available via AWS PrivateLink β€” internet access (or an HTTP proxy) is required for the key push step.
# SSH config using instance-connect as ProxyCommand
Host i-*
  ProxyCommand ssm-session-client instance-connect %r@%h

# With a custom key pair
Host i-*
  IdentityFile ~/.ssh/custom
  ProxyCommand ssm-session-client instance-connect %r@%h --ssh-public-key-file=~/.ssh/custom.pub
# Automatically configure SSH
ssm-session-client instance-connect add-proxy-command ec2-user@i-0bdb4f892de4bb54c

# Then connect normally
ssh ec2-user@i-0bdb4f892de4bb54c

Port Forwarding

Securely tunnel TCP traffic to a port on a private instance without SSH, open firewall rules, or a bastion host.

# Forward local port 8888 β†’ instance port 443
ssm-session-client port-forwarding i-0bdb4f892de4bb54c:443 8888

# Auto-assign local port
ssm-session-client port-forwarding i-0bdb4f892de4bb54c:443
Multiplexed connections: For SSM agents v3.0.196.0 and above, port forwarding automatically uses stream multiplexing (via smux), allowing multiple concurrent TCP connections over a single SSM session. Older agents fall back to single-connection mode automatically.

RDP (Windows targets only)

The rdp command (Windows build only) sets up a port-forwarding tunnel to port 3389 and launches mstsc.exe automatically.

# Basic RDP connection
ssm-session-client rdp i-0bdb4f892de4bb54c

# Retrieve the Windows administrator password automatically
ssm-session-client rdp i-0bdb4f892de4bb54c --get-password --key-pair-file ~/.ssh/my-ec2-keypair.pem

# Custom RDP port and username
ssm-session-client rdp i-0bdb4f892de4bb54c --rdp-port 3390 --username admin
FlagDefaultDescription
--rdp-port3389Remote RDP port on the EC2 instance
--local-port0 (auto)Local port for the SSM tunnel
--get-passwordfalseRetrieve the Windows administrator password via the EC2 API
--key-pair-fileβ€”EC2 key pair private key file (required with --get-password)
--usernameAdministratorRDP username

When --get-password is used, the password is retrieved from the EC2 API, decrypted with the provided key pair, and copied to the clipboard for pasting into the RDP credentials prompt.

IAM: requires ec2:GetPasswordData in addition to standard SSM session permissions.

Troubleshooting

Log Files

Logs are written to both the console and a rotating log file. The log directory depends on your operating system:

OSLog directory
Windows%USERPROFILE%\AppData\Local\ssm-session-client\logs
macOS$HOME/Library/Logs/ssm-session-client
Linux / other Unix$HOME/.ssm-session-client/logs

Log files are rotated daily or when they reach 10 MB. The last three log files are kept.

Debug Mode

Set the log level to debug to capture verbose output including AWS API calls, WebSocket messages, and connection lifecycle events.

Via environment variable (recommended for quick debugging)

SSC_LOG_LEVEL=debug ssm-session-client shell i-0bdb4f892de4bb54c

Via config file

log-level: debug

Via CLI flag

ssm-session-client shell i-0bdb4f892de4bb54c --log-level=debug
Debug output is always written to the log file (see paths above), even when the console is in a lower-verbosity mode. To see debug output in the terminal, set log-level: debug in your config file or via the environment variable.

Common Issues

macOS: "ssm-session-client cannot be opened"

macOS Gatekeeper quarantines downloaded binaries. Remove the quarantine flag:

xattr -d com.apple.quarantine /usr/local/bin/ssm-session-client

Windows: SmartScreen warning

Click More info β†’ Run anyway. The binary is code-signed; SmartScreen may still warn on first run until the binary has sufficient reputation. Running from an Administrator PowerShell session bypasses this.

Connection times out / "target not connected"

  • Verify the SSM Agent is running on the instance: in the EC2 console, check Systems Manager β†’ Fleet Manager β†’ instance status.
  • Ensure the instance has the required IAM instance profile with the AmazonSSMManagedInstanceCore managed policy.
  • If using VPC endpoints, confirm all four endpoints (ssm, ssmmessages, ec2, sts) are in place and their security groups allow traffic from the instance.
  • Enable debug logging (see above) and check the log file for API error details.

SSO: "no valid SSO token found"

  • Ensure sso-login: true is set in your config (or --sso-login flag).
  • If you cannot open a browser, copy the verification URL from the debug log or console and open it on another device.
  • Verify the SSO profile in ~/.aws/config has sso_start_url, sso_account_id, sso_role_name, and sso_region.

Target not found

  • Confirm the EC2 instance is in a running state.
  • For tag-based lookup, ensure the IAM credentials have ec2:DescribeInstances.
  • For alias lookup, confirm the alias is defined in the config file or passed with --alias.

Contributing

Contributions are welcome! Please open an issue to discuss significant changes before submitting a pull request. All code must pass the lint and unit tests before merging.

Prerequisites

  • Go (version from go.mod)
  • golangci-lint for linting
  • Acceptance tests only: An AWS account, and OpenTofu (or Terraform) for provisioning test infrastructure

Building from Source

# Clone the repository
git clone https://github.com/alexbacchin/ssm-session-client.git
cd ssm-session-client

# Build for the current platform
go build -o ssm-session-client .

# Cross-compile
GOOS=linux   GOARCH=amd64 go build -o ssm-session-client-linux-amd64 .
GOOS=darwin  GOARCH=arm64 go build -o ssm-session-client-darwin-arm64 .
GOOS=windows GOARCH=amd64 go build -o ssm-session-client.exe .

Unit Tests

# Run all unit tests with the race detector and coverage
go test ./... -race -coverprofile=coverage.out -covermode=atomic

# View coverage summary
go tool cover -func=coverage.out

# Run a single test
go test ./ssmclient/... -run TestTargetResolver -race

Linting

golangci-lint run

Key lint constraints enforced in this project:

  • Maximum function length: 75 lines / 50 statements
  • Maximum cognitive/cyclomatic complexity: 15
  • Maximum line length: 132 characters
  • Active linters: errcheck, gosec, funlen, gocognit, gocyclo, revive, bodyclose

Acceptance Tests

The acceptance test suite provisions real AWS infrastructure (an EC2 instance with no inbound SSH access), runs end-to-end tests against it, and tears everything down. Tests are tagged acceptance and are excluded from the standard go test ./... run.

What the tests cover

  • Shell access by instance ID, tag, alias, private IP, and DNS TXT record
  • SSH direct and SSH proxy connections
  • EC2 Instance Connect session
  • Port forwarding (single and multiple concurrent connections)
  • RDP tunnel (Windows runner, optional)
  • SSO login with cached token (optional, requires an SSO profile)
  • Error conditions: invalid target, missing region, session termination

1. Configure AWS credentials

The tests use standard AWS SDK credential chain. For CI, OIDC is recommended. For local runs, use a named profile or environment variables. The IAM principal needs permissions to manage EC2, SSM, IAM roles, and (optionally) Route53, KMS.

2. Provision infrastructure

cd test/scripts
make acceptance-prepare AWS_REGION=ap-southeast-2

# Wait for the SSM agent to come online
make acceptance-wait-ssm AWS_REGION=ap-southeast-2

3. Run the tests

make acceptance-run-local

4. Tear down

make acceptance-destroy AWS_REGION=ap-southeast-2

Full lifecycle (provision β†’ test β†’ destroy)

make acceptance AWS_REGION=ap-southeast-2

Interactive SSO test

# Requires a human to approve the device code in a browser
make acceptance-sso-interactive SSO_PROFILE=my-sso-profile

Windows / RDP tests

# Provision with a Windows instance
make acceptance-prepare TF_EXTRA_VARS="-var=create_windows_instance=true"

# Run on a Windows runner with the acceptance+windows build tags
go test ./test/acceptance/... -tags "acceptance windows" -run RDP -v
CI/CD: Acceptance tests run automatically on every release tag via release.yml. They also run nightly via acceptance.yml. AWS authentication uses GitHub OIDC (no long-lived secrets stored in GitHub).