はじめに
一般的な構成ならセキュリティを考慮してサービスを動かすホストには踏み台からしか接続出来ない制限を掛けている筈です。その結果サービスホストの細かい調査やチューニングを行いたい時には、一旦踏み台ホストに接続してから狙いのホストに接続する必要があります。
この作業はメンテナンス中は結構頻発しますし、サービスが増える程多くなります。今がまさにそんな状態ですので、これを機にスクリプトを作っておきたいと思った次第です。fssh(仮)
とコマンドを入力すると踏み台から接続可能なホストの一覧が表示されて、その中から一つを選択するとsshでログインが可能という様な仕様のスクリプトを作りたいと思います。
準備
スクリプトを紹介する前に準備を整えていきます。ちなみに踏み台及びログインする各ホストはAWSを想定しています(AWS CLIも使います)。そうでない方は部分的に参考にするなどというスタンスでお読み下さい。
1. ssh出来る
まず踏み台ホストへ接続出来る。踏み台ホストから各ホストに接続出来るという環境を用意して下さい。つまりログイン認証用の秘密鍵・公開鍵を配置しておいて下さい。今回はローカルから踏み台への接続に使う秘密鍵はローカルに、踏み台から各ホストへの接続には踏み台ホストに存在しているという前提で話を進めます。
2. aws cliが使える
AWS CLIをローカル(または踏み台)で使用します。なのでAWS CLIをインストールしておいて下さい。インストール方法は公式ドキュメントが一番簡単です。
3. jqが使える
jqとはJSON形式のデータを整形してくれるかなりイケメンなライブラリです。AWS CLIで踏み台経由でログインするホスト情報の一覧を取得するのですが、このレスポンスがデフォルトだとJSON形式なのでパースするために使用します。
ご使用の端末にbrew
が入っていれば簡単にインストールが可能です。
4. fzfが使える
fzfとはフィジーファインダーと呼ばれる、出力結果のリストに選択UIを提供し、あいまい検索で選択出来るようにするものです(だと思います)。fzfの導入や使い方についてはこちらや公式リポジトリをご覧になって下さい。
スクリプト作成
最初にコードを見せてしまいます。下記のコードの内必要な部分をご自身の環境に合わせて修正を加えてから~/.zshrc
に追記してfssh
と実行すれば動作します。
fssh() {
SSH_IP=`aws ec2 describe-instances --query 'Reservations[].Instances[].{PrivateIp:PrivateIpAddress,Name:Tags[?Key==\`Name\`].Value}' |
jq -c '.[] | { name: .Name[0], ip: .PrivateIp }' | sort | fzf | jq -r '.ip'`
ssh -tt [踏み台ホスト] ssh -i [踏み台の秘密鍵のパス] [ユーザ名]@${SSH_IP}
}
関数の一行目ではAWS CLIアカウントに紐づくec2インスタンスのプライベートIPアドレスと名前を取得しています。単体の出力結果は以下のようになります。
$ aws ec2 describe-instances --query 'Reservations[].Instances[].{PrivateIp:PrivateIpAddress,Name:Tags[?Key==`Name`].Value}'
[
{
"PrivateIp": "10.0.0.1",
"Name": [
"EC2 Instance - hoge"
]
},
{
"PrivateIp": "10.0.0.2",
"Name": [
"EC2 Instance - moge"
]
}
]
上記の出力から、一番上の階層の角カッコを外し、一行ずつに纏めるためにjq -c '.[] | { name: .Name[0], ip: .PrivateIp }'
をパイプで繋ぎます。出力結果は次の様になります。
$ aws ec2 describe-instances --query 'Reservations[].Instances[].{PrivateIp:PrivateIpAddress,Name:Tags[?Key==`Name`].Value}' | jq -c '.[] | { name: .Name[0], ip: .PrivateIp }'
{"name":"EC2 Instance - hoge","ip":"10.0.0.1"}
{"name":"EC2 Instance - moge","ip":"10.0.0.2"}
上記の結果にソートを掛けてから、fzfで検索を行えるようにして、選択した行からIPアドレスだけを出力するようにします。先程のコマンドに更にsort | fzf | jq -r '.ip'
をパイプで繋いでください。出力結果は言わずもがな選択した行のIPアドレスが出力されます。
$ aws ec2 describe-instances --query 'Reservations[].Instances[].{PrivateIp:PrivateIpAddress,Name:Tags[?Key==`Name`].Value}' | jq -c '.[] | { name: .Name[0], ip: .PrivateIp }' | sort | fzf | jq -r '.ip'
10.0.0.2
そして最後の行についてですが、踏み台sshの設定が~/.ssh/config
に書かれているという想定ですが、そうでない方は以下のコマンドに置き換えてください。
$ ssh -tt [ユーザ名]@[踏み台のホスト名] -p [ポート番号] -i [ローカルの秘密鍵] ssh -i [踏み台の秘密鍵] [ユーザ名]@[ホスト名]
以上です。
終わりに
白状するとjqを使うのは今回が初めてでした。JSONのパースに便利という噂だけは聞いていましたが、実際使ってみるととても良い使用感です。今まで地道にシェルで頑張っていた作業を大分簡略化出来そうです。