Edited at

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

More than 3 years have passed since last update.

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 を扱う


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を取り除くとうまくいった)


//github.com/ansible/ansible/blob/7f8e8ddca9cf103c05bf39d68ebb2e2ded4067f2/lib/ansible/parsing/dataloader.py


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のマージ記法が使えます!


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] }}