Ansibleでroot権限でタスクを実行したい場合はbecomeキーワードを使えばいいが、本質的にはこの仕組みは任意のユーザー権限でタスクを実行するもの。
root権限で処理されるのは、いくつかの関連パラメタを省略するとデフォルトでroot権限で動くようになっているため。
本記事では、多くの場合に省略されるパラメタをきっちり指定するとrootではない他ユーザー権限でタスクを処理できる点についてまとめておく。
LinuxのCLIに慣れてる人向けに補足すると、becomeだけ使うのはsudoを素で実行するとroot権限がデフォルト動作になるのと同じ。
本記事ではsudoに-uで指定するユーザーの権限でタスクを実行するのと同様のことを行う。
基本的なタスクの書き方
例として「ユーザーを新たに作成し、そのユーザー権限で実行する必要があるタスク」というケース。
ここではyu_takasakiユーザーを作成(パスワードはerabenaiyo)し、ホームディレクトリへでPython仮想環境を作成する、というもの。
- hosts: all gather_facts: false vars: username: yu_takasaki password: erabenaiyo tasks: - name: create user ansible.builtin.user: name: "{{ username }}" password: "{{ password | password_hash('sha512') }}" shell: /bin/bash home: "/home/{{ username }}" become: true - name: create venv ansible.builtin.pip: name: - pip - ansible-core==2.18.5 virtualenv: "/home/{{ username }}/python-env" virtualenv_command: python3 -m venv become: true become_user: "{{ username }}" become_method: sudo vars: ansible_become_password: "{{ password }}"
タスク「create user」は本記事では触れないが、「create venv」について、becomeをtrueにしつつ、become_userでユーザー名を指定することで、このユーザー権限でタスクを実行する記述になる。
ただbecome系のキーワードには「becomeのためのパスワードを指定」する専門の設定項目がなぜかないため、vars.ansible_become_passwordに指定ユーザーのパスワードをセットする。
(言い換えると、become_passwordはAnsibleにはないんで、varsを使って変数でセットする、ということ)
権限エラーの場合の原因と対処方法4選
環境によっては以下のようなエラーが発生する場合がある(ansible-playbookの実行に-v付与)
fatal: [node]: FAILED! =>
msg: |-
Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user (rc: 1, err: OpenSSH_9.9p1, OpenSSL 3.2.4 11 Feb 2025
debug1: Reading configuration data /home/zaki/.ssh/config
debug1: /home/zaki/.ssh/config line 1: Applying options for *
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Reading configuration data /etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf
debug1: Reading configuration data /etc/ssh/ssh_config.d/50-redhat.conf
debug1: Reading configuration data /etc/crypto-policies/back-ends/openssh.config
debug1: configuration requests final Match pass
debug1: re-parsing configuration
debug1: Reading configuration data /home/zaki/.ssh/config
debug1: /home/zaki/.ssh/config line 1: Applying options for *
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Reading configuration data /etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf
debug1: Reading configuration data /etc/ssh/ssh_config.d/50-redhat.conf
debug1: Reading configuration data /etc/crypto-policies/back-ends/openssh.config
debug1: auto-mux: Trying existing master at '/home/zaki/.ansible/cp/7c19651577'
debug1: mux_client_request_session: master session id: 2
chmod: invalid mode: ‘A+user:yu_takasaki:rx:allow’
Try 'chmod --help' for more information.
}). For information on working around this, see https://docs.ansible.com/ansible-core/2.18/playbook_guide/playbooks_privilege_escalation.html#risks-of-becoming-an-unprivileged-user
原因はリンクに書かれている通りで、ざっくりいうと「Ansibleはリモートマシンに処理のためのスクリプトを転送してそれをリモートで実行するが、対象サーバーに接続してるユーザーとbecomeで切り替えるユーザーが異なる場合、ユーザー間でスクリプトのアクセス権限が共有できる状態にある必要がある」というもの(rootの場合は正常に動作する)
リモートサーバーにsetfaclを入れる
順当な対処法としてはこれ。たぶん。
OSコマンドとしてsetfaclが使用可能だと、スクリプトの実行・読み取り権限を内部でよしなにしてくれる(説明が雑)。
dnfおよびaptともに、aclパッケージをインストールすれば使用可能になる。
debian系なら以下のタスクを事前に仕込んでおけばOK
- name: install acl ansible.builtin.apt: name: - acl update_cache: true become: true
観測範囲だと、AWSのAmazonLinux2023はデフォルトでこれが入っているため、特に小細工なしでbecome_userで他ユーザー権限の処理が可能。
common_remote_group (変数名ansible_common_remote_group)
これにグループ名をセットすることで転送するスクリプトファイルの(ownerでなく)groupをそのグループにするというもの。
接続ユーザーと実行ユーザーで同一のOSグループ設定を追加しておき、かつこの設定で読み取り権をグループに付与することでユーザーを切り替えてもスクリプトを実行できるようにする。(ANSIBLE_KEEP_REMOTE_FILES=trueでスクリプトファイルを確認した限りでは770になる)
前述のユーザー作成タスク含めてcommon_remote_groupを使用する構成に改良すると以下の通りで、Ansible実行時に接続するユーザーもnijigasakiグループに所属していればOK
- name: create user ansible.builtin.user: name: "{{ username }}" password: "{{ password | password_hash('sha512') }}" shell: /bin/bash home: "/home/{{ username }}" groups: - nijigasaki become: true - name: create venv ansible.builtin.pip: name: - pip - ansible-core==2.18.5 virtualenv: "/home/{{ username }}/python-env" virtualenv_command: python3 -m venv become: true become_user: "{{ username }}" become_method: sudo vars: ansible_become_password: "{{ password }}" ansible_common_remote_group: nijigasaki
world_readable_temp (変数名ansible_shell_allow_world_readable_temp)
雑だけど簡単で確実な案。
リモートに作成・実行するためのスクリプトファイルの権限をall readableにする(ANSIBLE_KEEP_REMOTE_FILES=trueでスクリプトファイルを確認した限りでは755になる / デフォルトは700)
タスク実行に関するスクリプトがOSのファイルシステム上で誰からもアクセスされても問題ないのであれば楽。
変数指定する場合は名称が(他に比べると大きく)異なるのでその点だけ注意。(world_readable_temp -> ansible_shell_allow_world_readable_temp)
become: true become_user: "{{ username }}" become_method: sudo vars: ansible_become_password: "{{ password }}" ansible_shell_allow_world_readable_temp: true
リモートからSSH認証可能なのであれば接続しなおす
becomeを使ったタスク内での権限変更でなく、SSH接続が可能であれば接続ユーザーを変更して実行しても回避できる。
remote_user: "{{ username }}" vars: ansible_password: "{{ password }}"
ユーザー作成直後とかだとSSH接続可能な条件がそろっていない可能性は高い(公開鍵認証の可否など)が、可能であればこれはこれで簡単。
参考情報
copyモジュールなどのファイル配置系の処理であれば標準でファイルのowner/groupを指定可能なので小難しい処理なしで「root権限で処理しつつ的確なファイルの所有権設定」をセットすれば多くの場合は問題ないが、owner/groupの設定ができないモジュールを使う場合はそうもいかないので、対処できる方法についてまとめてみた。
これ以外に「いやそんな小細工しなくてもこれで一撃でできるが?」な情報があればぜひ教えてください。