[AWS Session Manager] .bashrcと.ssh/configで快適なSSH環境を作る
はじめに
AWS Session Managerを使ってEC2にアクセスする場合、通常はaws ssm start-session
コマンドを利用します。これは毎回インスタンスIDを指定する必要があり、非常に面倒です。
今回は、.bashrc
と.ssh/config
、そして、インスタンス名を工夫することで、インスタンスIDを直書きする静的な設定を書くことなく、通常のSSHと同じような使い心地でSession Manager経由のアクセスを実現する方法を紹介します。
前提条件
以下のような状況・条件を想定しています。
AWS環境の構成
-
複数の環境(development/staging等)が存在する
- 例:開発環境(development)、ステージング環境(staging)
- 各環境用に別々のAWSアカウントを推奨
-
EC2インスタンスの命名規則
- インスタンス名に環境名が含まれていること
- 例:
myservice-webapp-development
,myservice-backend-staging
- フォーマット:
{サービス名}-{役割}-{環境名}
-
EC2インスタンスでSession Managerが有効化されている
-
EC2インスタンスの~/.ssh/authorized_keysに接続元の公開鍵が登録済み
クライアント側のシステム要件
-
クライアントOSはmacOS/Linux
- 筆者はLinuxで動作確認しましたが、多分macOSでも動きます。
-
シェルはbash
-
bash-completionが有効化されている
-
AWS CLIのプロファイル設定
- 環境ごとに異なるプロファイルが設定されている
- 例:
myservice-development
,myservice-staging
-
~/.aws/credentials
に適切な認証情報が設定済み
-
AWS CLI用のSession Managerプラグインがインストール済み
SSH補完機能
まず、~/.bashrc
に以下のようなSSH補完用の関数を追加します。この設定により、インスタンス名でのタブ補完が可能になります。
AWSプロフィールは登録しているものに変えてください。
_aws_ssh_complete() {
local cur opts_development opts_staging cache_file_development cache_file_staging cache_expire_time
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
cache_file_development="/tmp/aws_ssh_instances_myservice_development_cache"
cache_file_staging="/tmp/aws_ssh_instances_myservice_staging_cache"
cache_expire_time=300 # 300秒 (5分)
if [[ -f "${cache_file_development}" && $(($(date +%s) - $(stat -c %Y "${cache_file_development}"))) -lt ${cache_expire_time} ]]; then
opts_development=$(cat "${cache_file_development}")
else
# AWS CLIでインスタンスの名前を取得し、キャッシュに保存
opts_development=$(aws ec2 describe-instances \
--profile myservice-development \
--query 'Reservations[*].Instances[*].{Name:Tags[?Key==`Name`]|[0].Value}' \
--output text)
echo "${opts_development}" > "${cache_file_development}"
fi
if [[ -f "${cache_file_staging}" && $(($(date +%s) - $(stat -c %Y "${cache_file_staging}"))) -lt ${cache_expire_time} ]]; then
opts_staging=$(cat "${cache_file_staging}")
else
opts_staging=$(aws ec2 describe-instances \
--profile myservice-staging \
--query 'Reservations[*].Instances[*].{Name:Tags[?Key==`Name`]|[0].Value}' \
--output text)
echo "${opts_staging}" > "${cache_file_staging}"
fi
COMPREPLY=( $(compgen -W "${opts_development} ${opts_staging}" -- ${cur}) )
return 0
}
complete -F _aws_ssh_complete ssh
この補完機能には以下のような特徴があります:
- AWS CLIを使ってEC2インスタンス名を取得
- Tab補完時のパフォーマンス向上のため、結果を5分間キャッシュ
- development/staging環境それぞれのインスタンス一覧に対応
- 各環境用のAWS CLIプロファイルを使用
SSHの設定
次に、~/.ssh/config
に以下の設定を追加します。
ユーザ名は適切なものに変えてください。
host myservice-*-development
ProxyCommand sh -c "AWS_PROFILE=myservice-development aws ssm start-session --target $(aws ec2 describe-instances --filters 'Name=tag:Name,Values=%h' --query 'Reservations[0].Instances[0].InstanceId' --output text --profile myservice-development) --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
User ec2-user
host myservice-*-staging
ProxyCommand sh -c "AWS_PROFILE=myservice-staging aws ssm start-session --target $(aws ec2 describe-instances --filters 'Name=tag:Name,Values=%h' --query 'Reservations[0].Instances[0].InstanceId' --output text --profile myservice-staging) --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
User ec2-user
ポイントは以下の通りです:
- ProxyCommandでSession Manager経由のSSH接続を実現
- ホスト名パターン(
myservice-*-{environment}
)で環境を区別 - 環境ごとに適切なAWSプロファイルを使用
使用方法
設定が完了したら、以下のように通常のSSHコマンドでEC2インスタンスに接続できます:
$ source ~/.bashrc
$ ssh myservice-webapp-development # developmentのwebappインスタンスに接続
$ ssh myservice-api-development # developmentのapiインスタンスに接続
$ ssh myservice-backend-staging # stagingのbackendインスタンスに接続
インスタンス名は途中まで入力してTabキーを押すことで補完できます。
初回はaws-cliが実行されるので少し待ちますが、2回目以降からは高速に補完できます。
まとめ
.bashrc
と.ssh/config
を工夫することで、Session Manager経由のSSH接続を通常のSSHと同じように扱えるようになりました。これによりセキュアに最小限の設定でSSHができます。
特に複数環境がある場合でも、EC2インスタンスの命名規則を定めておけば、環境の切り替えも簡単に行えます。
Discussion