🔑

Ansible で AWS セッションマネージャーを使う

2023/09/16に公開

AWS では Systems manager の セッションマネージャ を使用することで EC2 インスタンスにログインできます。
ログインする際は通常は ssh を使うことが多いですが、セッションマネージャでは keypair を設定したりセキュリティグループで ssh 用のポートを準備する必要がないので、セキュリティ的に制限のあるような場合に便利です。

一方、Ansible でも実行ノードから対象ノードへの通信には通常 ssh が使用されますが、対象ノードが aws インスタンスの場合は上記のセッションマネージャを使用することができます。
検索するとマネコンを使って playbook をアップロードして実行する手順が出てきますが、Ansible community collections の ssm connection プラグインを使うと CLI 操作だけで完結できます。

今回は ssm connection plugin を試してみます。

セッションマネージャの確認

セッションマネージャのログイン設定が正しく設定されているか確認するため、適当なインスタンスを作成しておきます。
インスタンスを作成したら aws cli の ssm start-session で正常にログイン出来ることを確認しておきます。

$ aws ssm start-session --target i-0a9a9a1746d5d7f29

ここでエラー等でログインできない場合は aws cli の profile 設定が間違っている、IAM policy の設定が間違っている、インスタンスプロファイルが設定されていない等の可能性があります。

ssm connection のインストール

ssm connection プラグインは aws collection に含まれているので、ansible playbook の実行ノード上で ansible-galaxy でインストールします。

$ ansible-galaxy collection install community.aws

aws collection の依存関係で python の AWS SDK である boto3 も必要となるので、pip 等でインストールします。

$ pip install boto3 botocore

接続確認

以下の 2 種のインスタンスに対して接続確認します。

  • Amazon linux 2
  • Amazon linux 2023

ssm connection の変数

ssm connection では ansible_connection: aws_ssm を定義することで playbook 実行ノードから対象ノードへの通信にセッションマネージャーが使用されるようになります。
これ自体はただの ansible 変数なので、インベントリ内で定義したり、play レベル等の場所で定義できます。
また、セッションマネージャーを使うための認証方法として以下の変数を設定する必要があります。

変数名 説明
ansible_aws_ssm_instance_id 接続対象のインスタンス ID
ansible_aws_ssm_bucket_name S3 bucket 名
ansible_aws_ssm_access_key_id 接続に使用する IAM user の access key
ansible_aws_ssm_secret_access_key 接続に使用する IAM user の secret key
ansible_aws_ssm_region インスタンスのある region

これらは aws_ssm と同様に Ansible の変数として設定するか、もしくは環境変数としてセットすることも可能です。
変数名に対応する環境変数名は ssm connection の Parameters に書いてあるのでこちらを参照。

Amazon linux 2

動作検証として、Amazon linux 2 (ami-0f89bdd365c3d966d) のインスタンスに docker をインストールする playbook を作成します。

ssm.yml
---
- hosts: localhost
  gather_facts: false
  vars:
    ansible_connection: aws_ssm
    ansible_aws_ssm_instance_id: i-0a9a9a1746d5d7f29
    ansible_aws_ssm_bucket_name: mybucket
    ansible_aws_ssm_access_key_id: xxx
    ansible_aws_ssm_secret_access_key: yyy
    ansible_aws_ssm_region: ap-northeast-1
    ansible_python_interpreter: /usr/bin/python
  tasks:
    - name: Install docker
      ansible.builtin.yum:
        name: docker
        state: present
        use_backend: yum
      become: true

作成したら playbook を実行。

ansible-playbook ssm.yml

セッションマネージャーでインスタンスにログインし、docker がインストールされたか確認します。

$ aws ssm start-session --target i-0a9a9a1746d5d7f29

sh-4.2$ bash
[ssm-user@ip-172-31-34-141 bin]$ sudo systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: https://docs.docker.com
[ssm-user@ip-172-31-34-141 bin]$ docker -v
Docker version 20.10.23, build 7155243

無事に docker-engine や docker-cli がインストールされていることが確認できました。

Amazon linux 2023

Amazon linux 2023 でも Amazon linux 2 (ami-0a2e10c1b874595a1) と同様の playbook が使用できますが、package manager を dnf に変更します。

ssm.yml
---
- hosts: localhost
  gather_facts: false
  vars:
    ansible_connection: aws_ssm
    ansible_aws_ssm_instance_id: i-079ba89f2f4ff2e39
    ansible_aws_ssm_bucket_name: mybucket
    ansible_aws_ssm_access_key_id: xxx
    ansible_aws_ssm_secret_access_key: yyy
  tasks:
    - name: install
      ansible.builtin.dnf:
        name: docker
        state: present
      become: true

これで amazon linux 2023 に対しても dnf で docker をインストール出来るはずなのですが、実際に実行するとエラーとなりました。
エラーメッセージで調べてみると以下の issuse に該当しているようです。

Amazon linux 2023 では Bash/readline の仕様変更により Ansible の出力メッセージを正しく処理できず失敗するとのこと。
ワークアラウンドは issue のコメントにあるように、対象インスタンスの /etc/inputrc に enable-bracketed-paste off を追加すれば良いようです。

#1839 fixes it, but it's taking ages to be merged for unknown reasons. In the meantime I've set set enable-bracketed-paste off into /etc/inputrc which is, needless to say, not a fix at all since you need to configure all servers this way, which is exactly what ansible is meant to do. In my case was just one so for now it's sorted, thanks to @dennisjlee !

対象インスタンス上の etc/inputrc を編集した後、再度 playbook を実行すると正常にインストールできます。
先程と同様にインスタンスにログインして確認すると docker が正常にインストールされています。

$ aws ssm start-session --target i-079ba89f2f4ff2e39

sh-5.2$ cat /etc/os-release
NAME="Amazon Linux"
VERSION="2023"
ID="amzn"
ID_LIKE="fedora"
VERSION_ID="2023"
PLATFORM_ID="platform:al2023"
PRETTY_NAME="Amazon Linux 2023"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2023"
HOME_URL="https://aws.amazon.com/linux/"
BUG_REPORT_URL="https://github.com/amazonlinux/amazon-linux-2023"
SUPPORT_END="2028-03-01"

sh-5.2$ docker -v
Docker version 20.10.25, build b82b9f3

sh-5.2$ sudo systemctl  status docker
○ docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; preset: disabled)
     Active: inactive (dead)
TriggeredBy: ○ docker.socket
       Docs: https://docs.docker.com

上記の不具合については https://github.com/ansible-collections/community.aws/pull/1839 でつい先週 PR が作成されています。
なので今後の aws collections の最新バージョンでは修正され、わざわざワークアラウンドで対応する必要はなくなりそうです。

Discussion