Skip to main content

Enhanced Python AWS SSM Session Manager client with interactive sessions, exec, and file transfer support

Project description

PySSM Client

Enhanced Python AWS SSM Session Manager client with interactive sessions, exec, and file transfer support. It speaks the same binary protocol as the official Go plugin and provides additional functionality like library imports and extended CLI commands.

Highlights:

  • Interactive SSH-like sessions via SSM (ssh subcommand)
  • Direct connect to an existing SSM data channel (connect subcommand)
  • Proper ack/seq handling, terminal raw mode, signal forwarding (Ctrl-C/Z/), and periodic resize updates
  • Minimal logging by default; verbose traces with -v

Installation

Install from PyPI:

pip install pyssm-client

Or with uv:

uv add pyssm-client

Requirements

  • Python 3.12+
  • AWS credentials discoverable via environment or ~/.aws/credentials

Quick Start

# Interactive SSH-like session
pyssm ssh --target i-0123456789abcdef0

# Execute single command
pyssm exec --target i-0123456789abcdef0 --command "ls -la"

# Copy files
pyssm copy ./local-file.txt i-0123456789abcdef0:/tmp/remote-file.txt

CLI Usage

The CLI provides four subcommands: connect, ssh, exec, and copy.

ssh: Start an SSM session to a target

Starts a new SSM session using boto3 and connects interactively.

pyssm ssh \
  --target i-0123456789abcdef0 \
  --region us-west-2 \
  --profile myprofile

Options:

  • --target (required): EC2 instance ID (i-*) or managed instance ID (mi-*)
  • --document-name: SSM document (defaults to the agent’s standard shell doc)
  • --parameters: JSON object of document parameters
  • --profile, --region, --endpoint-url: AWS settings for boto3

Global options (apply to all commands):

  • -v/--verbose: enable DEBUG logging
  • --log-file PATH: log to file in addition to stderr
  • --coalesce-input [auto|on|off] (default auto): input batching
    • auto: enabled for non‑TTY stdin (piped input), disabled for interactive TTYs
    • on: always enable (tunable with --coalesce-delay-ms)
    • off: always disabled
  • --coalesce-delay-ms FLOAT (default 10.0): coalescing delay when enabled

Behavior:

  • Terminal set to cbreak, -echo -isig (no double echo; signals forwarded to remote)
  • Periodic terminal size updates (500ms) and on resize (SIGWINCH)
  • Ctrl-C (0x03), Ctrl-\ (0x1c), Ctrl-Z (0x1a) forwarded to remote
  • exit cleanly closes the session and the CLI

exec: Execute a single command

Execute a single command on a target instance and return the results with proper exit codes.

pyssm exec \
  --target i-0123456789abcdef0 \
  --command "ls -la /tmp" \
  --region us-west-2 \
  --profile myprofile

Options:

  • --target (required): EC2 instance ID (i-*) or managed instance ID (mi-*)
  • --command (required): Shell command to execute
  • --timeout: Command timeout in seconds (default: 600)
  • --profile, --region, --endpoint-url: AWS settings for boto3

This command:

  • Executes the command and captures stdout/stderr separately
  • Returns the actual exit code of the executed command
  • Filters shell noise (prompts, command echoes) from output
  • Useful for scripting and automation

copy: File transfer via SSM

Transfer files to/from targets using base64 encoding over SSM sessions.

# Upload local file to remote
pyssm copy \
  ./local-file.txt i-0123456789abcdef0:/tmp/remote-file.txt \
  --region us-west-2 \
  --profile myprofile

# Download remote file to local  
pyssm copy \
  i-0123456789abcdef0:/tmp/remote-file.txt ./local-file.txt \
  --region us-west-2 \
  --profile myprofile

Options:

  • --verify-checksum (default: on): Verify file integrity using MD5/SHA256
  • --encoding (default: base64): Transfer encoding (base64, raw, uuencode)
  • --chunk-size: Transfer chunk size in bytes (default: 8192)
  • --profile, --region, --endpoint-url: AWS settings for boto3

Features:

  • Automatic checksum verification to ensure file integrity
  • Progress reporting during transfer
  • Support for binary files via base64 encoding
  • Works with any file size (chunked transfer)

connect: Attach to an existing SSM data channel

Connects using session parameters you already have (typical when called by AWS CLI). You can pass a single JSON blob or individual flags.

JSON form (mimics the AWS CLI invocation):

pyssm connect '{
  "SessionId": "dacort-abc123",
  "StreamUrl": "wss://ssmmessages.us-west-2.amazonaws.com/v1/data-channel/dacort-abc123?...",
  "TokenValue": "...",
  "target": "i-0123456789abcdef0",
  "sessionType": "Standard_Stream"
}'

Flag form:

pyssm connect \
  --session-id dacort-abc123 \
  --stream-url wss://... \
  --token-value ... \
  --target i-0123456789abcdef0 \
  --session-type Standard_Stream

Notes:

  • The CLI validates parameters and will emit friendly errors if missing or invalid.
  • Global logging and coalescing options work here too.

Using as a Library

You can embed the plugin in your own Python program. There are four convenient levels: file transfer, exec API, high-level (CLI coordinator), and low-level (session + data channel).

File Transfer API: Upload/download files

For programmatic file transfers with progress tracking and verification:

from pyssm_client.file_transfer import FileTransferClient
from pyssm_client.file_transfer.types import FileTransferOptions

client = FileTransferClient()

