Ansible2.8の新機能2 - Become Plugins

Red Hatのさいとうです。 前回のAnsible2.8の新機能1 - Interpreter Discoveryから、だいぶ時間がたってしまいましたが、Ansible 2.8で実装された新機能2をお届けします。単に忙しかっただけで書くのを忘れてたわけじゃないんですよ。

今回ご紹介するのは Become Pluginです。

Become機能のプラグイン化

Ansible v2.8以前は、sudoやsuなどのコマンドを利用してrootなどの特定のユーザ権限でPlaybookを実行する機能は、コア機能が利用するライブラリ内で定義されており、利用者が独自に改変したり、拡張したりすることができませんでした。 Ansible v2.8以降では、この機能をプラグイン化してコア機能から切り離すことで、利用者が必要に応じて拡張できるようになりました。

この記事では、必要最低限の機能を実装した独自のbecome pluginを作成して、ansible-playbookコマンド実行時に利用する方法を紹介します。

Becomeプラグインの実装

ここでは、以下のように、sudo su -c <コマンド> を実行する以下のスクリプト(sudosu)をターゲットホストの/usr/bin/sudosuとして配置して、Playbook実行時にbecome methodとして利用します。

#!/bin/sh

sudo su "$@"

#
# [EOF]
#

これをターゲットホストに/usr/bin/sudosuとして配置したら、実行権を与えておきます。

# chmod +x /usr/bin/sudosu

続いて、become pluginであるsudosu.pyを作成します。DOCUMENTATIONansible_become_user , ansible_become_exe , ansible_become_password を記述するのを忘れないでください。この記述がないと、becomeパラメータとして必要なパスワードなどの情報をプラグインに引き渡すことができません:

# -*- coding: utf-8 -*-

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.module_utils.six.moves import shlex_quote
from ansible.plugins.become import BecomeBase

DOCUMENTATION = """
    become: sudosu
    description:
        - Testing for custom become_plugin
    options:
        become_user:
            description: User you 'become' to execute the task
            default: root
            vars:
              - name: ansible_become_user
        become_exe:
            description: sudosu executable
            default: sudosu
            vars:
              - name: ansible_become_exe
        become_pass:
            description: Password to pass to sudo
            required: False
            vars:
              - name: ansible_become_password
"""

class BecomeModule(BecomeBase):

    name = 'sudosu'

    def build_become_command(self, cmd, shell):
        self.prompt = '[sudo] password for '
        command = self.get_option('become_exe') or self.name
        success_cmd = self._build_success_command(cmd, shell)
        return '%s -c %s' % (command, shlex_quote(success_cmd))

#
# [EOF]
#

self.prompt にパスワードインタラクション用のプロンプトを設定します。それ以降の記述は、現状ドキュメントが存在していないため、su.pysudo.py などを参考にしてBecomeBaseクラスを読み解きつつ実装してみました(もちろんちゃんと動作します)。

このプラグインを、以下のようにPlaybookのbecome_pluginディレクトリに配置します:

.
├── become_plugins
│   └── sudosu.py
├── inventory
└── test.yml

このプラグインを利用するtest.ymlは、以下のように記述しています:

---
- hosts: all
  gather_facts: no

  tasks:
    - yum:
        name: wget
        state: latest
      become: yes
      become_method: sudosu
      become_user: root

最後に、このPlaybookを実行してみます。--ask-become-passsudo suの実行時に聞かれるパスワードを渡すのをお忘れなく。-vvvオプションを付与して実行すると、タスクの実行にsudosuが使われているのが確認できます。

$ ansible-playbook -i inventory test.yml --ask-become-pass -vvv
ansible-playbook 2.8.1
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/hsaito/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/hsaito/.pyenv/versions/2.7.16/envs/ansible-2.8.1-py27/lib/python2.7/site-packages/ansible
  executable location = /home/hsaito/.pyenv/versions/ansible-2.8.1-py27/bin/ansible-playbook
  python version = 2.7.16 (default, May  7 2019, 14:18:00) [GCC 9.0.1 20190312 (Red Hat 9.0.1-0.10)]
Using /etc/ansible/ansible.cfg as config file
BECOME password: ********

...

<test00> SSH: EXEC sshpass -d8 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o 'User="hsaito"' -o ConnectTimeout=10 -o ControlPath=/home/hsaito/.ansible/cp/22ce55f06b -tt test00 '/bin/sh -c '"'"'sudosu -c '"'"'"'"'"'"'"'"'/usr/bin/python /home/hsaito/.ansible/tmp/ansible-tmp-1561363694.88-125525749171244/AnsiballZ_yum.py'"'"'"'"'"'"'"'"' && sleep 0'"'"''

...

まとめ

become plugin(だけじゃないけど)は開発者向けのドキュメントが存在していません。バンドルされているsudoなどのプラグインを読み解いて、がんばって実装するしかありませんが、sudoやsuなどのようにバンドルされているプラグイン以外の権限昇格コマンドを利用したいような場合は、become pluginとして独自に実装できるようになりました。また、プラグイン化されたことで、アップストリームへの機能拡張のリクエストもしやすくなるというメリットもありますので、今後の拡張に期待したいところです(もう世にある権限昇格系のコマンドは既に実装されている気もしますが)。

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません