Ansible 多段SSH接続 簡単に検証してみた

# はじめに
Ansible 多段SSH接続で簡単に検証してみました。

以下のサイトを参考にしてみました。
https://oji-cloud.net/2022/07/25/post-7084/
https://qiita.com/brighton0725/items/9c3b205fdc3234298928


Ansibleは以下のUdemyを見ると理解が深まりました
ハンズオンの前にハンズオン理論編を見ることをお勧めします。

https://www.udemy.com/share/1087CO/



# 前提条件
## WSLにAnsibleをインストール

以下の手順に沿ってAnsibleのパッケージをインストールしました。
https://docs.ansible.com/ansible/2.9_ja/installation_guide/intro_installation.html#ubuntu-ansible
**注意 sudo apt install ansibleのみでインストールしたら/etc/ansible/配下の設定ファイルが自動作成されずにansibleが動作しないため、必ず以下のコマンドでインストールしてください**
```
$ sudo apt update
$ sudo apt install software-properties-common
$ sudo apt-add-repository --yes --update ppa:ansible/ansible
$ sudo apt install ansible
```

### SSH接続の設定
testユーザー配下の.sshフォルダへ移動する
```
$ cd /home/test/.ssh
```
.ssh配下に踏み台の秘密鍵とサーバーの秘密鍵を格納する
秘密鍵の権限は600にする。
```
$ ls -tlr
total 20
-rw------- 1 test test 1679 Apr  4 21:50 ec2-user.pem
-rw------- 1 test test  506 Apr  7 00:36 known_hosts.old
-rw------- 1 test test 1675 Apr  7 00:40 test.pem
-rw------- 1 test test  728 Apr  7 00:40 known_hosts
-rw-r--r-- 1 test test  240 Apr  7 00:41 config
```
SSH接続をhost名を指定して出来るように、configファイルを作成する
```
$ vi config

Host basion
  HostName ＜踏み台のIPアドレス＞
  User ec2-user
  Port 22
  IdentityFile /home/test/ec2-user.pem　　


Host test
  HostName ＜プライベートサブネットにEC2のIPアドレス＞
  User test
  IdentityFile /home/test/.ssh/test.pem
  ProxyCommand ssh -W %h:%p basion
```
踏み台サーバーにssh接続できることを確認する
```
$ ssh basion
Last login: Sun Apr  7 00:37:56 2024 from 192.168.0.30
[ec2-user@example ~]$
```
testサーバーにssh接続できることを確認する
```
$ ssh test
Last login: Sun Apr  7 00:41:40 2024 from 192.168.0.101
[rika@localhost ~]$
```
### インベントリファイルを作成
```
$ cd /etc/ansible
```
配下のファイルを確認する
```
$ cd /etc/ansible
$ ls -tlr
total 48
drwxr-xr-x 2 root    root     4096 Mar 27 02:11 roles
-rw-r--r-- 1 root    root     1175 Mar 27 02:11 hosts
-rw-r--r-- 1 root    root      614 Mar 27 02:11 ansible.cfg
-rw-r--r-- 1 root    root      113 Apr  4 22:15 test_playbook.yml
-rw-r--r-- 1 root    root    20075 Apr  6 23:24 ansible.cfg.dpkg-old
-rw-r--r-- 1 root    root       41 Apr  7 00:08 hosts.dpkg-old
-rw-r--r-- 1 root    root      147 Apr  7 01:03 inventory.ini ※新規作成
```

```
$ vi inventory.ini
[server]
server1 ansible_host=basion ansible_user=ec2-user ansible_become=yes
server2 ansible_host=test ansible_user=test ansible_become=yes
```

