AWS CLI v2をAnsibleでMacにインストールしてみた

Ansibleを使って、手元のMacにAWS CLI v2をインストールしてみたので紹介します。
2020.02.17

こんにちは。サービスグループの武田です。

先日、待望のAWS CLI v2がGAになりましたね!

[アップデート] リソース名の補完など強力な機能追加!AWS CLI v2 が GA されました!

ちょうどMacのセットアップをAnsibleに任せようと思っていたところだったので、さっそくAnsibleのプレイブックを書いてみました。

環境

次の環境で検証しました。

$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.15.3
BuildVersion:	19D76

$ ansible-playbook --version | grep -E 'playbook|version'
ansible-playbook 2.9.3
  executable location = /usr/local/bin/ansible-playbook
  python version = 3.8.1 (default, Dec 27 2019, 18:06:00) [Clang 11.0.0 (clang-1100.0.33.16)]

またディレクトリの構成は次のようになっています。

$ tree
.
├── ansible.cfg
├── hosts
├── roles
│   └── awscli
│       └── tasks
│           └── main.yml
└── site.yml

3 directories, 4 files

周辺ファイル

先に本質ではない部分のファイルをざっと紹介します。

ansible.cfgは全体の設定をするファイルです。今回はinterpreter_pythonのみ指定しています。

ansible.cfg

[defaults]
interpreter_python=/usr/bin/python3

インベントリファイルです。名前は任意ですが、今回はhostsとしました。

hosts

[localhost]
127.0.0.1

プレイブックの本体です。これも名前は任意ですが、今回はsite.ymlとしました。AWS CLIをインストールする設定はロールとして切り出したため、rolesで指定しています。

site.yml

---
- name: ansible
  hosts: localhost
  connection: local
  become: no
  gather_facts: no
  roles:
    - awscli

AWS CLIをインストールするプレイブック

それではawscliロールのプレイブックを紹介します。name: check awscliwhen: result.rc == 1はセットで、AWS CLIがインストールされているかの事前チェックをしています。このチェックを挟まない場合、プレイブックを実行するたびにダウンロードおよびインストール処理をします。name: download awscli installerはインストーラのダウンロードをしています。validate_certs: noを指定しないと失敗してしまったのですが、根本的な解決策をご存じの方は教えてください。name: install awscliが実際にインストールをする箇所です。実行にはsudoが必要なため、become: yesを指定しています。最後のname: add completion to .bashrcはコマンド補完を有効にするための設定を.bashrcに追記しています。zshなどを使用している場合はそれ用に書き換えてください。

roles/awscli/tasks/main.yml

---
- block:
  - name: check awscli
    command: "which aws"
    register: result
    check_mode: no
    changed_when: no
    failed_when: no

  - block:
    - name: download awscli installer
      get_url:
        url: https://awscli.amazonaws.com/AWSCLIV2.pkg
        dest: /tmp/AWSCLIV2.pkg
        validate_certs: no
      register: download

    - name: install awscli
      become: yes
      command: "installer -pkg {{ download.dest }} -target /"

    when: result.rc == 1

  - name: add completion to .bashrc
    lineinfile:
      path: ~/.bashrc
      line: complete -C aws_completer aws

  tags:
    - awscli

それでは書いたプレイブックを実行してみます!

$ ansible-playbook -i hosts site.yml

PLAY [ansible] *************************************************************************************

TASK [awscli : check awscli] ***********************************************************************
ok: [127.0.0.1]

TASK [awscli : download awscli installer] **********************************************************
changed: [127.0.0.1]

TASK [awscli : install awscli] *********************************************************************
fatal: [127.0.0.1]: FAILED! => {"changed": false, "module_stderr": "sudo: a password is required\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

PLAY RECAP *****************************************************************************************
127.0.0.1                  : ok=2    changed=1    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

おや、sudoが必要な箇所で失敗してますね。というわけで後半戦はこのエラーを解決します。

sudoを実行する3つの方法

おそらく普段からAnsibleを使っている方は慣れたものでしょうが、何らかの方法でsudoを実行するためのパスワードを指定する必要があります。一応sudoersにパスワードなしで実行できるように設定する方法もありますが、今回は除外します。ざっと調べた限り3つの方法がありましたので、それぞれ紹介します。

-Kオプションを指定し、実行時にパスワードを入力する

3つの方法の中で、これが一番簡単です。実行時に-Kオプションを指定するだけです。この方法のメリットは、2回目以降はwhen: result.rc == 1falseになるはずですので、オプションを指定しなくてもよくなることです(sudoが必要な処理がスキップされるため)。その結果、パスワードの入力が必要なのは初回だけということになります。

$ ansible-playbook -i hosts site.yml -K

環境変数としてパスワードを指定する

sudoのパスワードは、環境変数ansible_become_passwordが定義されているとこれを使ってくれます(他にもエイリアスあり)。

sudo – Substitute User DO — Ansible Documentation

環境変数は実行時に引数として指定することもできますし、インベントリファイルなどに定義することも可能です。

たとえば実行時に指定するなら次のようになります。

$ ansible-playbook -i hosts site.yml -e 'ansible_become_password=hogehoge'

ただコマンドヒストリなどに残ってしまうのはちょっと嫌ですね。またインベントリファイルで指定するなら次のようになります。

hosts

[localhost]
127.0.0.1 ansible_become_password=hogehoge

ただしファイルに書いてしまうとバージョン管理にコミットできない(少なくともコミットしたくない)ため、管理上問題になりそうです。

というわけで、2番目の方法はインタラクティブにパスワードを入力する必要はなくなりますが、ちょっと嫌味が残ってしまうなというのが感想です。

Vaultでパスワードを管理する

最後に紹介するのは、Ansibleが提供しているファイルの暗号化機能を利用したものです。ansible-vaultコマンドを使用して簡単に用意できます。

まずは全体で共通の環境変数を定義するためgroup_vars/all.ymlを作成します。作成時にVaultパスワードの入力が求められるため適当に入力します。

$ ansible-vault create group_vars/all.yml
New Vault password:
Confirm New Vault password:

エディタが開かれたら、次のようにパスワードを定義します。

group_vars/all.yml

---
ansible_become_password: hogehoge

これで暗号化されたファイルが用意できました。あとは実行時に--ask-vault-passオプションを指定して実行するだけです。

$ ansible-playbook -i hosts site.yml --ask-vault-pass

この方法のメリットは平文でパスワードを管理しなくてよくなることです。ただし今回のケースにおいてはデメリットの方が大きいと感じました。まずプレイブック実行時に、毎回--ask-vault-passオプションを指定する必要があること *1。毎回パスワードを入力しなければいけないこと *2。そもそも、どうせ入力するなら初めからMacのパスワードを入力すれば済むこと。

たくさんのサーバーにプロビジョニングする場合などは別ですが、今回のようにあくまでローカルマシンで実行するだけなら、Vaultはやりすぎかなと。というわけで、私は1番目の方法を採用しています。

まとめ

Ansibleを使ったAWS CLI v2のインストール方法(プレイブック)と、sudo実行について紹介しました。Ansibleのプレイブックを書くのは本当に数年ぶりで、調べることが多くてたいへんです。が、とても便利ですね!

脚注

  1. 設定ファイルで有効化の設定をする方法もあります
  2. 別途パスワードファイルを作成してそれを指定する方法もあります