Ansible Playbookのポータビリティ

Ansibleでは自動化する内容をPlaybookで管理します。

実行ユーザにとっては事前設定を必要とせずこのPlaybookを取得するだけで実行できることが理想的です。

詳細は後述しますが、実行ユーザの事前設定を避けるためにいくつかの準備をしていくとコマンド引数が増えていきます。

```
ANSIBLE_CONFIG="./ansible.cfg"
ansible-playbook --ssh-common-args="-o StrictHostKeyChecking=no" -i ./hosts TARGET.yml
```

このようにオプションが増えていくと、オプションが構成管理されないため運用が不安定になっていきます。
安定した運用を維持するためには、オプションも構成管理対象として、以下のコマンドだけでAnsibleを実行できることが理想的です。

```
ansible-playbook TARGET.yml
```

以降では、実行ユーザの事前設定を回避し、オプションを構成管理し、`ansible-playbook`をシンプルに実行する方法を説明します。


## 1. Playbookの取得
作成したPlaybookは構成管理し、適切な権限管理のもとワンライナーで取得可能とします。

```shell-session
git clone https://github.com/sonatard/ansible-sample.git
```

また手順を必ず`README.md`として記載します。


## 2. hostsファイルによる実行対象の管理

hostsファイルはデフォルトでは`/etc/ansible/hosts`から読み込まれます。
ただしこのファイルで管理する運用にしてしまうと、playbookを実行するユーザが別途hostsファイルを取得して上記のパスに配置しなければなりません。

これを回避するためには、`hosts`ファイルをplaybookを管理しているrootに配置します。

```
ansible-sample
├── README.md
├── ansible.cfg
├── TARGET.yml
├── group_vars
├── host_vars
├── hosts         ★
└── roles
```


以下のように実行可能になります。

```
ansible-playbook -i ./hosts TARGET.yml
```

またhostsは毎回同じにもかかわらずコマンド実行のたびに`-i ./hosts`オプションを指定したくはありません。
`anasible.cfg`を作成し、以下のような設定を追加します。
またPlaybookと同じディレクトリに配置してリポジトリの管理対象にします。

```:asnbile.cfg
[defaults]
inventory = hosts
```


```
ansible-sample
├── README.md
├── ansible.cfg         ★
├── TARGET.yml
├── group_vars
├── host_vars
├── hosts
├── ssh_config
└── roles
```

こうすることで自動的に`./hosts`が使われるようになります。


```
ansible-playbook TARGET.yml
```

`ansible.cfg`ファイルは実行時に指定せずとも自動的に読み込まれます。
正確には、以下の優先順位でansible.cfgは反映されます。

0. ANSIBLE_CONFIG環境変数で指定したファイル
0. ./ansible.cfg
0. $HOME/ansible.cfg
0. /etc/ansible/ansible.cfg


## 3. SSHオプション

### SSHの関連オプション

Ansibleを使っているとSSHのオプションを渡したくなることがあります。

例えば開発環境において頻繁にAnsibleのターゲットのIPが変わるような場合に、余計な警告を黙らせるため`--ssh-common-args`オプションに`StrictHostKeyChecking no`を渡します。

```
ansible-playbook --ssh-common-args="-o StrictHostKeyChecking=no" TARGET.yml
```

sshの設定はファイルの分離することが可能です。 `ssh_config`ファイルを作り、Playbookと同様のリポジトリで管理します。

```conf:ssh_config
Host *
  StrictHostKeyChecking no
```

```
ansible-sample
├── README.md
├── ansible.cfg
├── TARGET.yml
├── group_vars
├── host_vars
├── hosts
├── ssh_config         ★
└── roles
```

`-F` オプションでssh_configを指定可能です。

```
ansible-playbook --ssh-common-args="-F ssh_config" TARGET.yml
```

さらに実行のたびに`--ssh-common-args=`を指定することを回避します。
`ansible.cfg`を作成して`ssh_args`を設定します。

```conf:ansible.cfg
[ssh_connection]
ssh_args = -F ssh_config
```

以上で、自動的に`ssh_config`ファイルが読み込まれます。

```
ansible-playbook TARGET.yml
```

### 4. SSH鍵の管理

Ansibleを実行するターゲットにアクセスするためにはSSHの認証が通らなければいけません。

パスワード認証ではAnsibleの実行が手間になるため基本的には秘密鍵と公開鍵のペアを作成して、公開鍵を対象のサーバに登録し、秘密鍵をAnsible実行環境のユーザの`$HOME/.ssh/`に配置します。さらに`ssh-agent`を利用することでパスフレーズの入力が1度で済むため効率的です。

`ssh-agent`はAnsibleに限った話ではないため割愛します。


鍵の登録の作業は実行ユーザごとに必要な作業となります。
そこでAnsibleの実行対象すべてに1度で鍵の登録作業を完了するroleを作成します。

```:./roles/ssh/tasks/main.yml
- name: Add user authorized_keys to ${HOME}/.ssh/authorized_keys
  authorized_key:
    user: "{{ user.name }}"
    key: "{{ lookup('file', '/home/user/ssh/id_rsa.pub') }}"
```

```:setup_key.yml
- hosts: all
  vars:
      user:
        name: user_name
        pass: password
  roles:
    - sshkey
```

公開鍵を登録していない初回は`--ask-pass`を指定してSSHのパスワードログインをする必要があります。

```
TARGET_SERVER=xxx.co.jp
ansible-playbook -i "${TARGET_SERVER}," --ask-pass setup_key.yml
```


また非推奨ですが、もしplaybookを管理するリポジトリとAnsibleの実行対象が外部からアクセスできないセキュリティが担保された環境に配置されている場合には、パスフレーズが空の秘密鍵と公開鍵をレポシトリに含めることで、完全に事前設定が必要ないポータブルの環境が構築できます。
この場合は、誰かがサーバに公開鍵を1度登録してしまえば、誰でも`git clone`直後に`ansible-playbook`コマンドが実行可能です。

このときはssh_configにリポジトリ内の秘密鍵のパスを指定します。

```conf:ssh_config
Host *
  StrictHostKeyChecking no
  IdentityFile ./ssh/id_rsa
```

## 最後に

### 自動化ツールの運用、保守
Ansibleに限りませんが自動化ツールをチームで運用する際には、自動化した仕組みを利用するメンバーに説明することがとても重要になります。

自動化環境を構築した担当者は「自動化されているのだから細かい説明はいらないだろう　このコマンド打てばこうなるよ　」ということだけ伝えてしまいがちです。
しかしこれでは、他の人がその自動化ツールを使う可能性は下がります。
なぜなら多くの人は得体の知れない自動化ツールを実行することはとても怖く、多少手間だとしても慣れたやり方でやりたがるためです。


また環境を構築した担当者が先程のような発想になるのは、自動化資産の目的を「何も知らない人でも環境を構築できるようにすること」としているためだと思いますが、そうではなく「環境構築をコード化することで手順を明らかにし、チーム全員で自動化資産を運用保守をできる体制を整備する」ことを目的としたほうがいいでしょう。

おわり