【Ansible】かゆいところに手が届くTips　その2

Ansibleを使っていて、個人的にハマって調べたことをTipとしてまとめていきたいと思います。Tipsが溜まったらその3もやります！


# 今回紹介するTips

1. OSユーザのパスワードは事前にハッシュ化しなくてもいい！
2. role内変数を、role内のみで使うプライベート変数にする
3. Ansibleモジュール内で*（アスタリスク）を使用する
4. RPMパッケージをインストールさせたい
5. become使用時にsudoパスワードを自動入力したい
6. ansible-vault使用時にパスワードを環境変数で渡したい
7. 何回も書く必要のあるパラメーターをまとめる！
8. Ansibleでevalチックな変数の中に変数がある場合


## OSユーザのパスワードは事前にハッシュ化しなくてもいい！
---
**password_hash**を使う

以前お伝えしたテクニックでは事前に暗号化しておく手順でしたが、
リファレンスをよくよく見ると暗号化してくれる書き方がありました。

以下に対応しています。

- sha256
- sha512

使い方

```:yaml
  - name: ユーザー作成
    user:
      name: test
      #SHA256の時はこちら
      password: "{{ 'password' |password_hash('sha256', 'mysecretsalt') }}"
      #SHA512の時はこちら
      password: "{{ 'password' |password_hash('sha512', 'mysecretsalt') }}"
      home: /home/test
 ```

ただし注意点として、以下のように変数をリスト化しループを回した場合、実行結果にパスワードが平文で流れてしまいます。

```
  vars:
    test:
      - name: test1
        password: password
        home: /home/test1

      - name: test2
        password: password
        home: /home/test2

  tasks:
    - user:
        name: "{{ item.name }}"
        password: "{{ item.password |password_hash('sha256', 'mysecretsalt') }}"
        home: "{{ item.home }}"
      with_items:
        - "{{ test }}"
```

passwordが平文で見える！

```
PLAY ***************************************************************************

TASK [user] ********************************************************************
changed: [rhel6_d] => (item={u'home': u'/home/test1', u'password': u'password', u'name': u'test1'})
changed: [rhel6_d] => (item={u'home': u'/home/test2', u'password': u'password', u'name': u'test2'})
```

なので、リスト化する場合は`no_log: True`をつけ、出力しないようにします。

```
  vars:
    test:
      - name: test1
        password: password
        home: /home/test1

      - name: test2
        password: password
        home: /home/test2

  tasks:
    - user:
        name: "{{ item.name }}"
        password: "{{ item.password |password_hash('sha256', 'mysecretsalt') }}"
        home: "{{ item.home }}"
      with_items:
        - "{{ test }}"
      no_log: True
```

こうなります

```
TASK [user] ********************************************************************
changed: [rhel6_d] => (item=(censored due to no_log))
changed: [rhel6_d] => (item=(censored due to no_log))
```


## role内変数を、role内のみで使うプライベート変数にする

**private_role_vars = yes**を使う

roleで呼び出された・定義された変数は、別のroleに処理が移っても引き継がれます。Ansibleの変数命名ルールにて、先頭にrole名をつけろと記載されているのもそのためです。

しかし、そうもできない場合はroleの中で変数を閉じる必要がありますのでansible.cfgに以下の記載を追記します。

```:ansible.cfg
private_role_vars = yes
```

## Ansibleモジュール内で*（アスタリスク）を使用する

**with_fileglob**を使う

```:tasks
- copy: 
    src: {{ item }} 
    dest: /path

  with_fileglob:
    - "/etcsysconfig/network-scripts/ifcfg-*"
```

ちなみにfetchモジュールで、with_fileglobを使用すると出力はOKとでるのにファイルが取得されないケースがあります。これは、with_fileglobの解決がローカルホストで行われるのに対し、fetchはターゲットマシン（構成管理対象サーバー）で実施されるためです。

そのため、*指定をしたい場合には、shellモジュールでfind検索を実施し、registerで登録した値をwith_itemsに入れるやり方となります。
※他のうまいやり方あったら教えて下さい。


## RPMパッケージをインストールさせたい

**yum モジュール**を使う

yumモジュールでは、nameアトリビュートにてフルパスでの指定ができるため、ローカル上のRPMファイルを指定することでインストールが可能です。

