Ansibleを触ってPlaybookやRoleを理解しよう

今回は構成管理のデファクトスタンダードであるOSSのAnsibleを使って、
sudoパスワードの暗号化、Playbookを使ってのコマンド実行、PlaybookからAnsibleのroleに変更、Roleを使ってのユーザ作成を行ってみます。

ディストリビューションによって違いがないかUbuntu18.04,20.04,22.04、Debin9,10、CentOS7、AlmaLinux8,9、RockyLinux8,9、RHEL8と11種類のOSを用意して実行していきます。

準備

Debianでsudoが実行できるよう準備

Debianを最小でインストールした場合はsudoがインストールされていないので
sudoをインストールして、sudoのグループに所属させます。

$ apt -y install sudo
$ usermod -aG sudo xxxxxx

パスワードなしでのSSHログイン準備

後でAnsibleでのパスワードログインもやっていきますが
通常のシーケンスである鍵交換をしていきます。

まず、サーバー側のSSH鍵を作成します。

$ cd ~/.ssh
$ ssh-keygen -t rsa -f id_rsa
$ chmod 600 ~/.ssh/id_rsa
$ chmod 700 ~/.ssh

鍵配布を行っていきます、
ここからクライアントの数だけループを行います。

$ ssh-copy-id 192.168.1.50
$ ssh 192.168.1.50
$ ssh-copy-id 192.168.1.51
$ ssh 192.168.1.51
.........................................

Playbookでの実行

Playbookの準備

現時点ではロールを使いませんが
Ansbileのロールを作成します。

$ ansible-galaxy init --offline test
$ tree test
test
├── README.md
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
└── main.yml

鍵を登録したクライアントを記載します。

$ vi test/inventory
[yum]
192.168.1.55
[dnf]
localhost
192.168.1.56
192.168.1.57
192.168.1.58
192.168.1.59
[apt]
192.168.1.50
192.168.1.51
192.168.1.52
192.168.1.53
192.168.1.54

登録したホストが認識されているか確認します。

$ ansible-inventory --graph -i test/inventory
@all:
|--@apt:
|  |--192.168.1.50
|  |--192.168.1.51
|  |--192.168.1.52
|  |--192.168.1.53
|  |--192.168.1.54
|--@dnf:
|  |--192.168.1.56
|  |--192.168.1.57
|  |--192.168.1.58
|  |--192.168.1.59
|  |--localhost
|--@yum:
|  |--192.168.1.55
|--@ungrouped:

Ansible Vaultでパスワードを暗号化します

