Tambourine作業メモ

主にスキル習得のためにやった作業のメモ。他人には基本的に無用のものです。

Ansibleで遊んでみる(5) 〜 INJECT_FACTS_AS_VARS とはなんなのか

3回目でやった例を、もう一度見てみたい。

Unix OSでユーザーのグループを作る。以下の様なタスクを作ると、hogeグループをID=7777で作ることが出来る。

tasks:
  - name: Make groups
    group:
      name: hoge
      gid: 7777

複数のユーザーを作りたかったら、こう書けと入門書には書いてある。

vars:
- usergroups:
  - name: hoge
    gid: 7777
  - name: fuga
    gid: 8888

tasks:
  - name: Make groups
    group:
      name: "{{ item.name }}"
      gid: "{{ item.gid }}"
    loop: "{{ usergroups }}"

しかし、これはどう見ても冗長だ。

vars:
- usergroups:
  - name: hoge
    gid: 7777
  - name: fuga
    gid: 8888
tasks:
  - name: Make groups
    group: "{{ item }}"
    loop: "{{ usergroups }}"

これで良くないか?

というわけで試してみる。

TASK [usergroup : Make groups] *************************************************
[WARNING]: Using a variable for a task's 'args' is unsafe in some situations
(see
https://docs.ansible.com/ansible/devel/reference_appendices/faq.html#argsplat-
unsafe)
changed: [inst] => (item={'name': 'hoge', 'gid': 7777})
changed: [inst] => (item={'name': 'fuga', 'gid': 8888})

ちゃんと動作するが、怒られる。「安全じゃ無い」らしい。「argsを使ったら、危ないよ」としてるのは、つまり、

group: dict_value

group:
  args: dict_value

と扱われるということらしい。

詳しくはこちら・・・と書いているので、そのFAQを見てみよう。

docs.ansible.com

ただし、 usermod_args に渡されるパラメーターや値が、 ウイルスなどに感染したターゲットマシンの host facts に含まれる悪意のある値で上書きされる可能性があるため、 このようなタスクの構築にはリスクがあります。

AnsibleのFactはあんまりよく理解できていない概念の1つなんだけども、つまり、操作対象システムの情報、例えばOSが何かとかバージョンが何かといういうものを変数と同じように参照できる仕組みのことだ。そして、それはまさに変数(Var)と同じスコープの中で同じように扱われる。

しかし、Ansibleというプログラムのことを考えたら、Factはシステムの外部から与えられたものなので信用できない情報が含まれることがある。例えば、Rubyにはtaintという仕組みが(あるが、有効に使うのが難しいので風前の灯火で)ある。コマンドライン引数などの文字列オブジェクトなどに汚染されてますよマークが付いて、そのマークが付いたオブジェクトで一部の動作が禁止されるというような仕組みだ。Ansibleはパラメータとして与えられた情報を元にroot権限でコマンドが実行されるような仕組みなので、コマンドの引数が汚染された情報でうっかり書き換えられると大変にマズい。それはなんとなく理解できる。

しかし、そもそも自分で定義したVarがFactで塗り替えられるかも知れないというのは、何かが間違っている。そもそも、AnsibleのVarは定義できる場所が多すぎてスコープがよくわからないんだけども。というわけで、Factは別の名前空間に押し込められることになった。Ansible 2.5でのこと。しかしながら、まだ移行期間なのでFactがVarを塗り替える状況は変わらない。現状は、INJECT_FACTS_AS_VARSをFalseに設定する(例えばANSIBLE_INJECT_FACT_VARSという環境変数をFalseに設定する)と将来的に予告されているとおりにVarの名前空間にFactは入ってこない動作になり、この警告の表示も消える。

しかし、タスクへのパラメータをdictを渡そうとすると、Factで上書きされる可能性が生じるのはなぜなのかは、やっぱりよくわからない。