```:tasks
yum:
  name: xxxxx.rpm
  state: present
```

参考：[Ansible で RPM を扱う](http://qiita.com/dayflower/items/21c64a6f5da155a5ade3)

## become使用時にsudoパスワードを自動入力したい

**ansible_become_pass**を使う

自動入力ができない！ということで、sudo時のパスワードをNOPASSWDにしている皆さん朗報です。

以前はsudo_passwordとかありましたが、becomeが推奨されてからはansible.cfg内では指定できなくなりました。じゃあどうするのか！というと、ansible_become_passが用意されています。

こいつの使い方は2通りあります。

- インベントリファイルで指定
- 変数ファイルで指定（変数として作成する）

```:インベントリファイルの場合
[target]
hostname1 ansible_become_pass=xxxx
```

```:変数ファイルの場合
ansible_become_pass: xxxx
```


### 発展ケース（環境変数渡し）

```:変数ファイルの場合
ansible_become_pass: "{{ lookup('env','SUDO_PASSWD') }}"
```

## ansible-vault使用時にパスワードを環境変数で渡したい

JenkinsなどのCIツールを使用している場合や、vaultのパスワードファイルを残しておきたくない場合に使えるテクニックです。

`--vault-password-file`を使います。

`--vault-password-file`は引数にファイルだけではなく、実行権限の付与されたスクリプトを取ることができ、その標準出力をパスワードとして利用することができます。

つまり、環境変数をスクリプトで解析し標準出力させることで、vaultパスワードをローカルに残す必要がなくなります。ダイナミックインベントリ的な使い方ですね。



```:vault.sh
#!/bin/bash
echo $VAULT_PASS
```

```:bash
export VAULT_PASS=xxx
ansible-playbook site.yml --vault-password-file vault.sh
```

### メモ

プロセス置換を利用して、シェルすら作りたくない！という場合はMacのみプロセス置換にて以下が可能です。（CentOSではできなかった）

```:bash
ansible-playbook site.yml --vault-password-file <(echo $VAULT_PASS)
```

Centos系のLinuxではプロセス置換時に一時ファイルを以下のように`pipe:[xxxxxxxx]`で管理しています。

```
[server ]# ll <(date)
lr-x------ 1 root root 64  4月  8 11:01 /dev/fd/63 -> pipe:[24349835]
```

ansible-vaultコマンド実行時に読み込まれる以下のファイルでは、`os.path.realpath`（実際のファイルのパスを参照する）とかかれているために`pipe:[xxxxxxxx]`が読まれてしまいうまく動作しないようです。（realpathを取り除くとうまくいった）


```https://github.com/ansible/ansible/blob/7f8e8ddca9cf103c05bf39d68ebb2e2ded4067f2/lib/ansible/parsing/dataloader.py:python

this_path = os.path.realpath(to_bytes(os.path.expanduser(vault_password_file), errors='strict'))
if not os.path.exists(to_bytes(this_path, errors='strict')):
  raise AnsibleFileNotFound("The vault password file %s was not found" % this_path)
```

MacではCentosとプロセス管理の仕組み（proc周辺）が異なるため、プロセス置換でもうまくいくようです。



## 何回も書く必要のあるパラメーターをまとめる！

**YAMLのマージ記法**を使う。

[参考：ansible-playbook内でもYAMLのマージ記法が使えます!](http://qiita.com/tbuchi888/items/2ff64060290bcabc721e)

```:task
 - file:
     path: /tmp/a
     << : &DEF
       owner: ansible
       group: ansible
       mode: 0755
       state: directory
 - file:
     path: /tmp/b
     << : *DEF
```

DEF変数にowner/group/mode/stateの設定をいれ、それを使いまわしています。これにより次回以降のパーミッション周りの設定をすっきりさせています。（変数名はなんでもよいです`<< : &`と`<< : *`が大事）

これ色々と使えそうですね！


## Ansibleでevalチックな変数の中に変数がある場合

```
{{ somvar_{{other_var}} }}
```

こういうことしたいときは、以下のようにします。

```
{{['somevar_'  + other_var] }}

host_varsを使ってる時はこっちらしい
{{ hostvars[inventory_hostname]['somevar_'  + other_var] }}
```


## 

## 


## 

##