zshで楽にAWS EC2インスタンスにsshログインしたい

みなさんさようなら.

仕事でも家でもAWSを使っていて,よくsshログインをしなければならない局面がある. で,高度に自動化されたAWSだと,Autoscaling Groupを使ってEC2インスタンスを自動で生み出したり,また自動で落としたりするよね. ECSを使っていても,裏側にはAutoscaling Groupを用意しておいて,インスタンスが足らなくなったら補充したりする.

で,そういうインスタンスに全てEIPを振ったり,固定のAレコードをつけたりしますか?

俺はめんどくさくてやってません(EIPはインスタンスに割り当てられてないと課金されるしね).

そうなると自然と,sshログインする際に「今どんなインスタンスが生きてるんだろー」って確認して,ターゲットのインスタンスのIPをコピーしてきてターミナルに貼り付けたりする.

めんどくさい.ああめんどくさい,めんどくさい.

この作業だけで,ブラウザを開く -> AWSのコンソールにログインする -> EC2インスタンスを探し出す -> IPをコピーする -> ターミナルに戻ってsshコマンドを組み上げるというだけの作業をやらなきゃいけない.AWSアカウントに二段階認証をつけていたりすると,コンソールにログインするだけでめんどくさい.

pecoとかpercolを使ってなんとかする

この悩みはみんな当たるらしく,

qiita.com

qiita.com

みんな自作の関数を公開してくれている.

俺も今までこれらの例を参考に自分で関数を作っていた.

proxyを踏み台にしたい

管理するサーバ台数が多くなってくると,今度は個人ユーザを各サーバに配置するのがめんどくさくなる. セキュリティ的にも,いろんな人の公開鍵がアプリケーションサーバに埋め込まれてるのは嬉しくないし,会社だと人が辞めたり入ってきたりして,そのたびに全台のユーザ削除や追加を行わなければならない.

そうすると,自然とプロキシサーバみたいなものを作って,それを踏み台にしてアプリケーションサーバにログインする構造を作りたくなる.そうすれば,ユーザの管理はプロキシサーバでのみ行えばよくて,人が辞めたり入ってきた場合でもプロキシサーバでユーザ削除・追加を行えば十分になる.

となると,ログインする際にはプロキシを踏み台にする必要がある. いろんな場所のIPが固定されているなら,~/.ssh/config あたりに書けば良いが,プロキシサーバすらもchefで作ったりして,たまにインスタンスごと作りなおしたりする.

となると,先ほどの関数,プロキシ経由でも使いたいぞ.

zsh-ec2ssh

というわけで,作った.そしてそろそろプラグインにしてみた.

github.com

もちろん,プロキシを使わずに,単にリストアップしたEC2インスタンスにログインするだけの関数も提供している.

f:id:h3poteto:20180203192910g:plain

インストール方法はREADMEに書いているけど,zplugとか使うと楽だよ.

単にsshログインしたい

こんな~/.zshrc を書く.

AWS_PROFILE_NAME=default
AWS_DEFAULT_REGION=ap-northeast-1
SSH_USER=h3poteto
SSH_PRIVATE_KEY_PATH=$HOME/.ssh/id_rsa

function zsh-ec2ssh-default() { zsh-ec2ssh $AWS_PROFILE_NAME $AWS_DEFAULT_REGION $SSH_USER $SSH_PRIVATE_KEY_PATH }
zle -N zsh-ec2ssh-default
bindkey '^t' zsh-ec2ssh-default # Ctrl + t

proxyを踏み台にしてsshしたい

こっちはちょっと複雑.

AWS_PROFILE_NAME=production
AWS_DEFAULT_REGION=ap-northeast-1
SSH_USER=h3poteto
AWS_PROXY_PROFILE=proxy
SSH_PROXY_USER=proxy-login-user
SSH_PRIVATE_KEY_PATH=$HOME/.ssh/id_rsa

function zsh-ec2ssh-production-proxy() { zsh-ec2ssh-with-proxy $AWS_PROFILE_NAME $AWS_DEFAULT_REGION $SSH_USER $AWS_PROXY_PROFILE $SSH_PROXY_USER $SSH_PRIVATE_KEY_PATH }
zle -N zsh-ec2ssh-production-proxy
bindkey '^p' zsh-ec2ssh-production-proxy # Ctrl + p

これを発動すると,まず,AWS_PROXY_PROFILE で指定されたAWSアカウント内のインスタンスをリストアップする.この中から,踏み台にしたいサーバを選択する. 次に,AWS_PROFILE_NAME で指定されたAWSアカウント内のインスタンスがリストアップされる.ここから,ログインしたいサーバを選択する.

profileを分けて指定させたのは,プロキシサーバを必ずしも同じAWSアカウント内に作っていないパターンがあったため(実体験,でもよくなかったとは思ってる).

このときのSSH_PRIVATE_KEY_PATHはプロキシサーバへのログインに必要な秘密鍵の場所を指定する. プロキシサーバ->アプリケーションサーバのログイン時の鍵指定には対応していない(けどこれって普通にプロキシサーバ作ったらだいたい$HOME/.ssh/id_rsaとかでログインできるように作るんじゃないかな?という期待).

同じくSSH_PROXY_USERはプロキシサーバへログインする際のユーザ名. プロキシサーバ->アプリケーションサーバのログイン時のユーザはSSH_USERで指定する.

あと,ちなみにこのへんの値は,だいたいデフォルトを環境変数から読むようになっていて,$AWS_DEFAULT_PROFILEとか$AWS_DEFAULT_REGIONとか$USERとかが設定されていると,そのへんをデフォルトとして使うようにしてある.

依存に入っているpecoはいいけどmyawsってなに?

友達が作っているコマンドラインツールで, A human friendly AWS Client written in Go らしい.

awscliでもいいんだけど(というか昔はawscliを使っていた),これが出してくる情報が多すぎて,jq等を使ってフィルタリングしないといけない.これが結構めんどくさい上に,依存がひとつ増えてしまう. 対して,myawsの場合,出力するものを割と自由に指定できる(出力のfields指定ができる)のと,デフォルトのままで結構見やすい.その上goのバイナリなのでシングルバイナリになっている.

というわけで採用した.brewでインストールできるし!

github.com

StrictHostKeyChecking=noが気になる

はい,これは迷いどころで,askかyesにしたほうがいいというのもわかる. というかオプションで差し込めるようにしようかなーと思ったんだけど,まだ作ってない.どうしよう,やっぱり気になるかな.