An open API service indexing awesome lists of open source software.

https://github.com/maayanyosef/herdr-aws-ssm

Pick an EC2 instance and connect over AWS SSM in a herdr --remote session - no bastion or public IP.
https://github.com/maayanyosef/herdr-aws-ssm

aws-ssm herdr herdr-plugin terminal

Last synced: 25 days ago
JSON representation

Pick an EC2 instance and connect over AWS SSM in a herdr --remote session - no bastion or public IP.

Awesome Lists containing this project

README

          

# herdr-aws-ssm

[![CI](https://github.com/maayanyosef/herdr-aws-ssm/actions/workflows/ci.yaml/badge.svg)](https://github.com/maayanyosef/herdr-aws-ssm/actions/workflows/ci.yaml)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
![Bash 3.2+](https://img.shields.io/badge/bash-3.2%2B-4EAA25.svg)
![herdr 0.7+](https://img.shields.io/badge/herdr-0.7%2B-8a2be2)
![platforms: linux • macOS](https://img.shields.io/badge/platforms-linux%20%E2%80%A2%20macOS-informational)

**Connect to your EC2 instances over AWS SSM without leaving your terminal — pick
an instance from a fuzzy list and drop into a full [herdr](https://herdr.dev)
`--remote` session, tunneled through Session Manager.** No bastion, no public IP,
no long-lived SSH keys: authentication uses short-lived EC2 Instance Connect keys,
and the right SSH user is detected from each instance's AMI. Works with any AWS
account using your existing CLI profiles.

## Why you'd want it

- **`herdr --remote`, over SSM.** You get herdr full thin client — remote herdr
install, clipboard bridge, persistent session that survives detach/reattach —
but the transport is an SSM `AWS-StartSSHSession` tunnel instead of a reachable
SSH endpoint. Private-subnet boxes with no inbound work fine.
- **No keys to manage.** Each connection pushes an ephemeral EC2 Instance Connect
key (~60s), then opens the session. Nothing persists on the instance, nothing
sits in your repo.
- **The right user, automatically.** Ubuntu → `ubuntu`, Amazon Linux → `ec2-user`,
Debian → `admin`, … detected from the instance's AMI so you don't have to
remember per-image logins.
- **Safe with production.** Any profile you label `prod` is flagged in the picker
and requires a typed `yes-prod` before it connects — the gate fails closed.
- **Zero config to start.** Uses your current AWS profile/region out of the box;
point it at more accounts when you want. Pure Bash, no build step,
[hardened](SECURITY.md) around your credentials.

## What it does

- **Discover across accounts** — lists running instances for every profile you
configure (Name tag, id, type, AZ), and marks each with its SSM reachability
(`ssm:Online`) so you don't pick a target the agent can't reach.
- **Pick fast** — a fuzzy picker (`fzf` if installed, a numbered menu otherwise);
`prod`- labeled targets are flagged and gated behind a typed confirmation.
- **Detect the SSH user** — resolves the login user from the picked instance's
AMI and connects as `herdr --remote @`, so the login user always
matches the ephemeral key that was pushed.
- **Install the transport once** — writes a managed `~/.ssh/config` block that
routes `Host i-* mi-*` through the SSM ProxyCommand, atomically and
idempotently; after that even a bare `herdr --remote i-…` tunnels over SSM.
- **Check your setup** — `doctor` verifies the AWS CLI, Session Manager plugin,
`herdr`, and that each profile's credentials are live.

## Quick start

Prereqs: AWS CLI v2 + the Session Manager plugin installed (see
[below](#installing-the-session-manager-plugin)), and a herdr 0.7+.

```bash
# 1. Install the plugin.
herdr plugin install maayanyosef/herdr-aws-ssm

# 2. (optional) Point it at your AWS profiles. With no config it uses your
# current AWS context ($AWS_PROFILE/$AWS_REGION). To search specific
# accounts, drop a config.env in the plugin's config dir (printed on install):
mkdir -p ~/.config/herdr/plugins/config/herdr-aws-ssm
cat > ~/.config/herdr/plugins/config/herdr-aws-ssm/config.env <<'EOF'
HERDR_SSM_PROFILES="dev=my-dev-profile prod=my-prod-profile"
HERDR_SSM_REGION="us-east-1"
HERDR_SSM_OSUSER="auto"
EOF

# 3. Authenticate to AWS (any profile the picker will list).
aws sso login --profile my-dev-profile

# 4. Install the ssh-config transport (once), then preflight.
herdr plugin action invoke setup --plugin herdr-aws-ssm
herdr plugin action invoke doctor --plugin herdr-aws-ssm
```

`doctor` should report `ok` for `aws` / `session-manager-plugin` / `herdr` and
`ok sso ` for each logged-in profile. Action output goes to the herdr plugin
log rather than your terminal; to see the results directly, run the installed
script (its path is shown by `herdr plugin list`), e.g.
`bash ~/.config/herdr/plugins/github/herdr-aws-ssm-*/bin/doctor.sh`.

**5. Connect.** `connect` is interactive (it shows a picker, then hands off to
`herdr --remote`), so run it where it has a terminal — **bind a key** and press
it inside herdr (recommended), rather than a detached `plugin action invoke`:

```toml
# ~/.config/herdr/config.toml
[[keys.command]]
key = "prefix+e" # pick any free combo
type = "plugin_action"
command = "herdr-aws-ssm.connect"
description = "SSM connect to an EC2 instance"
```

Run `herdr server reload-config`, press your key, pick an instance — you're in.
(No keybinding is forced by the plugin, to avoid colliding with a herdr built-in.)

Once `setup` has run, a bare `herdr --remote ` also works, e.g.
`herdr --remote i-0123456789abcdef0`. Production targets (any profile labelled
`prod`) require typing `yes-prod` before they connect.

## Actions

| Action | id | What it does |
|----------------------------------|-----------|-------------------------------------------------------------------------------------|
| **SSM connect (herdr --remote)** | `connect` | List instances → pick → detect user → confirm prod → `herdr --remote @` |
| **SSM: install ssh config** | `setup` | Write the managed `~/.ssh/config` block + a starter config; run once |
| **SSM: doctor / preflight** | `doctor` | Verify AWS CLI, `session-manager-plugin`, `herdr`, and live credentials per profile |

## How it works

1. **`setup`** writes an `~/.ssh/config` block routing `Host i-* mi-*` through
`bin/proxy.sh`. The write is atomic (temp file + `mv`) and idempotent (a
delimited managed block), so it never duplicates or truncates your config.
2. **`bin/proxy.sh`** (the ssh `ProxyCommand`) pushes an ephemeral public key with
`ec2-instance-connect send-ssh-public-key`, then execs
`aws ssm start-session --document-name AWS-StartSSHSession`. ssh runs its
handshake over that SSM channel.
3. **`connect`** lists instances across your profiles, lets you pick one, detects
the SSH user from its AMI, gates production, and launches
`herdr --remote @` — so ssh's login user and the pushed key agree.

## Prerequisites

- AWS CLI v2 + `session-manager-plugin` (see below); `fzf` optional (numbered
menu otherwise).
- An authenticated AWS profile (`aws sso login --profile

`, or any credential
source the AWS CLI understands).
- Instances: SSM agent running + an instance profile with
`AmazonSSMManagedInstanceCore`.
- IAM: `ssm:StartSession` (with the `AWS-StartSSHSession` document) and
`ec2-instance-connect:SendSSHPublicKey`.

### Installing the AWS CLI

AWS CLI v2 install instructions (all platforms):

```bash
# macOS (Homebrew)
brew install awscli
```

Verify with `aws --version` (expect `aws-cli/2.x`).

### Installing the Session Manager plugin

`aws ssm start-session` needs the Session Manager plugin installed locally. Full
per-OS instructions:

```bash
# macOS (Homebrew)
brew install --cask session-manager-plugin

# Debian / Ubuntu (x86_64)
curl -o /tmp/session-manager-plugin.deb \
"https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_64bit/session-manager-plugin.deb"
sudo dpkg -i /tmp/session-manager-plugin.deb

# RHEL / Amazon Linux (x86_64)
sudo dnf install -y \
"https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpm"
```

Verify with `session-manager-plugin --version`. `doctor` also checks for it.

## Configuration

All settings are optional. Unset values fall back to your current AWS context
(`$AWS_PROFILE` / `$AWS_REGION`) and sensible defaults — so it works with no
configuration at all.

| Var | Default | Meaning |
|----------------------|-----------------------------------------------------|---------------------------------------------|
| `HERDR_SSM_PROFILES` | `default=$AWS_PROFILE` (or `default`) | Space-separated `env=aws-profile` pairs |
| `HERDR_SSM_REGION` | `$AWS_REGION` → `$AWS_DEFAULT_REGION` → `us-east-1` | AWS region to search/connect in |
| `HERDR_SSM_OSUSER` | `auto` | SSH login user; `auto` detects from the AMI |

- **`HERDR_SSM_PROFILES`** — each `env` label is arbitrary. Any label named
exactly `prod` is treated as production and requires a typed `yes-prod`
confirmation before connecting. Example:
`HERDR_SSM_PROFILES="dev=my-dev-sso prod=my-prod-sso"`.
- **`HERDR_SSM_OSUSER=auto`** maps the instance's AMI to a login user
(Ubuntu → `ubuntu`, Amazon Linux → `ec2-user`, Debian → `admin`, …), falling
back to `ec2-user`. Set a fixed value to skip detection.

Set these two ways:

- **Local development:** copy `.env.example` to `.env` (git-ignored) and edit.
- **Installed plugin:** `setup` writes a `config.env` into the plugin's config
dir; edit it there.

## Security

The plugin runs as you, with your AWS credentials, and is not sandboxed. It uses
ephemeral keys, keeps no secrets in the repo, only calls read-only AWS APIs for
discovery, and gates production. See **[SECURITY.md](SECURITY.md)** for the full
threat model and how to report a vulnerability.

## Development

Pure Bash, no build step. The test suite uses a tiny in-repo harness (no `bats`)
and stubs `aws`/`herdr` on `PATH`, so it needs no AWS access:

```bash
for t in tests/*_test.sh; do bash "$t" || exit 1; done
```

CI runs the suite on Linux (bash 5) and macOS (bash 3.2, the compatibility floor)
and lints with `shellcheck`. Releases are cut by pushing a `vX.Y.Z` tag matching
`herdr-plugin.toml` (see `.github/workflows/`).

## License

[MIT](LICENSE) © herdr-aws-ssm contributors