17 releases (6 breaking)
| 0.7.1 | Mar 23, 2026 |
|---|---|
| 0.7.0 | Mar 5, 2026 |
| 0.6.9 | Mar 5, 2026 |
| 0.5.0 | Mar 2, 2026 |
| 0.1.0 | Feb 25, 2026 |
#605 in Command line utilities
235KB
5K
SLoC
awsx2
A fast AWS management CLI and interactive TUI built in Rust. Manages EC2 instances, SSM tunnels, local reverse proxies, and AWS Client VPN with SAML authentication through a single tool.
awsx2 # launch interactive TUI
awsx2 list # CLI mode — list all instances
Features
- Dual-mode — full-screen TUI for interactive use, CLI for scripts and automation
- EC2 management — list, start, stop, force-stop, switch instance types (GPU/CPU)
- Smart tunneling — SSM port-forwarding with ALB-aware routing, security group analysis, and bastion fallback
- Client VPN — AWS Client VPN with SAML/SSO authentication, headless browser MFA, and automatic DNS configuration
- Reverse proxy — auto-configures nginx +
/etc/hostsso internal URLs work directly in the browser - Cross-platform — macOS (Homebrew) and Linux (Debian/Ubuntu, RHEL/CentOS, Amazon Linux)
Prerequisites
- AWS CLI v2 with SSO configured
- Session Manager Plugin
- SSM Agent running on target EC2 instances
- nginx (only for
--proxyfeature) - Chromium/Chrome (only for
vpn connect— headless SAML auth) - AWS VPN Client or OpenVPN (only for
vpn connect)
Installation
One-liner (downloads pre-built binary from GitHub Releases):
curl -fsSL https://raw.githubusercontent.com/JeanMaximilienCadic/myawesomescripts/master/aws/awsx2/install.sh | bash
Detects your OS and architecture automatically. Installs to /usr/local/bin (override with INSTALL_DIR).
From crates.io:
cargo install awsx2
From source:
cargo build --release
cp target/release/awsx2 /usr/local/bin/
CLI Usage
Run awsx2 <command>. Instance commands accept --name or read from the INSTANCE_NAME environment variable.
Instance Management
awsx2 list # List all EC2 instances
awsx2 status --name my-server # Show instance details
awsx2 start --name my-server # Start an instance
awsx2 stop --name my-server # Graceful stop
awsx2 force-stop --name my-server # Force stop (immediate)
awsx2 switch gpu --name my-server # Switch to g4dn.4xlarge
awsx2 switch cpu --name my-server # Switch to m6i.2xlarge
Authentication
awsx2 login # SSO login using $AWS_PROFILE
awsx2 login my-profile # SSO login with explicit profile
DNS Resolution
awsx2 resolve https://app.internal.example.com
Traces the full path: hostname → DNS → ALB → target group → EC2/Fargate backend.
Tunnels
Direct tunnel to an EC2 instance by name pattern:
awsx2 tunnel web-server 8080 8000
# ^pattern ^local ^remote
URL tunnel with smart ALB resolution (auto-detects bastion and remote port):
awsx2 tunnel-url https://app.internal.example.com 8080
The resolution chain: URL → ALB match → healthy target group → security group rules → SSM-online hop instance. Falls back to trying all available bastions if ALB resolution fails.
URL tunnel with reverse proxy so the URL works directly in the browser:
awsx2 tunnel-url https://app.internal.example.com 8080 --proxy
This additionally:
- Writes an nginx config forwarding port 80 → localhost:8080
- Adds
127.0.0.1 app.internal.example.comto/etc/hosts - Reloads nginx and flushes DNS cache
DNS tunnel (resolve hostname, tunnel to the resolved IP):
awsx2 tunnel-dns https://app.internal.example.com 8080 8501
Remote tunnel via a specific bastion to an arbitrary host:
awsx2 tunnel-remote bastion 10.0.1.42 8080 8501
# ^bastion ^target ^local ^remote
Tunnel management:
awsx2 tunnel-test 8080 # Check if port is open
awsx2 tunnel-stop # Kill all SSM tunnels + clean up proxies
SSH via SSM
Seamless SSH to EC2 instances using SSM as transport — no bastion hosts, no public IPs, no key management.
Generate ~/.ssh/config entries for all running, SSM-online instances:
awsx2 ssh-config # Update ~/.ssh/config
awsx2 ssh-config --dry-run # Preview without writing
awsx2 ssh-config --user ubuntu # Override SSH user (default: ec2-user)
This creates a managed block in ~/.ssh/config with entries like:
# BEGIN awsx2-managed
Host dev-risk-model-ec2
User ec2-user
ProxyCommand awsx2 ssm-proxy --name dev-risk-model-ec2 --port %p --region ap-northeast-1
# END awsx2-managed
Running ssh-config again replaces the managed block and removes any stale duplicate Host entries outside it.
Then just SSH normally:
ssh dev-risk-model-ec2
On first connection, ssm-proxy automatically pushes your SSH public key to the instance via SSM send-command (cached for 7 days). Subsequent connections skip this step.
The ssm-proxy subcommand resolves the EC2 Name tag to an instance ID dynamically, so instance replacements (e.g. ASG rotations) are handled transparently.
VPN
Connect to AWS Client VPN endpoints that use SAML/SSO authentication. Credentials are saved locally so you only need to enter the MFA code each time.
# One-time setup — saves credentials to ~/.config/awsx2/vpn.json
awsx2 vpn setup \
--username user@example.com \
--password 'secret' \
--ovpn /path/to/client.ovpn \
--dns-server 10.0.0.2 \
--dns-domain '~internal.example.com'
# Connect (prompts for MFA if not provided)
sudo -E awsx2 vpn connect 123456
# Check status
awsx2 vpn status
# Disconnect
sudo -E awsx2 vpn disconnect
The connect flow:
- Sends initial auth to VPN server to obtain SAML challenge URL
- Launches headless Chromium to complete SSO login (username, password, MFA)
- Captures SAML response via local HTTP callback
- Reconnects to VPN with the SAML token (uses AWS patched OpenVPN if available)
- Configures DNS routing via
resolvectlfor the specified domain
Requires sudo -E to create the tun interface and configure DNS. The -E flag preserves your AWS environment variables.
TUI
Launch with awsx2 (no arguments). Navigate with keyboard — no mouse required.
Global Keys
| Key | Action |
|---|---|
Tab / Shift+Tab |
Switch tabs |
? |
Toggle help overlay |
q / Ctrl+c |
Quit |
Instances Tab
| Key | Action |
|---|---|
j / k / Up / Down |
Navigate |
g / G |
Jump to first / last |
/ |
Filter by name, ID, or type |
Esc |
Clear filter |
s |
Start instance |
S |
Stop instance |
f |
Force-stop instance |
r |
Refresh |
Columns: Instance ID, Name, Type, State, SSM Status, Tunnel, Private IP. States are color-coded: green = running, red = stopped, yellow = pending/stopping.
Tunnels Tab
| Key | Action |
|---|---|
j / k / Up / Down |
Navigate |
n |
New tunnel by instance name (wizard) |
u |
New tunnel by URL (smart ALB resolution) |
b |
New tunnel via bastion (wizard) |
d / Delete |
Stop selected tunnel |
A |
Stop all tunnels |
r |
Refresh |
Each tunnel shows real-time status with latency measurement:
● OK 42ms— tunnel active, measured round-trip▲ OPEN— port open, not yet probed◌ DOWN— tunnel unreachable
Tunnels auto-refresh every ~15 seconds.
Tools Tab
| Key | Action |
|---|---|
j / k / Up / Down |
Navigate menu |
Enter |
Execute |
Available tools:
- Switch Profile — select from
~/.aws/configprofiles - Switch Region — change AWS region
- Login — SSO login
- Resolve URL — trace DNS to backend resource
- Test Port — check if a tunnel port is open
- Stop All Tunnels — kill all SSM sessions
VPN Tab
| Key | Action |
|---|---|
j / k / Up / Down |
Navigate menu |
Enter |
Execute |
r |
Refresh status |
Available actions:
- Connect — enter MFA code and connect to VPN
- Disconnect — stop active VPN session
- Setup — configure SSO credentials and .ovpn path (multi-step wizard)
- Status — check VPN connection state, IP, and PID
Reverse Proxy
The --proxy flag on tunnel-url sets up nginx so the original hostname works in your browser over the SSM tunnel.
How It Works
- Writes a site config to nginx (
proxy_passto the tunnel's local port) - Adds a
/etc/hostsentry pointing the hostname to127.0.0.1 - Reloads nginx and flushes the DNS cache
awsx2 tunnel-stopcleans everything up automatically
Platform Support
| macOS (Homebrew) | Linux (Debian/Ubuntu) | Linux (RHEL/CentOS) | |
|---|---|---|---|
| Config path | /opt/homebrew/etc/nginx/servers/ |
sites-available/ + symlink to sites-enabled/ |
/etc/nginx/conf.d/ |
| Nginx reload | nginx -s reload |
systemctl reload nginx |
systemctl reload nginx |
| DNS flush | dscacheutil + mDNSResponder |
resolvectl / systemd-resolve |
resolvectl / nscd |
nginx Installation
# macOS
brew install nginx
# Debian / Ubuntu
sudo apt install nginx
# RHEL / CentOS / Amazon Linux
sudo yum install nginx
Architecture
awsx2
├── main.rs # Entry point, CLI (clap) + TUI event loop
├── aws.rs # AWS CLI wrapper (EC2, SSM, ALB, SG, DNS)
├── tunnel.rs # SSM tunnel lifecycle (start, detect, stop, probe)
├── proxy.rs # nginx reverse proxy + /etc/hosts management
├── vpn.rs # Client VPN with SAML auth (headless Chrome, config persistence)
├── models.rs # Domain types (Instance, TunnelProcess, VpnConfig, etc.)
├── error.rs # Error types (AppError enum with thiserror)
└── tui/
├── app.rs # Application state, background task channels
├── ui.rs # Layout, colors, popup rendering
└── pages/
├── instances.rs # Instances tab (table + key handlers)
├── tunnels.rs # Tunnels tab (table + creation wizards)
├── tools.rs # Tools tab (menu + actions)
└── vpn.rs # VPN tab (connect, disconnect, setup)
Key design decisions:
- Shells out to
awsCLI rather than using the AWS SDK — leverages existing SSO/credential configuration with zero extra setup - Tunnels are detached child processes, discovered by parsing
psoutput forsession-manager-plugin - TUI runs background operations on threads, communicates via
mpscchannels - No runtime dependencies beyond the AWS CLI and session manager plugin
Dependencies
| Crate | Purpose |
|---|---|
ratatui |
Terminal UI framework |
crossterm |
Terminal I/O (raw mode, key events) |
clap |
CLI argument parsing with env var support |
serde + serde_json |
AWS CLI JSON output parsing |
thiserror |
Error type derivation |
libc |
Unix signal handling (SIGTERM for tunnel cleanup) |
headless_chrome |
Chrome DevTools Protocol for SAML browser automation |
tiny_http |
Lightweight HTTP server for SAML callback listener |
regex |
Parsing SAML URL and session ID from OpenVPN output |
url |
URL parsing for SAML form data extraction |
dirs |
Platform-correct config directory (~/.config/awsx2/) |
tempfile |
Secure temporary files for OpenVPN configs and credentials |
exec |
Unix exec replacement for SSM proxy (replaces process without forking) |
Environment Variables
| Variable | Used by |
|---|---|
AWS_PROFILE |
Default profile for all AWS operations |
AWS_DEFAULT_REGION |
Default region |
INSTANCE_NAME |
Default instance name for CLI commands |
License
MIT
Dependencies
~14–30MB
~434K SLoC