🦔

pecoを使ったssh接続先を一覧表示するスクリプトを実装してみた

2023/01/02に公開

Introduction

pecoを使って踏み台サーバーから接続先EC2をリストアップし、ssh接続を自動化するec2-sshスクリプトを実装する

pecoとは?

pecoはLinuxやMacなどで利用できるフィルタリングコマンドツールである。
https://github.com/peco/peco

コマンド履歴の検索性能をあげたり、今回のように必要なインスタンス情報を
抽出して一覧表示してくれるようにしたりすることができる便利ツール

構成図

接続元アカウント(A)から接続先アカウント(B)で稼働しているEC2インスタンスの一覧をpecoで取得してみる

peco-001

事前準備

  • 事前にVPC間の接続およびEC2インスタンスが準備できていること
  • bastion01サーバー(踏み台サーバー)からtest001、test002サーバー間は事前にSSH接続ができるようになっていること
  • 今回はテストサーバーなので、以下スペックのインスタンスに統一
    • OS:Amazon Linux 2
    • インスタンスタイプ:t2.micro

How to

概要手順

  1. クロスアカウントロールの作成 @アカウントB
  2. bastion01用サーバーロール(インスタンスプロファイル)の作成 @アカウントA
  3. pecoのインストール @bastion01
  4. jqコマンドのインストール @bastion01
  5. ec2-sshスクリプトの配置 @bastion01

クロスアカウントロールの作成

  • アカウントB(EC2インスタンスをリストアップしたい対象先)のアカウントにてAssumeRoleを作成
  1. IAMのロール画面からロールを作成をクリック

    peco-002

  2. 以下パラメータを設定して「次へ」をクリック

    • 信頼されたエンティティタイプ:AWSアカウント
    • AWSアカウント:別のアカウント
    • アカウントID:アカウントAのID

    ※必要に応じてオプションを追加(今回は設定なし)

    peco-003

  3. 許可ポリシーにAmazonEC2ReadOnlyAccessを追加して「次へ」をクリック

    peco-004

  4. ロール名を入力して「ロールを作成」をクリック

    peco-005

  5. 作成完了

    peco-006

  6. 「信頼関係」タブから[信頼ポリシーを編集]をクリック

    peco-007

  7. Conditionに以下内容を追記して更新

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "AWS": "arn:aws:iam::アカウントAのID:root"
                },
                "Action": "sts:AssumeRole",
                "Condition": {
                    //以下内容を追記
                    "StringEquals": {
                        "sts:ExternalId": "test-ssh-bastion"
                    }
                }
            }
        ]
    }
    

    peco-008

bastion01用サーバーロール(インスタンスプロファイル)の作成 @アカウントA

  • アカウントAにて、bastion01サーバーからアカウントBのEC2インスタンス閲覧用権限を付与するためにIAMロールを作成
  1. IAMのポリシー画面から「ポリシーを作成」を選択

    peco-009

  2. AssumeRoleを許可

    peco-010

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "EC2SSHPolicy",
                "Effect": "Allow",
                "Action": "sts:AssumeRole",
                "Resource": "arn:aws:iam::741420225566:role/ec2-ssh-accept-role"
            }
        ]
    }
    
  3. 名前を入力して「ポリシーの作成」をクリック

    peco-011

  4. IAMのロール画面にて「ロールの作成」をクリック

  5. 信頼されたエンティティにEC2を選択

    peco-012

  6. 先ほど作成したポリシーを選択

    peco-013

  7. ロール名をつけて、「ロールを作成」をクリック

    peco-014

  8. ロールが作成されたので、これをbastion01インスタンスにアタッチをしましょう

  9. bastion01インスタンスを選択して「アクション」-「セキュリティ」-「IAMロールを変更」をクリック

    peco-016

  10. 作成したIAMロールを選択して「IAMロールの更新」をクリック

    peco-017

  11. アタッチされていることを確認

    peco-018

