【Ansible】シンプルにユーザのパスワード変更

## 概要
パスワード変更をansibleでシンプルに実施する方法です。
暗号化されたファイルからユーザとパスワードを読み、管理対象ホストのユーザのパスワードを変更します。すべての管理サーバに同一ユーザ名とパスワードでログインできるようにする。シンプルにするため、ロールは使用しません。
ユーザとパスワードが記載されたファイルはansible-vualtで暗号化します

## 背景
こんなことありませんか？
- linuxでローカルユーザにパスワード認証でログインしている
- サーバは違っても同一ユーザ名とパスワードでログインしたい
- 定期的にパスワード変更が必要な社内ルールがある
- 台数が数十台から数百台にある
- （Ansible活用しろと言われても構築にうまく活用できない）

サーバ台数が多いと非常に手間で、数ヶ月に一回でも面倒になる。LADPを導入・管理するにはハードルがある。また、Ansible活用している言われてうまく活用できていないのでとりあえず使うなどｎ

## 環境
台数が多くてもわかりにくので2台の管理対象ホストに対して実行する

```bash:inventory
servera.lab.test.com ansible_host=172.25.250.XX
serverb.lab.test.com ansible_host=172.25.250.XX
```

ansibleのplaybook実行元（コントロールノード）とパスワードを変える対象のサーバ（管理対象ホスト）は同じOSとpythonのバージョンを導入。すでにansibleの初期設定はできている状態。devopsユーザとして接続可能。redhatでサブスクがあるものを利用しているので、ansible-navigatorを利用しています、環境によってはansible-playbookを利用してください

```bash:実行環境(コントロールノード)
cat /etc/redhat-release
Red Hat Enterprise Linux release 9.0 (Plow)
ansible-navigator --version
ansible-navigator 2.1.0
python --version
Python 3.9.10
```

```bash:実行環境(管理対象ホスト)
cat /etc/redhat-release
Red Hat Enterprise Linux release 9.0 (Plow)
python --version
Python 3.9.10
```
CFGもシンプルにインベントリのみ記載
```cfg:ansible.cfg
[defaults]
inventory = inventory
```
## 流れ
1. パスワードファイルの準備（ansible-valut使用）
1. playbook・実行
1. sshの確認

## パスワードファイルの準備（ansible-valut使用）

ユーザとパスワードが記載されたファイルを作成する。
内容が暗号化されて保存されるようにansible-valutを使用して変数ファイル(password.yml)を
作成する。ansible-vaultのコマンドを実行するとパスワードの入力を2回求められる。パスワードは編集するとき、playbookを実行する際に必要となる。実行すると標準でviが起動するのでユーザとパスワード記載して保存する

```bash:password.ymlの作成
[ansible-user@workstation change-password]$ ansible-vault create password.yml
New Vault password: 
Confirm New Vault password: 
```

今回作成したユーザとパスワードの変数ファイル。リストとして2ユーザのパスワードを記載
```yml:password.yml
users:
  - name: test_user1
    pass: abcd
  - name: test_user2
    pass: efgh
```


暗号化されているのでcatでみてもわからない
```bash:password.ymlの作成
[ansible-user@workstation change-password]$ cat password.yml 
$ANSIBLE_VAULT;1.1;AES256
39333565653138333936643432306563336431306363373233393834306231613965393631656661
3763363535666436663762313335363661313065356538650a326262373235383331353861626337
38666361663430363733616338303837373236323130643932666336626237313631343232663237
3262623432353833390a383361306533653465373531363833386261396334336436353566313433
66613737373332306438613434653364353662376430653036356339356239363038666537343833
65393335393963346230616532313761666461643739353736613930366135633634663161346666
34313333376632306464353062636339323736623432613063326530656161346232626565383335
36353962313364633433
```


ansible-valut viewで確認が可能。編集したいときはeditとすればよい
```bash:password.ymlのansible-vaultを使用して表示
[ change-password]$ ansible-vault view password.yml 
Vault password: 
users:
  - name: test_user1
    pass: abcd
  - name: test_user2
    pass: efgh
```
##  playbook・実行

パスワードファイル（ユーザとパスワード）を読みこんで管理対象ホストで実行する