sudoに必要なパスワードを変数ansible_sudo_passに登録します。
複数の環境設定ファイルが使いやすいようvars/main.ymlではなくvars/main/*.ymlで設定します。

$ cd test
$ rm -rf vars/main.yml
$ mkdir vars/main
$ vi vars/main/sudo_pass.yml
ansible_sudo_pass: hogehoge

暗号化用のパスワードを記載します。
場所はどこでもいいのですが、.sshディレクトリに格納してます。

$ vi ~/.ssh/sudo_pass

ansible-vaultでsudo_pass.ymlで暗号化します。
@の前のsudoがvault-idになり、
@の後のファイル名がパスワード格納ファイルになります。

$ ansible-vault encrypt --vault-id sudo@~/.ssh/sudo_pass vars/main/sudo_pass.yml
Encryption successful

sudo_pass.ymlが暗号化されたことを確認します。

$ cat vars/main/sudo_pass.yml
$ANSIBLE_VAULT;1.2;AES256;sudo
36633337366438316536346238633862666431653066303537663836666236626232376631306262
3239643862663036323232306238356232663836363430640a343137373135376262386436353033
65393763363963346232656536326136353239353435336565343530633964306464623432663661
3730643661613862370a326631613933343531306433616138343139363836633538323234643861
30303930373165316231623136326465343430313366656161383131666139363863383931356363
3936343530306432666337386135303630646564633064313261

Playbookの作成と実行(SSH鍵認証、sudoパスワード入力不要)

まずロールではなく単独のPlaybookで操作を行っていきます。
各サーバにSSH鍵でログインして、sudoしてwhoamiを実行するPlaybookを作成します。
また、ログが表示できるようhandlerで捕捉します。
xxxxは任意のユーザに変えてください

$ vi test.yml
---
- name: test
  hosts: all
  user: xxxxxx
  become: true
  gather_facts: false
  vars_files:
  - vars/main/sudo_pass.yml
  tasks:
  - name: whoami
    command: whoami
    notify: handler
    register: result
  handlers:
  - name: handler
    debug: var="result"

実行します。場合によっては以下のエラーが起きるかもしれません。

$ ansible-playbook --vault-id sudo@~/.ssh/sudo_pass test.yml -i inventory

fatal: [192.168.0.53]: FAILED! => {"ansible_facts": {}, "changed": false, "failed_modules": {"ansible.legacy.setup": {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "failed": true, "module_stderr": "Shared connection to 192.168.0.53 closed.\r\n", "module_stdout": "/bin/sh: 1: sudo: not found\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 127}}, "msg": "The following modules failed to execute: ansible.legacy.setup\n"}
fatal: [192.168.0.54]: FAILED! => {"ansible_facts": {}, "changed": false, "failed_modules": {"ansible.legacy.setup": {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "failed": true, "module_stderr": "Shared connection to 192.168.0.54 closed.\r\n", "module_stdout": "/bin/sh: 1: sudo: not found\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 127}}, "msg": "The following modules failed to execute: ansible.legacy.setup\n"}

Python3の実行エラー回避

対象のDebianのサーバで確認した所
原因は/usr/bin/python3が存在しないようです。

$ whereis python
python: /usr/bin/python /usr/bin/python3.7 /usr/bin/python3.7m /usr/bin/python2.7 /usr/lib/python3.7 /usr/lib/python2.7 /etc/python /etc/python3.7 /etc/python2.7 /usr/local/lib/python3.7 /usr/local/lib/python2.7 /usr/share/python /usr/share/man/man1/python.1.gz
$ whereis python
python: /usr/bin/python3.9 /usr/lib/python2.7 /usr/lib/python3.9 /etc/python3.9 /usr/local/lib/pyth

inventoryにPythonのパスを記載します。

$ vi inventory
[dnf]
localhost
192.168.1.55
192.168.1.56
192.168.1.57
192.168.1.58
192.168.1.59
[apt]
192.168.1.50
192.168.1.51
192.168.1.52
192.168.1.53 ansible_python_interpreter=/usr/bin/python3.7
192.168.1.54 ansible_python_interpreter=/usr/bin/python3.9 

再度実行します。エラーが起きないはずです。

$ ansible-playbook --vault-id sudo@~/.ssh/sudo_pass test.yml -i inventory

–vault-idを省略できるようにします。
実行ディレクトリにansible.cfgを記載してデフォルトを上書きします。
まずはvault-id抜きでエラーが出ることを確認します。

$ ansible-playbook test.yml -i inventory
ERROR! Attempting to decrypt but no vault secrets found
$ vi ansible.cfg
[defaults]
vault_identity_list: sudo@~/.ssh/sudo_pass
vault_id_match: true

再度実行してみます。

$ ansible-playbook test.yml -i inventory

RoleでのAnsible実行

RoleでのPlaybookの作成(ログインパスワード平文、sudoパスワード平文))

今度はsudoが可能なスポットの作業用ユーザを作成します。
また、ロール化も行います。
今回はパスワードログインで行ってみます。
また、sudoができるようディストリビューションごとに異なるグループに所属させます。
特にエラー処理していないため実行ごとにパスワードハッシュが変わり常にchangedになります。

処理部分を記載

$ vi tasks/main.yml
---
# tasks file for test
- name: RedHat Create User
  user:
    user: test1
    group: wheel
    password: "{{ 'hogehoge'|password_hash('sha512') }}"
  when:
  - ansible_distribution != "Ubuntu"
  - ansible_distribution != "Debian"

- name: Debian Ubuntu Create User
  user:
    user: test1
    group: sudo
    password: "{{ 'hogehoge'|password_hash('sha512') }}"
  when:
  - ansible_distribution == "Ubuntu" or ansible_distribution == "Debian"

- name: User Check
  command: "id test1"
  notify: handler
  register: result

ハンドラーを記載します。

$ vi handlers/main.yml
---
# handlers file for test
- name: handler
  debug: var="result"

ロールを実行するPlaybookを記載します。

$ cd ../
$ vi test.yml
---
- name: test
  hosts: all
  become: true
  gather_facts: true

  roles:
  - test

ansible.cfgは実行ディレクトリに置く必要があるため再度記載します。

$ vi ansible.cfg
[defaults]
vault_identity_list: sudo@~/.ssh/sudo_pass
vault_id_match: true

RoleでのPlaybookの実行(SSHパスワード平文、sudoパスワード平文)

inventoryにログイン情報とsudoパスワードを記載して、実行を行います。

$ vi test/inventory
[RHEL]
localhost
192.168.1.55
192.168.1.56
192.168.1.57
192.168.1.58
192.168.1.59
[Ubuntu]
192.168.1.50
192.168.1.51
192.168.1.52
[Debian]
192.168.1.53
192.168.1.54
[all:vars]
ansible_ssh_pass=hogehoge
ansible_sudo_pass=hogehoge
$ ansible-playbook test.yml -i test/inventory 

ログインとsudoで昇格できるか先程のPlaybookでは確認していないため
必要に応じてログインしてsudoでスーパーユーザになれるか確認して下さい。
最初のPlaybookの実行ユーザをtest1に書き換えます。

$ cd test
$ vi test.yml
---
- name: test
  hosts: all
  user: test1
  become: true
  gather_facts: false
  tasks:
  - name: whoami
    command: whoami
    notify: handler
    register: result
  handlers:
  - name: handler
    debug: var="result"

実行します。

$ ansible-playbook test.yml -i inventory