🐄

[AWS Session Manager] .bashrcと.ssh/configで快適なSSH環境を作る

2024/10/25に公開

はじめに

AWS Session Managerを使ってEC2にアクセスする場合、通常はaws ssm start-sessionコマンドを利用します。これは毎回インスタンスIDを指定する必要があり、非常に面倒です。

今回は、.bashrc.ssh/config、そして、インスタンス名を工夫することで、インスタンスIDを直書きする静的な設定を書くことなく、通常のSSHと同じような使い心地でSession Manager経由のアクセスを実現する方法を紹介します。

前提条件

以下のような状況・条件を想定しています。

AWS環境の構成

  1. 複数の環境(development/staging等)が存在する

    • 例:開発環境(development)、ステージング環境(staging)
    • 各環境用に別々のAWSアカウントを推奨
  2. EC2インスタンスの命名規則

    • インスタンス名に環境名が含まれていること
    • 例:myservice-webapp-development, myservice-backend-staging
    • フォーマット: {サービス名}-{役割}-{環境名}
  3. EC2インスタンスでSession Managerが有効化されている

  4. EC2インスタンスの~/.ssh/authorized_keysに接続元の公開鍵が登録済み

クライアント側のシステム要件

  1. クライアントOSはmacOS/Linux

    • 筆者はLinuxで動作確認しましたが、多分macOSでも動きます。
  2. シェルはbash

  3. bash-completionが有効化されている

  4. AWS CLIのプロファイル設定

    • 環境ごとに異なるプロファイルが設定されている
    • 例:myservice-development, myservice-staging
    • ~/.aws/credentialsに適切な認証情報が設定済み
  5. 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インスタンスの命名規則を定めておけば、環境の切り替えも簡単に行えます。

Urth

Discussion