| オプション                              | 意味                                                                 | 理由・目的                                                                                   |
|---------------------------------------|----------------------------------------------------------------------|----------------------------------------------------------------------------------------------|
| `run`                                 | Ansible Navigator のサブコマンドで、プレイブックの実行モード。       | プレイブックを実行（または構文チェックや模擬実行）するため。                                 |
| `-m stdout`                           | 出力形式を stdout（標準出力）に設定。                              | 対話UIではなく、シンプルでログ出力などに適した形式で結果を確認したいため。                     |
| `--pae false `| `--pae false` はアーティファクト保存を無効化。 | 実行履歴（アーティファクト）を残さずに、playbookを実行（ansbile-vualtを使用しているため）     |
| `--vault-id @prompt`                  | 暗号化された値の復号に使うVaultパスワードをプロンプトで入力。        | プレイブックに暗号化された情報（例：パスワード）が含まれており、復号のために必要。             |
| `--check`                             | ドライラン（模擬実行）モード。変更はせず、変更される内容を表示。     | 実際に何が変更されるかを事前に確認したいため。環境に影響を与えずに確認可能。                   |
| `--syntax-check`                      | プレイブックの構文チェックのみを実行。                              | 実際の処理をせず、YAML文法やAnsible的な構文の誤りを事前に検出するため。                        |



```yml:change_user_passwrod.yml
---
- name: Change user password for all our servers
  hosts: all
  become: true
  remote_user: devops
  vars_files:
    - password.yml
  tasks:
    - name: Change user password  using ansible.builtin.user
      ansible.builtin.user:
        name: "{{ item['name'] }}"
        password: "{{ item['pass'] | ansible.builtin.password_hash('sha512') }}"
        state: present
      loop: "{{ users }}"
``` 

まずは、syntaxのチェック、password.ymlのパスワードの入力が求められる

```bash:change_user_passwrod.ymlのsyntaxチェック
[ansible-user@workstation change-password]$ ansible-navigator run -m stdout --pae false change_user_password.yml --syntax-check --vault-id @prompt
Vault password (default): 

playbook: /home/ansible-user/change-password/change_user_password.yml``` 
```

次はdry-runでチェック、password.ymlのパスワードの入力が求められる

```bash:change_user_passwrod.ymlのdry-runでチェック
[ansible-user@workstation change-password]$ ansible-navigator run -m stdout --pae false change_user_password.yml --check --vault-id @prompt
Vault password (default): 

PLAY [Change user password for all our servers] ***********************************************************************************************

TASK [Change user password  using ansible.builtin.user] ***************************************************************************************
changed: [serverb.lab.test.com] => (item={'name': 'test_user1', 'pass': 'abcd'})
changed: [servera.lab.test.com] => (item={'name': 'test_user1', 'pass': 'abcd'})
changed: [serverb.lab.test.com] => (item={'name': 'test_user2', 'pass': 'efgh'})
changed: [servera.lab.test.com] => (item={'name': 'test_user2', 'pass': 'efgh'})

PLAY RECAP ************************************************************************************************************************************
servera.test.test.com    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
serverb.test.test.com    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

``` 

実際に実行（各、管理対象ホストで実際に流す）
```bash:change_user_passwrod.ymlの実行
[ansible-user@workstation change-password]$ ansible-navigator run -m stdout --pae false change_user_password.yml --check --vault-id @prompt
Vault password (default): 

PLAY [Change user password for all our servers] ***********************************************************************************************

TASK [Change user password  using ansible.builtin.user] ***************************************************************************************
changed: [serverb.lab.test.com] => (item={'name': 'test_user1', 'pass': 'abcd'})
changed: [servera.lab.test.com] => (item={'name': 'test_user1', 'pass': 'abcd'})
changed: [serverb.lab.test.com] => (item={'name': 'test_user2', 'pass': 'efgh'})
changed: [servera.lab.test.com] => (item={'name': 'test_user2', 'pass': 'efgh'})

PLAY RECAP ************************************************************************************************************************************
servera.lab.test.com    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
serverb.lab.test.com    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

  
``` 
問題なく成功。パスワード変更なので、同じユーザとパスワードで実行してもchangedで記録されています。

## ログイン確認（sshコマンド）
ansibleで実行したあとにどこまで確認すべきかのお作法がわかっていません。ただ、本当に大丈夫なの？に答えるためにシェルでとりあえずログインできる確認します。

```bash:実際にsshでチェック
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no ユーザ名@サーバ
``` 

ここでログインに失敗した場合はpamでロックが起きていないか確認してみてください。

sshの確認も確認目的によっては、taskとして追加することや別のplaybookを作ってもよいかもしれません。


## 振り返り
ansibleの使い方として、構築の自動化とう本来の目的からは外れるのかなとは感じていますが、まずはansibleを使って労力を削減したい、使い始めるという目的と記載してみました。

パスワード変更をansibleでシンプルに実施する方法です。
暗号化されたファイルからユーザとパスワードを読み、管理対象ホストのユーザのパスワードを変更します。すべての管理サーバに同一ユーザ名とパスワードでログインできるようにする。シンプルにするため、ロールは使用しません。
ユーザとパスワードが記載されたファイルはansible-vualtで暗号化します