Ansibleを使ってリモートサーバーのセットアップをするときにsudoをしばしば使うのですが、定期的に "Missing sudo password" と怒られるのをよくやるので、ここにまとめておきたいと思います。
Summary for the impatient
リモートサーバーのsshdの設定が適切でないと、Ansibleによる自動化は失敗します。Ansibleを実行するノードではなくAnsibleで自動化する対象のノードに対して以下のような設定を行えば回避可能です。「cloud-user」のところは実際に存在するユーザーに置き換えるか、Ansible用のユーザーを作っておくと良いでしょう。Ansible Playbookで使うユーザーに対してssh-copy-id
コマンドでキーペアの交換を行っておきましょう。
wheelグループはrootライクな権限を持つグループです。suコマンドを通じて、rootユーザになることができます。Linuxディストリビューションによっては違うグループ名の場合があります。たとえばDebian/Ubuntuの場合は sudo
です。
$ sudo vi /etc/ssh/sshd_config PasswordAuthentication no #sshによるパスワード認証を許可しない $ sudo systemctl restart sshd #設定反映のためsshdを再起動 $ sudo usermod -aG wheel cloud-user #wheelグループにcloud-userを追加 $ sudo visudo #sudoの設定変更 ... #%wheel ALL=(ALL) ALL #デフォルト設定。コメント化する %wheel ALL=(ALL) NOPASSWD: ALL #追記。sudo実行時のパスワード入力をやめる
問題の詳細と解決策
問題の詳細
Ansibleでまず、こんなインベントリーを作ると思います。インベントリーファイルは対象のサーバーを記述するためのファイルです。そのほか、認証に必要な情報(例えばユーザー名とか秘密鍵、使うPythonの指定)を行います。 ansible_python_interpreter
を指定した場合はそのバージョンが対象のホストにインストールされている必要があります。
% cat hosts [node] 192.168.0.100 [all:vars] ansible_python_interpreter=/usr/bin/python3 ansible_user=cloud-user ansible_ssh_private_key_file=/Users/macuser/.ssh/id_rsa
Playbookはとりあえず今回はこれを使うことにします。単純にpingを実行するだけのPlaybookです。ちなみにpingを実行するのに多くの場合sudoコマンドは実行する必要がありませんが、一般的にPlaybookで何かセットアップするときにはsudoはほぼ使うため、become: yes
をあえて追加しています。
% cat playbook.yaml --- - hosts: all become: yes tasks: - name: try ping ping:
そして次のように実行するわけですが、こんな感じで失敗するはずです。
% ansible-playbook playbook.yaml -i hosts ... TASK [Gathering Facts] ********************************************************* fatal: [192.168.0.100]: FAILED! => {"msg": "Missing sudo password"}
普通にLinuxをセットアップすると、ユーザに対してパスワード認証が可能になっていると思います。またデフォルトのLinuxの設定だとsudoを実行するときにユーザーのパスワードを入力するように設定されていると思います。このため、セットアップ後デフォルトのままのLinuxホストをAnsibleで何らかの自動化をしようとすると何らかの問題が発生してうまくいかないと思います。
今回エラーとして表示された「Ansible Missing sudo password」メッセージを検索すると、次の情報を見つけると思います。ヒントにはなりますが色々書かれていること、書かれていないことがあるので、混乱してしまいます。そこで今回、対応方法をまとめておこうと思いました。
問題の解決策
これを下記のように設定すると回避できます。
SSHDの設定変更
パスワード認証の無効化を行い、SSH Server (sshd) を再起動します。
$ sudo vi /etc/ssh/sshd_config PasswordAuthentication no $ sudo systemctl restart sshd
公開鍵認証を出来るようにするために、事前に次のコマンドを実行するか、/home/cloud-user/.ssh/authorized_keys
ファイルに公開鍵の入力を忘れずに(ssh-copy-idを使う場合は、初回の実行時に該当ユーザーのパスワードの入力が必要です)。
$ ssh-copy-id -i ~/.ssh/id_rsa cloud-user@192.168.1.100
sudoの設定変更
任意のユーザーでsudoコマンドを実行したときにパスワードが聞かれないように設定変更します。
$ sudo visudo ... cloud-user ALL=(ALL) NOPASSWD: ALL
これで終わりのはずですが、実はこの設定をしても引き続きsudoコマンドを実行するとパスワードを聞かれてしまいます。このままだとAnsibleで公開鍵認証でリモートサーバーのセットアップは出来ません。
[cloud-user@cent8-test2 ~]$ sudo visudo [sudo] cloud-user のパスワード:
実際に実行してみると次のような感じです。
% ansible-playbook playbook.yaml -i hosts PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* fatal: [192.168.0.100]: FAILED! => {"ansible_facts": {}, "changed": false, "failed_modules": {"setup": {"failed": true, "module_stderr": "Shared connection to 192.168.0.100 closed.\r\n", "module_stdout": "sudo: パスワードが必要です\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}}, "msg": "The following modules failed to execute: setup\n"}
この状態では-K
オプションをつけて実行することで、対象のサーバーのsudoパスワードを聞かれるので、正しいパスワードを入力すれば一応通すことは出来ます。ただこれは自動化ではないですし、やはりパスワードを聞かれる状態は格好良くはありません。
% ansible-playbook playbook.yaml -i hosts -K BECOME password: PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [192.168.0.100] TASK [try ping] **************************************************************** ok: [192.168.0.100] PLAY RECAP ********************************************************************* 192.168.0.100 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
そこで、該当のユーザーをwheelグループに追加します。先ほど追加した行はコメント化するか削除して、wheelグループの場合はsudoコマンド実行時にパスワードを聞かれない設定を追加します。
なお、DebianやUbuntuではwheelグループではなくsudoグループです。
$ sudo usermod -aG wheel cloud-user $ sudo visudo #cloud-user ALL=(ALL) NOPASSWD: ALL #コメント化か削除 #%wheel ALL=(ALL) ALL #デフォルト設定。コメント化する %wheel ALL=(ALL) NOPASSWD: ALL #追記
設定変更後、-Kオプションを取り除いて実行してみます。
% ansible-playbook playbook.yaml -i hosts PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [192.168.0.100] TASK [try ping] **************************************************************** ok: [192.168.0.100] PLAY RECAP ********************************************************************* 192.168.0.100 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
問題なく実行できました。
まとめ
今回取り上げた問題ですが、おそらく何らかのオーケストレーションツールを使ってデプロイされたサーバーやクラウド上のサーバーではデフォルトで今回のような設定がされており、はまることはないと思います。
今回のような設定を一切変更せずパスワード認証でPlaybookを流したい場合は、 sshpass
と ansible-playbook
コマンドの -K
および -k
オプションを使う方法があります。ただ色々と面倒くさい(例えばクライアント側にsshpassを入れる必要があったり、パスワードの管理がちょっと面倒だったり、Missing sudo password in Ansibleにパスワードを書いておく方法はあるけどセキュアじゃないし、CLIの実行時にパスワードを入力する方法もあるけどコマンドの履歴にパスワードが残ってしまいセキュアではないし..)ので、公開鍵認証の方が良いです。
おまけ
ちなみに sshpass
の件を調査していたら、次の記事を見つけました。7年前の自分が書いてましたね。