### プレイブック作成
```
$ vi test_playbook.yml
- hosts: server
  tasks:
    - name: test-playbook
      file:
        path: /tmp/test.txt
        state: touch
```
### プレイブックの文法チェック
以下のサイトを参考にしました。
https://chibinfra-techblog.com/ansible-playbook-to-how-to-read-the-output-results/
```
$ ansible-playbook -i inventory.ini test_playbook.yml --check

PLAY [server] ***************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************
ok: [server1]
ok: [server2]

TASK [test-playbook] ********************************************************************************************************************************************************
changed: [server1]
changed: [server2]

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

```
-vv 恐らく詳細の処理を表示してplaybookを実行した。
```
$ ansible-playbook -i inventory.ini test_playbook.yml -vv
ansible-playbook [core 2.16.5]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/shibata/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.10/dist-packages/ansible
  ansible collection location = /home/shibata/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible-playbook
  python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/usr/bin/python3)
  jinja version = 3.1.3
  libyaml = True
Using /etc/ansible/ansible.cfg as config file
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.

PLAYBOOK: test_playbook.yml *************************************************************************************************************************************************
1 plays in test_playbook.yml

PLAY [server] ***************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************
task path: /etc/ansible/test_playbook.yml:1
ok: [server1]
ok: [server2]

TASK [test-playbook] ********************************************************************************************************************************************************
task path: /etc/ansible/test_playbook.yml:3
changed: [server1] => {"changed": true, "dest": "/tmp/test.txt", "gid": 0, "group": "root", "mode": "0644", "owner": "root", "secontext": "unconfined_u:object_r:user_tmp_t:s0", "size": 0, "state": "file", "uid": 0}
changed: [server2] => {"changed": true, "dest": "/tmp/test.txt", "gid": 0, "group": "root", "mode": "0644", "owner": "root", "size": 0, "state": "file", "uid": 0}

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

```
### サーバーにtest.txtファイルが作成されていることを確認した
WSLにて以下のコマンドを実行する。
```
$ cat config
Host basion
  HostName ＜踏み台のIPアドレス＞
  User ec2-user
  Port 22
  IdentityFile /home/test/ec2-user.pem　　


Host test
  HostName ＜プライベートサブネットにEC2のIPアドレス＞
  User test
  IdentityFile /home/test/.ssh/test.pem
  ProxyCommand ssh -W %h:%p basion
```
/tmp/test.txtが作成されていることを確認した
```
$ ssh basion "ls -l /tmp/test.txt"
-rw-r--r--. 1 root root 0 Apr  7 01:23 /tmp/test.txt

$ ssh test "ls -l /tmp/test.txt"
-rw-r--r-- 1 root root 0 Apr  7 01:23 /tmp/test.txt
```

### 踏み台サーバーのEC2のログ確認
```
less /var/log/messages
Apr  7 01:23:55 example systemd-logind: New session 19 of user ec2-user.
Apr  7 01:23:56 example ansible-ansible.legacy.setup: Invoked with filter=[] gather_subset=['all'] fact_path=/etc/ansible/facts.d gather_timeout=10
Apr  7 01:23:59 example ansible-file: Invoked with src=None selevel=None force=False setype=None _original_basename=None unsafe_writes=False access_time=None seuser=None recurse=False state=touch access_time_format=%Y%m%d%H%M.%S group=None modification_time=None serole=None _diff_peek=None modification_time_format=%Y%m%d%H%M.%S path=/tmp/test.txt owner=None follow=True attributes=None mode=None
Apr  7 01:24:59 example systemd-logind: Removed session 20.
```
### プライベートサブネットのEC2のログ
```
less /var/log/messages
Apr  7 01:21:33 localhost ansible-ansible.legacy.setup: Invoked with filter=[] gather_subset=['all'] fact_path=/etc/ansible/facts.d gather_timeout=10
Apr  7 01:21:33 localhost ansible-file: Invoked with src=None selevel=None force=False setype=None _original_basename=None unsafe_writes=False access_time=None seuser=None recurse=False state=touch access_time_format=%Y%m%d%H%M.%S group=None modification_time=None serole=None _diff_peek=None modification_time_format=%Y%m%d%H%M.%S path=/tmp/test.txt owner=None follow=True attributes=None mode=None
```
### 補足情報
Ansibleでpingの疎通確認しました。

フォルダ移動しました。
```
cd /etc/ansible
```
踏み台サーバーはAnsible経由でping疎通ができました。
````
$ ansible -i inventory.ini  server1 -m ping
server1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
````
testサーバーのping通信が到達しません
````
$ ansible -i inventory.ini  server2 -m ping
server2 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: Connection timed out during banner exchange\r\nConnection to UNKNOWN port 65535 timed out",
    "unreachable": true
}
````
私のPC環境の可能性はありますが、
# まとめ
Ansibleのハンズオンをしてざっくりと概要を理解出来ました。
本記事を参考にハンズオンをしてみたらイメージが付きやすくなると思います。