踏み台経由でAnsibleを実行する

# はじめに

こちらは[Ansible Advent Calender 2018](https://qiita.com/advent-calendar/2018/ansible) 13日目の記事です。

この記事では、Ansibleの実行対象が踏み台サーバの向こう側に存在する場合の、Ansibleの実行方法について記載します。

# Ansibleの仕組みのおさらい
AnsibleではSSHで対象サーバに入り、Pythonのスクリプトを実行することでサーバの状態を管理します。 
 そこで踏み台サーバ経由でAnsibleを実行するには[多段SSH](https://qiita.com/ik-fib/items/12e4fab4478e360a82a1)の仕組みを使います。

# 実行環境
以下の図のような環境を想定します。

![ansible-bastion.002.jpg](https://qiita-image-store.s3.amazonaws.com/0/113160/1ae4a276-ba78-756a-4b30-5b645b0a669c.jpeg)

上記のサーバに対し予め、

- Ansible実行サーバ -> 踏み台サーバの公開鍵認証でのSSH設定
- 踏み台サーバ -> 実行対象サーバへの公開鍵認証でのSSH設定

を設定し、Ansible実行サーバの秘密鍵(`id_rsa`)と踏み台サーバの秘密鍵(`id_rsa.bastion`)をAnsible実行サーバにもたせておきます。

また、踏み台サーバの設定ができるかを確認するため、事前にcontroller -> targetに直接通信できないことを確認しておきます。

```
vagrant@controller:~$ cat host_list
bastion
target

vagrant@controller:~$ ansible -m shell -a "uname -n" -i host_list target
target | UNREACHABLE! => {
    "changed": false,
    "msg": "ERROR! SSH encountered an unknown error during the connection. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue",
    "unreachable": true
}
```


# 多段SSHの設定
Ansibleで多段SSHを行うには、大きく以下の2パターンがあるためそれぞれ設定の仕方を記載します。

- OSレベルでの設定
- Ansibleでの設定

## OSレベルの設定

OSのSSHのconfig (~/.ssh/config, /etc/ssh/configなど)に多段SSHの設定を入れておくことで、Ansibleがその設定を読み込んで多段SSHを実行できます。

**しかし、OSのSSH設定を変更すると、Ansible以外のプログラムにも影響を与える点に注意してください。**

実際の設定例としては以下のようになります。

```
vagrant@controller:~/.ssh$ cat config
Host bastion
  User vagrant
  IdentityFile ~/.ssh/id_rsa

Host target
  User vagrant
  IdentityFile ~/.ssh/id_rsa.bastion
  ProxyCommand ssh -W %h:%p bastion
```

この状態で実行し、通信が通ることを確認します。

```
vagrant@controller:~$ ansible -m shell -a "uname -n" -i host_list target
target | SUCCESS | rc=0 >>
target
```

## Ansibleで設定

上記で説明した通り、OSレベルで設定すると、他のSSHを使うプログラムにも影響を与えてしまいます。
Ansibleの実行のみ多段SSHをしたいのであれば、こちらで設定した方が良いかもしれません。

`ansible.cfg` の動作を確認するために上記で設定した `~/.ssh/config` は消して繋がらない状態にしておきます。

```
vagrant@controller:~$ ansible -m shell -a "uname -n" -i host_list target
target | UNREACHABLE! => {
    "changed": false,
    "msg": "ERROR! SSH encountered an unknown error during the connection. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue",
    "unreachable": true
}
```

では `ansible.cfg` に設定してみます。

内容としては、基本的に `~/.ssh/config` で設定したものを `ansible.cfg` に書くだけです。上記と同様の設定を `ansible.cfg` に記載すると以下のようになります。

```
[ssh_connection]
ssh_args = -o ProxyCommand="ssh -i ~/.ssh/id_rsa bastion -W %h:%p" -i ~/.ssh/id_rsa.bastion
```

また、これと同様の設定を[環境変数(ANSIBLE_SSH_ARGS)](https://docs.ansible.com/ansible/2.5/reference_appendices/config.html#ansible-configuration-settings)で設定しておくこともできます。

```
vagrant@controller:~$ export ANSIBLE_SSH_ARGS='-o ProxyCommand="ssh -i ~/.ssh/id_rsa bastion -W %h:%p" -i ~/.ssh/id_rsa.bastion'
```

上記の設定をした状態で実行すると、以下のように繋がることが確認できます。

```
vagrant@controller:~$ ansible -m shell -a "uname -n" -i host_list target
target | SUCCESS | rc=0 >>
target
```

ちなみに `ansible.cfg` の設定は、以下のような[優先順位](https://docs.ansible.com/ansible/2.5/reference_appendices/config.html#ansible-configuration-settings)で読み込まれます。

- ANSIBLE_CONFIG (環境変数)
- ansible.cfg (カレントディレクトリ)
- ~/ansible.cfg (ホームディレクトリ)
- /etc/ansible/ansible.cfg

例えば、Playbookによって設定を変えたい、というような場合だとPlaybookごとに `ansible.cfg` をもたせて設定しておくと良いです。

# おわりに
[Ansible Advent Calender 12日目](https://qiita.com/morin_river/items/40abd1baab4c588deafd) の記事を見て、自分もOSSにコントリビュートしてみたいなぁ、とぼんやり思いました。来年は「Ansibleのモジュール作ってコントリビュートしてみた」という記事がかけるように頑張りたい…

# 参考記事
- [多段SSHの設定を.ssh/configにまとめる](https://qiita.com/ik-fib/items/12e4fab4478e360a82a1)