OpenLDAP環境が整ったところで、これまでrootユーザでansibleを実行していたが、これからは一般ユーザでansibleを扱う。
一応、イメージとしてはこんな感じ。
この環境下において、ldapクライアントに対してansibleでいろいろ作業する際の実行ユーザについて掘り下げていく。
前提条件
・ldapサーバでユーザを一括管理して、teraterm端末またはansibleサーバからすべてのldapクライアントに同じldapユーザでsshログインができる状態とする。
・AnsibleでOpenLDAP環境構築 -⑦ldapクライアント インストールのplaybookでもあるように、/etc/sudoersをldapmanagerというグループに属しているユーザがsudoの実行権限を持つように設定されているとする。
・ldapmanagerに属しているユーザ名をuser01とする。
◎idコマンドでこのように見える状態↓
[root@ldapclient ~]# id user01 uid=1001(user01) gid=1001(ldapmanager) groups=1001(ldapmanager)
◎/etc/sudoersの設定
## Same thing without a password # %wheel ALL=(ALL) NOPASSWD: ALL %ldapmanager ALL=(ALL) ALL
・/etc/ansible/ansible.cfgのsudo_user、ask_sudo_pass、ask_passは事前にコメントアウトし、無効とする。
#sudo_user = root #ask_sudo_pass = True #ask_pass = True
ansible実行時のユーザ指定
rootユーザでansibleを実行する分にはあまり悩むことはないが、一般ユーザでansibleを実行する際には少し注意が必要。
ansible実行時のユーザパターンとして、以下が考えられる。
①ansibleサーバ⇒rootユーザ、playbook実行先ユーザ⇒rootユーザ
②ansibleサーバ⇒rootユーザ、playbook実行先ユーザ⇒ldapユーザ
③ansibleサーバ⇒rootユーザ、playbook実行先ユーザ⇒モジュール毎にrootユーザまたはldapユーザを指定
④ansibleサーバ⇒ldapユーザ、playbook実行先ユーザ⇒rootユーザ
⑤ansibleサーバ⇒ldapユーザ、playbook実行先ユーザ⇒ldapユーザ
⑥ansibleサーバ⇒ldapユーザ、playbook実行先ユーザ⇒モジュール毎にrootユーザまたはldapユーザを指定
だが、②③についてはあまり現実的ではない。ansibleをrootユーザで実行しているのにわざわざplaybook内でldapユーザにして権限を落としてしまっているからだ。
従って、②③の確認は(勝手に)不問とする。
一応表にまとめておく。
パターン | ansible サーバ |
playbook実行時の ldapクライアント側ユーザ |
備考 |
---|---|---|---|
① | root | root | |
② | root | ldapユーザ | 確認無し |
③ | root | root/ldapユーザ(モジュール毎に指定) | 確認無し |
④ | ldapユーザ | root | |
⑤ | ldapユーザ | ldapユーザ | |
⑥ | ldapユーザ | root/ldapユーザ(モジュール毎に指定) |
上記のパターンごとにansibleの動作を追ってみることにする。
①ansibleサーバ⇒rootユーザ、playbook実行先ユーザ⇒rootユーザ
以下、sample.txtを生成するplaybookを例とする。
[root@ansible_sv ~]# cat /etc/ansible/yml/sample.yml - hosts: ldapclient gather_facts: no remote_user: root tasks: - name: yum update yum: name=* state=present - name: create txt file: state=touch path=/home/user01/sample.txt owner=user01 group=ldapmanager mode=0666 [root@ansible_sv ~]#
これをansible-playbookコマンドで実行すると。。。
[root@ansible_sv ~]# ansible-playbook /etc/ansible/yml/sample.yml PLAY [ldapclient] ************************************************************************************************************************************ TASK [yum update] ************************************************************************************************************************************ fatal: [192.168.3.7]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Warning: Permanently added '192.168.3.7' (ECDSA) to the list of known hosts.\r\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic,password).\r\n", "unreachable": true} PLAY RECAP ******************************************************************************************************************************************* 192.168.3.7 : ok=0 changed=0 unreachable=1 failed=0 [root@ansible_sv ~]#
エラーになってもうた。
確かに冷静に考えると、普通にsshコマンドで相手側サーバのユーザをrootにしたときにパスワードを聞かれるけど、前提条件で/etc/ansible/ansible.cfgの「ask_pass」をコメントアウトしちゃったもんだから、上記のansbile-playbookコマンドを実行したときはパスワード無しでアクセスしてるがために出てしまったエラー。
この場合ansible-playbookコマンドは「–ask-pass」オプションをつける。
[root@ansible_sv ~]# ansible-playbook /etc/ansible/yml/sample.yml --ask-pass SSH password: PLAY [ldapclient] ************************************************************************************************************************************ TASK [yum update] ************************************************************************************************************************************ ok: [192.168.3.7] TASK [create txt] ********************************************************************************************************************************* changed: [192.168.3.7] PLAY RECAP ******************************************************************************************************************************************* 192.168.3.7 : ok=2 changed=1 unreachable=0 failed=0 [root@ansible_sv ~]#
いけました\(^o^)/
rootユーザしか使わないから–ask-passオプションをつけるのが面倒だという人は、/etc/ansible/ansible.cfgの「ask_pass」を再度生かせるように、コメントアウトを外せばOK。
②ansibleサーバ⇒rootユーザ、playbook実行先ユーザ⇒ldapユーザ
③ansibleサーバ⇒rootユーザ、playbook実行先ユーザ⇒モジュール毎にrootユーザまたはldapユーザを指定
は、省略。
④ansibleサーバ⇒ldapユーザ、playbook実行先ユーザ⇒rootユーザ
このパターンを行う場合、事前に以下の作業が必要。
・ansibleサーバにもldapクライアントを構築しておく。
・ansibleサーバにldapクライアントを構築した後、/home/<ldapユーザ名>/.ssh配下にssh秘密鍵を格納しておく。
AnsibleでOpenLDAP環境構築 -⑦ldapクライアント インストールか、LDAP構築 まとめを参照して頂けると幸い。
まずはansibleサーバにldapユーザでsshログインを行う。無事にログインでき、プロンプトが「[<ユーザ名>@<サーバ名> ~]$」となれば、ldapサーバからldapユーザの情報を受け取り、ldapユーザが使用できていることになる。
[user01@ansible_sv ~]$
ここまできたら、上記①のplaybookを再び使うことにする。
[user01@ansible_sv ~]$ sudo cat /etc/ansible/yml/sample.yml あなたはシステム管理者から通常の講習を受けたはずです。 これは通常、以下の3点に要約されます: #1) 他人のプライバシーを尊重すること。 #2) タイプする前に考えること。 #3) 大いなる力には大いなる責任が伴うこと。 パスワード: - hosts: ldapclient gather_facts: no remote_user: root tasks: - name: yum update yum: name=* state=present - name: create txt file: state=touch path=/home/user01/sample.txt owner=user01 group=ldapmanager mode=0666 [user01@ansible_sv ~]$
初回にsudoを実行すると、上記の質問が出てくる。そのあとsudo実行用のパスワードを入力する。
ldapユーザを登録した際に、「userPassword:」モジュールで指定した文字列がsudo実行用のパスワードになる。本稿では「ldapuser01」となる。
①ansibleサーバ⇒rootユーザ、playbook実行先ユーザ⇒rootユーザとの差は、ansible-playbookコマンドをldapユーザで実行するということ。rootユーザで実行した場合と結果が異なるところに注目したい。
[user01@ansible_sv ~]$ ansible-playbook /etc/ansible/yml/sample.yml --ask-pass SSH password: PLAY [ldapclient] ************************************************************************************************************************************ TASK [yum update] *******************************************************************************************************************************
。。。
待てど暮らせどここから先に進まず。しょうがないのでCtrl+Cキーで脱出。すると、
[user01@ansible_sv ~]$ ansible-playbook /etc/ansible/yml/sample.yml --ask-pass
SSH password:
PLAY [ldapclient] ************************************************************************************************************************************
TASK [yum update] *******************************************************************************************************************************
^CProcess WorkerProcess-1:
Traceback (most recent call last):
File "/usr/lib64/python2.7/multiprocessing/process.py", line 258, in _bootstrap
self.run()
File "/usr/lib/python2.7/site-packages/ansible/executor/process/worker.py", line 118, in run
self._rslt_q
File "/usr/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 130, in run
res = self._execute()
File "/usr/lib/python2.7/site-packages/ansible/executor/task_executor.py", line 528, in _execute
result = self._handler.run(task_vars=variables)
File "/usr/lib/python2.7/site-packages/ansible/plugins/action/normal.py", line 45, in run
results = merge_hash(results, self._execute_module(tmp=tmp, task_vars=task_vars, wrap_async=wrap_async))
File "/usr/lib/python2.7/site-packages/ansible/plugins/action/__init__.py", line 642, in _execute_module
tmp = self._make_tmp_path()
File "/usr/lib/python2.7/site-packages/ansible/plugins/action/__init__.py", line 245, in _make_tmp_path
tmpdir = self._remote_expand_user(self._play_context.remote_tmp_dir, sudoable=False)
File "/usr/lib/python2.7/site-packages/ansible/plugins/action/__init__.py", line 549, in _remote_expand_user
data = self._low_level_execute_command(cmd, sudoable=False)
File "/usr/lib/python2.7/site-packages/ansible/plugins/action/__init__.py", line 889, in _low_level_execute_command
rc, stdout, stderr = self._connection.exec_command(cmd, in_data=in_data, sudoable=sudoable)
File "/usr/lib/python2.7/site-packages/ansible/plugins/connection/ssh.py", line 955, in exec_command
(returncode, stdout, stderr) = self._run(cmd, in_data, sudoable=sudoable)
File "/usr/lib/python2.7/site-packages/ansible/plugins/connection/ssh.py", line 240, in wrapped
return_tuple = func(self, *args, **kwargs)
File "/usr/lib/python2.7/site-packages/ansible/plugins/connection/ssh.py", line 853, in _run
return self._bare_run(cmd, in_data, sudoable, checkrc)
File "/usr/lib/python2.7/site-packages/ansible/plugins/connection/ssh.py", line 693, in _bare_run
events = selector.select(timeout)
File "/usr/lib/python2.7/site-packages/ansible/compat/selectors/_selectors2.py", line 482, in select
maxevents=max_events)
File "/usr/lib/python2.7/site-packages/ansible/compat/selectors/_selectors2.py", line 136, in _syscall_wrapper
result = func(*args, **kwargs)
KeyboardInterrupt
[ERROR]: User interrupted execution
[user01@ansible_sv ~]$
わっ、なんか出た 汗
見たところpython系エラーなんだけど、いちいち全部追うのは不毛すぎるので、ちらちら見てみると、
sudoable=False
という気になる表示があった。たしかにansible-playbookを実行するときにsudoはつけてない。
でもsudoをつけると、結局①ansibleサーバ⇒rootユーザ、playbook実行先ユーザ⇒rootユーザと一緒になるのでは。。。
と疑問を持ちながら、一応sudoつきで実行してみることにする。
[user01@ansible_sv ~]$ sudo ansible-playbook /etc/ansible/yml/sample.yml --ask-pass パスワード: SSH password: PLAY [ldapclient] ************************************************************************************************************************************ TASK [yum update] ************************************************************************************************************************************ ok: [192.168.3.7] TASK [create txt] ********************************************************************************************************************************* changed: [192.168.3.7] PLAY RECAP ******************************************************************************************************************************************* 192.168.3.7 : ok=2 changed=1 unreachable=0 failed=0 [user01@ansible_sv ~]$
思った通りでした ^^;
ただ面倒なことに、sudoをつけることによってsudoパスワードとrootパスワードの両方を聞かれることになってしまうという。
ldapユーザからの実行については、まだまだ改善の余地があるような気がする。
⑤ansibleサーバ⇒ldapユーザ、playbook実行先ユーザ⇒ldapユーザ
このパターンを行う場合も、④ansibleサーバ⇒ldapユーザ、playbook実行先ユーザ⇒rootユーザと同様に事前に以下の作業が必要。
・ansibleサーバにもldapクライアントを構築しておく。
・ansibleサーバにldapクライアントを構築した後、/home/<ldapユーザ名>/.ssh配下にssh秘密鍵を格納しておく。
AnsibleでOpenLDAP環境構築 -⑦ldapクライアント インストールか、LDAP構築 まとめを参照して頂けると幸い。
まずは、ansibleサーバにldapユーザでsshログインをする。無事にログインでき、プロンプトが「[<ユーザ名>@<サーバ名> ~]$」となれば、ldapサーバからldapユーザの情報を受け取り、ldapユーザが使用できていることになる。
[user01@ansible_sv ~]$
ldapユーザ(本稿ではuser01)でansible-playbookを実行するのだが、この場合①のplaybookを少し変える。
各モジュールをsudoで実行されるように、「become」「become_user」というモジュールを記述する。
[user01@ansible_sv ~]$ sudo cat /etc/ansible/yml/sample.yml パスワード: - hosts: ldapclient gather_facts: no become: yes become_user: root tasks: - name: yum update yum: name=* state=present - name: create txt file: state=touch path=/home/user01/sample.txt owner=user01 group=ldapmanager mode=0666 [user01@ansible_sv ~]$
初回にsudoを実行すると、上記の質問が出てくる。そのあとsudo実行用のパスワードを入力する。
ldapユーザを登録した際に、「userPassword:」モジュールで指定した文字列がsudo実行用のパスワードになる。本稿では「ldapuser01」となる。
モジュールの説明。
「become: yes」は、モジュールに対しsudoで実行しますか?はい!という意味。
「become_user: root」は、sudoはどのユーザ権限を使用しますか?rootで!という意味。
becomeモジュールを記述することにより、それ以下の階層で実行するモジュールはすべてsudoつきで実行される。
通常linuxではsudo権限が与えられたユーザでsudoつきのlinuxコマンドを実行すると、sudoのパスワードを聞かれるようになる(/etc/sudoersでNOPASSWORDを指定すれば聞かれないが、本稿ではやらない)が、ansibleもbecomeモジュールを記述したplaybookを実行すると、それ以下の階層はもれなくsudoつきでモジュールが実行される。そのときにsudoパスワードが通っていないとansibleがエラーとなるので、パスワードを通す必要がある。
前提条件で/etc/ansible/ansible.cfgの「ask_sudo_pass」をコメントアウトしているので、普通にansible-playbookを実行してもsudoパスワードを聞かれることがなく、しかも実行結果で「”sudo: パスワー ドが必要です\r\n”」と表示されエラーとなる。
[user01@ansible_sv ~]$ ansible-playbook /etc/ansible/yml/sample.yml PLAY [ldapclient] ************************************************************************************************************************************ TASK [yum update] ************************************************************************************************************************************ Enter passphrase for key '/home/user01/.ssh/id_ed25519': fatal: [192.168.3.7]: FAILED! => {"changed": false, "module_stderr": "Shared connection to 192.168.3.7 closed.\r\n", "module_stdout": "sudo: パスワー ドが必要です\r\n", "msg": "MODULE FAILURE", "rc": 1} PLAY RECAP ******************************************************************************************************************************************* 192.168.3.7 : ok=0 changed=0 unreachable=0 failed=1 [user01@ansible_sv ~]$
このような場合は、「–ask-become-pass」オプションをつけると、sudoのパスワードを聞かれるようになる。
[user01@ansible_sv ~]$ ansible-playbook /etc/ansible/yml/sample.yml --ask-become-pass SUDO password: PLAY [ldapclient] ************************************************************************************************************************************ TASK [yum update] ************************************************************************************************************************************ Enter passphrase for key '/home/user01/.ssh/id_ed25519': ok: [192.168.3.7] TASK [create txt] ********************************************************************************************************************************* changed: [192.168.3.7] PLAY RECAP ******************************************************************************************************************************************* 192.168.3.7 : ok=2 changed=1 unreachable=0 failed=0 [user01@ansible_sv ~]$
ansible-playbookコマンドを実行直後、「SUDO password:」でsudoパスワードを聞かれる。ldapユーザに設定したuserPassword(ここではldapuser01)を入力すると、無事にansibleのタスクが全部通る。
ただしここでも、ansible-playbook実行中にssh公開鍵のパスフレーズを聞かれている。
今回使用しているplaybookはモジュールも少ないので大したことはないが、多数モジュールを組んだ場合そのモジュールを実行するごとにssh公開鍵のパスフレーズを聞かれたりするから、ものすごく面倒。
そこで、いったん自分の秘密鍵にパスフレーズを事前に登録することによって、連続でパスフレーズを入力しなければならない事態を回避することができる。
evalコマンドとssh-addコマンドを、以下のように実行する。
[user01@ansible_sv ~]$ eval "$(ssh-agent)" Agent pid 3078 [user01@ansible_sv ~]$ ssh-add ~/.ssh/id_ed25519 Enter passphrase for /home/user01/.ssh/id_ed25519: Identity added: /home/user01/.ssh/id_ed25519 (root@ldapserver) [user01@ansible_sv ~]$
「Enter passphrase for ~」の箇所で、パスフレーズ(本稿ではsshmanager)を入力する。(root@ldapserver)は公開鍵から消すの忘れてた。。。害はないのでこのままにする。
これで、再度ansible-playbookコマンドを実行する。
[user01@ansible_sv ~]$ ansible-playbook /etc/ansible/yml/sample.yml --ask-become-pass SUDO password: PLAY [ldapclient] ************************************************************************************************************************************ TASK [yum update] ************************************************************************************************************************************ ok: [192.168.3.7] TASK [create txt] ********************************************************************************************************************************* changed: [192.168.3.7] PLAY RECAP ******************************************************************************************************************************************* 192.168.3.7 : ok=2 changed=1 unreachable=0 failed=0 [user01@ansible_sv ~]$
「Enter passphrase for key ‘/home/user01/.ssh/id_ed25519’:」が出てこなくなりました\(^o^)/
⑥ansibleサーバ⇒ldapユーザ、playbook実行先ユーザ⇒モジュール毎にrootユーザまたはldapユーザを指定
このパターンを行う場合も、④ansibleサーバ⇒ldapユーザ、playbook実行先ユーザ⇒rootユーザと同様に事前に以下の作業が必要。
・ansibleサーバにもldapクライアントを構築しておく。
・ansibleサーバにldapクライアントを構築した後、/home/<ldapユーザ名>/.ssh配下にssh秘密鍵を格納しておく。
AnsibleでOpenLDAP環境構築 -⑦ldapクライアント インストールか、LDAP構築 まとめを参照して頂けると幸い。
user01でldapクライアントへsshログイン実行し、プロンプトがuser01ありになるところまでを確認。
[user01@ansible_sv ~]$
このパターンの場合、playbookをさらに以下の内容に変えてみた。
[user01@ansible_sv ~]$ sudo cat /etc/ansible/yml/sample.yml パスワード: - hosts: ldapclient gather_facts: no tasks: - name: yum update remote_user: root yum: name=* state=present - name: create txt 1 become: yes become_user: root file: state=touch path=/root/sample1.txt owner=root group=root mode=0666 - name: create txt 2 file: state=touch path=/root/sample2.txt owner=root group=root mode=0666 - name: create txt 3 file: state=touch path=/home/user01/sample3.txt owner=root group=root mode=0666 [user01@ansible_sv ~]$
各nameモジュールでremote_userやbecomeをつけたりつけなかったりの構成。
「 – name: yum update」のyumモジュールはrootユーザにて実行。
「 – name: create txt 1」のfileモジュールはsudoつきで実行。一応rootユーザでないと操作できない/root配下にファイルを作るようにしている。
「 - name: create txt 2」のfileモジュールはremote_userもbecome/become_userもない状態でファイルを作る。/root配下にファイルを作るからどうなるか楽しみ。
「 – name: create txt 3」のfileモジュールはldapユーザのホームディレクトリにファイルを作る。これもremote_user,become/become_userモジュールがない状態。
パターン④⑤の教訓もあり、ここで使用するansible-playbookコマンドのオプションは「–ask-pass」と「–ask-become-pass」の両方と想定。
しかもsudoつきで実行してみることにする。
[user01@ansible_sv ~]$ sudo ansible-playbook /etc/ansible/yml/sample.yml --ask-pass --ask-become-pass パスワード: SSH password: SUDO password[defaults to SSH password]: PLAY [ldapclient] ************************************************************************************************************************************ TASK [yum update] ************************************************************************************************************************************ ok: [192.168.3.7] TASK [create txt 1] ********************************************************************************************************************************** changed: [192.168.3.7] TASK [create txt 2] ********************************************************************************************************************************** changed: [192.168.3.7] TASK [create txt 3] ********************************************************************************************************************************** changed: [192.168.3.7] PLAY RECAP ******************************************************************************************************************************************* 192.168.3.7 : ok=4 changed=3 unreachable=0 failed=0 [user01@ansible_sv ~]$
一応うまくいったけど、ansible-playbookコマンド冒頭のsudoパスワードと、rootパスワードと、playbook上のbecomeモジュール用にさらにsudoパスワードと。。。
一回コマンド打つのにどんだけパスワード打たすねん!て感じ。
実は、ansible-playbookコマンドをオプション変えたりしていろいろ試してみたけど、–ask-become-passはなくても行けました。
[user01@ansible_sv ~]$ sudo ansible-playbook /etc/ansible/yml/sample.yml --ask-pass パスワード: SSH password: PLAY [ldapclient] ************************************************************************************************************************************ TASK [yum update] ************************************************************************************************************************************ ok: [192.168.3.7] TASK [create txt 1] ********************************************************************************************************************************** changed: [192.168.3.7] TASK [create txt 2] ********************************************************************************************************************************** changed: [192.168.3.7] TASK [create txt 3] ********************************************************************************************************************************** changed: [192.168.3.7] PLAY RECAP ******************************************************************************************************************************************* 192.168.3.7 : ok=4 changed=3 unreachable=0 failed=0 [user01@ansible_sv ~]$
まぁ、sudoつきでansible-playbookコマンドを実行しているので、結局rootユーザでansible-playbookコマンドを実行しているのと変わんないんだよね。。
rootユーザでbecomeつけても意味がない(root権限でモジュールを実行しているのと同じになる)ので、本来ldapユーザでは扱えない「 - name: create txt 2」の/rootディレクトリにもファイルを作ることができる。
言えること
①~⑥パターンをやってみて言えること。
・ansible-playbookコマンドを実行する場合は、playbookでremote_userやbecome/become_userがどのように割り当てられているか確認し、–ask-passや–ask-become-passオプションで権限クリアできるようにしておく。
・ansibleサーバ側はrootユーザか、もしくはsudoつきにしてansible-playbookコマンドを実行するとよい(かも)。