# Upload file
options = FileTransferOptions(verify_checksum=True)
success = await client.upload_file(
    local_path="./local-file.txt",
    remote_path="/tmp/remote-file.txt", 
    target="i-0123456789abcdef0",
    options=options,
    region="us-west-2",
    profile="myprofile"
)

# Download file
success = await client.download_file(
    remote_path="/tmp/remote-file.txt",
    local_path="./downloaded-file.txt",
    target="i-0123456789abcdef0", 
    options=options,
    region="us-west-2",
    profile="myprofile"
)

Exec API: Single command execution

For simple command execution with clean stdout/stderr separation:

from pyssm_client.exec import run_command, run_command_sync

# Async version
result = await run_command(
    target="i-0123456789abcdef0",
    command="ls -la /tmp",
    region="us-west-2",
    profile="myprofile"
)
print(f"Exit code: {result.exit_code}")
print(f"Stdout: {result.stdout.decode('utf-8')}")
print(f"Stderr: {result.stderr.decode('utf-8')}")

# Sync version  
result = run_command_sync(
    target="i-0123456789abcdef0",
    command="sha256sum /path/to/file"
)
if result.exit_code == 0:
    checksum = result.stdout.decode('utf-8').strip().split()[0]

High-level: reuse the CLI coordinator

import asyncio
from pyssm_client.cli.types import ConnectArguments
from pyssm_client.cli.main import SessionManagerPlugin
from pyssm_client.utils.logging import setup_logging

setup_logging()  # or logging.DEBUG for verbose

args = ConnectArguments(
    session_id="dacort-abc123",
    stream_url="wss://...",
    token_value="...",
    target="i-0123456789abcdef0",
    session_type="Standard_Stream",
)

plugin = SessionManagerPlugin()
exit_code = asyncio.run(plugin.run_session(args))

Low-level: wire session + data channel yourself

import asyncio
from pyssm_client.session.session_handler import SessionHandler
from pyssm_client.communicator.utils import create_websocket_config
from pyssm_client.communicator.data_channel import SessionDataChannel

async def main():
    handler = SessionHandler()
    # Create session (without executing) from your already-resolved params
    session = await handler.validate_input_and_create_session({
        "sessionId": "dacort-abc123",
        "streamUrl": "wss://...",
        "tokenValue": "...",
        "target": "i-0123456789abcdef0",
        "sessionType": "Standard_Stream",
    })

    # Create data channel and wire handlers
    ws_cfg = create_websocket_config(stream_url="wss://...", token="...")
    dc = SessionDataChannel(ws_cfg)
    dc.set_input_handler(lambda b: sys.stdout.buffer.write(b) or sys.stdout.flush())
    # Optional: closed and coalescing handlers
    dc.set_closed_handler(lambda: print("\n[session closed]\n"))
    # dc.set_coalescing(True, delay_sec=0.01)  # for piped input

    session.set_data_channel(dc)
    await session.execute()        # open websocket + handshake
    # then run your own event loop + stdin handling as needed

asyncio.run(main())

Tips:

  • For custom UIs, provide your own input_handler (bytes from the agent) and feed send_input_data() with bytes from your UI.
  • Use send_terminal_size(cols, rows) whenever your layout changes.
  • On shutdown, call await session.terminate_session().

Development

Run tests:

uv run pytest -q

Formatting & linting:

uv run black .
uv run ruff check .
uv run mypy .

Logging:

  • By default, logs are minimal. Use -v or set up setup_logging(level=logging.DEBUG) programmatically for detailed traces.

Architecture

The codebase has been recently refactored for better maintainability and reliability:

  • Clean message handling: AWS SSM protocol messages are parsed by dedicated MessageParser and routed to specialized handlers (HandshakeHandler, StreamHandler, ControlHandler)
  • Reliable file transfers: Fixed line ending normalization issues that caused checksum mismatches
  • Modular design: Session management, WebSocket communication, and CLI coordination are cleanly separated
  • Type safety: Full mypy type checking with modern Python type hints

This provides a solid foundation for extending functionality while maintaining compatibility with the AWS SSM protocol.

Known Limitations

  • KMS encryption handshake is not implemented; sessions requiring encryption will not negotiate keys.
  • Port/InteractiveCommands sessions are stubbed and not fully implemented.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyssm_client-0.1.1.tar.gz (107.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyssm_client-0.1.1-py3-none-any.whl (63.9 kB view details)

Uploaded Python 3

File details

Details for the file pyssm_client-0.1.1.tar.gz.

File metadata

  • Download URL: pyssm_client-0.1.1.tar.gz
  • Upload date:
  • Size: 107.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.8.19

File hashes

Hashes for pyssm_client-0.1.1.tar.gz
Algorithm Hash digest
SHA256 7f4e4c5c0f2c6c22edb8be48bb8e86e47f7c1cfb13a7e0f44d5f73c14fd25c80
MD5 da03a955ca54124a5a6c5b570ab78a54
BLAKE2b-256 e432cdc803c1bde603b160ae3bb1edcbfa0a309c5119d373d7983255b61bd74d

See more details on using hashes here.

File details

Details for the file pyssm_client-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for pyssm_client-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 31d9af22adb5682b263266b9426bf92ea601c96bcfbc1697695645521263d211
MD5 40ad64a5a0905ba1b9b6ba7c6d1b4c13
BLAKE2b-256 f513f1b2d3c74ad3a5f378ae5f46b0f244c595610ac059d82a04b88ed0c0ef6a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page