pecoのインストール

  1. Githubリポジトリからpecoをインストール(ここではx86_64の最新バージョンをインストール)

    [root@bastion01 ~]# wget https://github.com/peco/peco/releases/download/v0.5 10/peco_linux_amd64.tar.gz
    --2023-01-02 11:34:52--  https://github.com/peco/peco/releases/download/v0.5 10/peco_linux_amd64.tar.gz
    Resolving github.com (github.com)... 20.27.177.113
    Connecting to github.com (github.com)|20.27.177.113|:443... connected.
    HTTP request sent, awaiting response... 302 Found
    Location: https://objects.githubusercontent.com github-production-release-asset-2e65be/20553267 cbc7b300-c885-11eb-90e5-bd7ad29383d0?X-Amz-Algorithm=AWS4-HMAC-SHA256 X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20230102%2Fus-east-1%2Fs3%2Faws4_req est&X-Amz-Date=20230102T113452Z&X-Amz-Expires=300 X-Amz-Signature=eee259616e4478553ef122ee5a3c43f20acfc523d6e983fb4fb0025a0d56 863&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=20553267 response-content-disposition=attachment%3B%20filename%3Dpeco_linux_amd64.tar gz&response-content-type=application%2Foctet-stream [following]
    --2023-01-02 11:34:52--  https://objects.githubusercontent.com github-production-release-asset-2e65be/20553267 cbc7b300-c885-11eb-90e5-bd7ad29383d0?X-Amz-Algorithm=AWS4-HMAC-SHA256 X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20230102%2Fus-east-1%2Fs3%2Faws4_req est&X-Amz-Date=20230102T113452Z&X-Amz-Expires=300 X-Amz-Signature=eee259616e4478553ef122ee5a3c43f20acfc523d6e983fb4fb0025a0d56 863&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=20553267 response-content-disposition=attachment%3B%20filename%3Dpeco_linux_amd64.tar gz&response-content-type=application%2Foctet-stream
    Resolving objects.githubusercontent.com (objects.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ...
    Connecting to objects.githubusercontent.com (objects.githubusercontent.com) 185.199.110.133|:443... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 2204567 (2.1M) [application/octet-stream]
    Saving to: ‘peco_linux_amd64.tar.gz’ 
    100 [=========================================================================== =====================================>] 2,204,567   1.34MB/s   in 1.6s 
    2023-01-02 11:34:55 (1.34 MB/s) - ‘peco_linux_amd64.tar.gz’ saved [2204567 2204567] 
    ## インストールされている
    [root@bastion01 ~]# ll
    total 2156
    -rw-r--r-- 1 root root 2204567 Dec  7  2021 peco_linux_amd64.tar.gz
    
  2. ダウンロードしたファイルを解凍

    [root@bastion01 ~]# tar zxf peco_linux_amd64.tar.gz
    [root@bastion01 ~]# ll
    total 2156
    drwxr-xr-x 2 ec2-user ec2-user      50 Jun  8  2021 peco_linux_amd64
    -rw-r--r-- 1 root     root     2204567 Dec  7  2021 peco_linux_amd64.tar.gz
    [root@bastion01 ~]# ll peco_linux_amd64
    total 4008
    -rw-r--r-- 1 ec2-user ec2-user   18890 Jun  8  2021 Changes
    -rwxr-xr-x 1 ec2-user ec2-user 4049673 Jun  8  2021 peco
    -rw-r--r-- 1 ec2-user ec2-user   29754 Jun  8  2021 README.md
    
  3. 解凍したフォルダ内にpecoの実行ファイルが入っているので/usr/local/binに移動させましょう

    [root@bastion01 ~]# mv peco_linux_amd64/peco /usr/local/bin/
    [root@bastion01 ~]# ll/usr/local/bin/
    -bash: ll/usr/local/bin/: No such file or directory
    [root@bastion01 ~]# ll /usr/local/bin/
    total 3956
    -rwxr-xr-x 1 ec2-user ec2-user 4049673 Jun  8  2021 peco
    
  4. バージョン情報が表示されれば、pecoのインストールが完了

    [root@bastion01 ~]# peco --version
    peco version v0.5.10 (built with go1.16)
    

jqのインストール

  • peco実行時にEC2インスタンスの必要な情報を抽出するために、jqをインストールする

    [root@bastion01 ~]# yum install jq
    Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
    amzn2-core                                                                                                                          | 3.7 kB  00:00:00
    Resolving Dependencies
    --> Running transaction check
    ---> Package jq.x86_64 0:1.5-1.amzn2.0.2 will be installed
    --> Processing Dependency: libonig.so.2()(64bit) for package: jq-1.5-1.amzn2.0.2.x86_64
    --> Running transaction check
    ---> Package oniguruma.x86_64 0:5.9.6-1.amzn2.0.4 will be installed
    --> Finished Dependency Resolution
    
    Dependencies Resolved
    
    ===========================================================================================================================================================
    Package                            Arch                            Version                                      Repository                           Size
    ===========================================================================================================================================================
    Installing:
    jq                                 x86_64                          1.5-1.amzn2.0.2                              amzn2-core                          154 k
    Installing for dependencies:
    oniguruma                          x86_64                          5.9.6-1.amzn2.0.4                            amzn2-core                          127 k
    
    Transaction Summary
    ===========================================================================================================================================================
    Install  1 Package (+1 Dependent package)
    
    Total download size: 281 k
    Installed size: 890 k
    Is this ok [y/d/N]: y
    Downloading packages:
    (1/2): oniguruma-5.9.6-1.amzn2.0.4.x86_64.rpm                                                                                       | 127 kB  00:00:00
    (2/2): jq-1.5-1.amzn2.0.2.x86_64.rpm                                                                                                | 154 kB  00:00:00
    -----------------------------------------------------------------------------------------------------------------------------------------------------------
    Total                                                                                                                      1.9 MB/s | 281 kB  00:00:00
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
      Installing : oniguruma-5.9.6-1.amzn2.0.4.x86_64                                                                                                      1/2
      Installing : jq-1.5-1.amzn2.0.2.x86_64                                                                                                               2/2
      Verifying  : jq-1.5-1.amzn2.0.2.x86_64                                                                                                               1/2
      Verifying  : oniguruma-5.9.6-1.amzn2.0.4.x86_64                                                                                                      2/2
    
    Installed:
      jq.x86_64 0:1.5-1.amzn2.0.2
    
    Dependency Installed:
      oniguruma.x86_64 0:5.9.6-1.amzn2.0.4
    
    Complete!
    

ec2-sshスクリプトの配置

  • 作成するスクリプトではaws sts assume-roleコマンドを実行し、必要情報を取得できるようにする

  • 因みに、aws sts assume-roleコマンドでは対象のロールに対する一時認証情報を取得することができる

    [root@bastion01 ~]# aws sts assume-role --role-session-name test-ssh --role-arn arn:aws:iam::${アカウントBのID}:role/ec2-ssh-accept-role --external-id test-ssh-bastion
    {
        "AssumedRoleUser": {
            "AssumedRoleId": "AROA2ZIAW2QPO4P6NMAPX:test-ssh",
            "Arn": "arn:aws:sts::${アカウントBのID}:assumed-role/ec2-ssh-accept-role/test-ssh"
        },
        "Credentials": {
            "SecretAccessKey": "5C9/VpDU9yWY8QITXV1goLnNh05GAptQvuneHNQN",
            "SessionToken": "FwoGZXIvYXdzEIX//////////wEaDCGJ4LGsqaUAUEUjliKsAWTBMJmJ9fsr2qTfRuUjGKQz8THi0QRpUd/535raO+RjSS4sT2T6JNqrTnlWavmzeh7jL8Q9d1niJjwXP7boziogsDpqagXv22+kZOVIKJvfexEUFlrcVzo7LgeDjsUiNSs3lVBzSzXY/9a9DNUmolDt+eF+83aE37dGVnCCOMvqZBHH9ZemG3C9DFALBWXUYgUx7ZFFHnuWQsmCDLG5gCdRC01DI4E7HrHZtGwoiorLnQYyLaYJCTzb8Bmu+lrsk/dwO35t5Yvn01IoEF0WdAWKmWMrHfgI+wxno3aklPoQ7w==",
            "Expiration": "2023-01-02T12:50:34Z",
            "AccessKeyId": "ASIA2ZIAW2QPAD5SRIVV"
        }
    }
    
  1. /etc/bashrcに以下内容を追記

    # For ssh list
    function ec2-ssh() {
      eval "$(aws sts assume-role --role-session-name test-ssh \
      --role-arn "arn:aws:iam::${アカウントBのID}:role/ec2-ssh-accept-role" --external-id test-ssh-bastion \
      --query '[Credentials.AccessKeyId, Credentials.SecretAccessKey, Credentials.SessionToken]' \
      --output text | (
      read AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SECURITY_TOKEN
      export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SECURITY_TOKEN
      declare -p AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SECURITY_TOKEN))"
    
      local user=`whoami`
      local host=$(aws ec2 describe-instances --region ap-northeast-1 --output json --filters "Name=instance-state-code,Values=16" | jq -r '.Reservations[].Instances[] | [.Tags[] | select(.Key == "Name").Value][] + "\t" +  .InstanceType + "\t" + .PrivateIpAddress + "\t" + .Platform' | awk '{if ($4 != "windows") printf "%-45s %-15s %-10s\n",$1,$2,$3}' | sort | /usr/local/bin/peco | awk '{print $3}')
      ssh "$user@$host"
    }
    
  2. /etc/bashrcsourceコマンドで再適用

    [root@bastion01 ~]# source /etc/bashrc
    
  3. 以上でセットアップ完了。ec2-sshと打つとアカウントBの稼働中インスタンス一覧が表示される。
    選択するとそのインスタンスにssh接続できるようになる

    ec2-user@bastion01 ~]$ ec2-ssh
    QUERY>                                                                                                                                 IgnoreCase [2 (1/1)]
    test001                                       t2.micro        10.100.1.133
    test002                                       t2.micro        10.100.1.129
    
    Last login: Mon Jan  2 11:31:47 2023 from ip-10-0-0-4.ap-northeast-1.compute.internal
    
           __|  __|_  )
           _|  (     /   Amazon Linux 2 AMI
          ___|\___|___|
    
    https://aws.amazon.com/amazon-linux-2/
    [ec2-user@test001 ~]$
    

Commentary

[ec2-user@bastion01 ~]$ ssh-keygen -t ecdsa -b 521
Generating public/private ecdsa key pair.
Enter file in which to save the key (/home/ec2-user/.ssh/id_ecdsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ec2-user/.ssh/id_ecdsa.
Your public key has been saved in /home/ec2-user/.ssh/id_ecdsa.pub.
The key fingerprint is:
SHA256:xeEQdi81+0C2Bv8GwOo0w4UQB0mBIc09cN6Gyu25L88 ec2-user@bastion01
The key's randomart image is:
+---[ECDSA 521]---+
|  .oo*B*=+= =    |
|   .+o+=.=oX +   |
|      oooo= O    |
|   . o .*. o =   |
|    o .oSo    +  |
|     . ..    .   |
|      o          |
|      .o         |
|      .+E        |
+----[SHA256]-----+
[ec2-user@bastion01 ~]$
[ec2-user@bastion01 ~]$ cat .ssh/id_ecdsa.pub
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAD96eEy8hJWAEafkmKRRjNXCTwUXClHMrz2wd4UAFCClwiqJZE6sBYsQl7VRtEZs94b4JPM/wnZZ7fNHKdY7c/KqwE6a2XyNy4i+Wgwf9QMJYPdoBgdOEDoRFKL2mrV6Kc1MMBqCCoGjlQvIBdtfLdxUQdvKESOA6Xqdnd6rMAqwbcrYw== ec2-user@bastion01

Reference

  1. pecoとEC2 APIを使って踏み台経由のSSHログインを楽にする
  2. STSで一時クレデンシャルを発行する
  3. AWS CLIがAssumeRoleする際のセッション名を指定する

Discussion