跳到正文
DEV Community· Morgan Seznec·· 4 小時前AI 評分55

hop 如何免去複製 EC2 執行個體 ID,以及 CLI 為何拒絕猜測目標

How I stopped copying EC2 instance IDs (and why my CLI refuses to guess)

AI 導讀

Morgan Seznec 開發的 hop CLI 可跨多個 AWS 帳戶及區域搜尋 EC2 執行個體,並透過 Session Manager 開啟 shell,免去逐一查找及輸入執行個體 ID。

正文

I work across a lot of AWS accounts. Reaching one machine used to take several steps: remember which account it lives in, find the matching profile in ~/.aws/config, check the region, look up the instance ID in the console or with aws ec2 describe-instances, and finally type:

aws ssm start-session --target i-0ee8781d10780ec32 --profile acme-prod --region eu-west-3

A few times a day, over fifteen accounts and three regions, that adds up. I wrote some shell functions to shorten it. They kept growing, and they became hop.

hop listing a fictional fleet, choosing between two matches, then connecting by IP

Searching every account at once

hop reads every profile in ~/.aws/config and ~/.aws/credentials and queries each one in its own region. The queries run in parallel, 16 at a time, and the result stays in a local cache for 15 minutes. A fleet of a few dozen accounts comes back in a few seconds the first time, and instantly after that.

Then you type whatever you remember about the machine:

hop shop app        # words of its name
hop 10.90.2.73      # a private IP, copied from an alert
hop i-0ee8781d...   # an instance ID
hop                 # a fuzzy picker over the whole fleet

hop ls shows what it found, with the profile and region of each instance:

$ hop ls
  NAME          PROFILE           REGION          ENV   IP           AGENT   LOGGING
  shop-app      acme-prod         eu-west-3       prod  10.83.2.182  online  yes
  grafana       globex-prod       us-east-1       prod  10.90.2.73   online  yes
  tps-api       initech-test      ap-southeast-2  test  10.68.3.138  online  yes
  ...
26 instances, 9 profiles, regions eu-west-3, eu-west-1, us-east-1, us-west-2, eu-central-1, ap-southeast-2

The shell goes through Session Manager. The instance needs the SSM agent and an instance role; port 22 can stay closed, and there are no SSH keys to hand out.

Why it refuses to guess

A tool that opens shells on production servers should not pick a machine on its own when the query is vague, and most of the design work went there.

hop connects without asking only when exactly one instance matches strongly: its exact name, ID or IP, or whole words of a single name. Everything looser goes through you.

  • When two instances share the words, like shop-app in production and shop-app-staging, hop opens the picker with both.
  • A typo such as shop-ap makes hop ask whether you meant shop-app.
  • A private IP has to match exactly, so 10.0.1.2 never lands on 10.0.1.21. The same private IP can also exist in two accounts, so hop run and hop push ask before acting on an IP when several profiles are in scope.
  • Without a terminal (a script, a cron job, ssh's ProxyCommand), hop has nobody to ask. It prints the candidates and stops:
$ hop run "shop app prod" uptime < /dev/null
hop: "shop app prod" only partly matches shop-app (acme-prod, eu-west-3): give its full name, ID or IP, or narrow with -p, -r or -e (no terminal to confirm)

The cache brings its own risk. An instance can be replaced between two refreshes, and its old name or IP can then belong to another machine. So when the data for an instance is more than a minute old, hop looks it up again in its account before acting. If it is gone, stopped, renamed or has a new IP, hop says what changed and searches again:

hop: shop-app (i-0ee8781d10780ec32, acme-prod, eu-west-3) is now stopped: searching again

Knowing whether the session is recorded

Session Manager can record every shell to CloudWatch Logs or S3. The setting lives in the SSM-SessionManagerRunShell document, once per account and per region, and it often differs from one account to the next. hop reads it along with the inventory and tells you before the shell opens:

$ hop shop app
hop: session LOGGED on shop-app (i-0ee8781d10780ec32, acme-prod, eu-west-3) to /ssm-logs. Everything that follows is recorded.

On an account where no destination is set, hop warns and asks Open anyway? [y/N]. With transcript: require in its configuration, it refuses those sessions.

SSO across many accounts

With IAM Identity Center, dozens of profiles often share one portal and one token. hop groups the profiles by portal, so one hop login signs in to every account behind it. It also checks the token before connecting, and when it has expired, it offers to open the portal right away.

A profile can be defined twice, with SSO in config and with keys in credentials. The AWS CLI then uses SSO, while the Go SDK on its own would pick the keys. hop does what the CLI does. hop doctor lists these profiles, along with expired tokens, long-lived keys and profiles that need an MFA code.

The other commands

  • hop run tools uptime runs a command and returns its exit code. If you stop waiting, hop cancels a command the instance has not picked up yet, so it does not run later behind your back.
  • hop tunnel tools 5432 15432 --host db.internal forwards a port, here to a database that only the instance can reach.
  • hop push ./app.conf tools /etc/app.conf copies a small file and compares the SHA-256 on both sides.
  • hop init ssh >> ~/.ssh/config sends ssh ec2-user@tools.hop, scp and rsync through Session Manager as well.

GCP support is experimental: with gcp_projects in the configuration, hop lists Compute Engine instances across your projects and opens shells on them through IAP. It only does shells there for now. If you would use it, or want Azure, tell me in this discussion.

A release you can check

hop opens shells on your servers, so what you install should be verifiable. Each release has its checksums signed with Sigstore from the GitHub Actions run, SLSA level 3 provenance, and GitHub attestations for the archives and the Docker image:

gh attestation verify hop_0.3.1_linux_amd64.tar.gz -R morganseznec/hop
slsa-verifier verify-artifact --provenance-path hop.intoto.jsonl \
  --source-uri github.com/morganseznec/hop --source-tag v0.3.1 hop_0.3.1_linux_amd64.tar.gz

Trying it

On macOS:

brew install --cask morganseznec/tap/hop-cli

Linux packages (deb, rpm, apk, Arch), Windows archives and a Docker image are on the releases page, and go install github.com/morganseznec/hop/cmd/hop@latest works too. The README lists the IAM permissions hop needs.

The code is on GitHub under the MIT license: https://github.com/morganseznec/hop. I would like to hear from people who manage many accounts, especially about what is missing for your setup.

Built with Claude Code. This article was written with Claude.

來源:DEV Community · dev.to