ansible の -Kオプションによるリモートホストへのsudoのパスワード引き渡しが便利すぎるのですが、どのように実装されているか気になったので調べてみた。
https://github.com/ansible/ansible/blob/devel/lib/ansible/runner/connection_plugins/paramiko_ssh.py#L209
この辺で、sudo_passが使われている。
ansible/ansible/blob/devel/lib/ansible/runner/connection_plugins/paramiko_ssh.py#L209
if self.runner.sudo or sudoable:
shcmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)
elif self.runner.su or su:
shcmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd)
vvv("EXEC %s" % shcmd, host=self.host)
sudo_output = ''
try:
chan.exec_command(shcmd)
if self.runner.sudo_pass or self.runner.su_pass:
while not sudo_output.endswith(prompt) and success_key not in sudo_output:
chunk = chan.recv(bufsize)
if not chunk:
if 'unknown user' in sudo_output:
raise errors.AnsibleError(
'user %s does not exist' % sudo_user)
else:
raise errors.AnsibleError('ssh connection ' +
'closed waiting for password prompt')
sudo_output += chunk
if success_key not in sudo_output:
if sudoable:
chan.sendall(self.runner.sudo_pass + '\n')
elif su:
chan.sendall(self.runner.su_pass + '\n')
sendallで標準入力に流し込んでいるもよう。
make_sudo_cmdをみてみよう
ansible/ansible/blob/devel/lib/ansible/utils/__init__.py
def make_sudo_cmd(sudo_user, executable, cmd):
"""
helper function for connection plugins to create sudo commands
"""
# Rather than detect if sudo wants a password this time, -k makes
# sudo always ask for a password if one is required.
# Passing a quoted compound command to sudo (or sudo -s)
# directly doesn't work, so we shellquote it with pipes.quote()
# and pass the quoted string to the user's shell. We loop reading
# output until we see the randomly-generated sudo prompt set with
# the -p option.
randbits = ''.join(chr(random.randint(ord('a'), ord('z'))) for x in xrange(32))
prompt = '[sudo via ansible, key=%s] password: ' % randbits
success_key = 'SUDO-SUCCESS-%s' % randbits
sudocmd = '%s -k && %s %s -S -p "%s" -u %s %s -c %s' % (
C.DEFAULT_SUDO_EXE, C.DEFAULT_SUDO_EXE, C.DEFAULT_SUDO_FLAGS,
prompt, sudo_user, executable or '$SHELL', pipes.quote('echo %s; %s' % (success_key, cmd)))
return ('/bin/sh -c ' + pipes.quote(sudocmd), prompt, success_key)
sudocmd を展開するとこんな感じか
sudo -k; sudo -S -p “[sudo via ansible, key=randbits]” -u root /bin/bash “echo SUDO-SUCCESS-randbits; cmd”
いろいろと使った事が無いsudoのオプションが並んでいる。
-S
-S (stdin) オプションを指定すると、 sudo はパスワードをターミナルデバイスからではなく、 標準入力から読み込む。パスワードは末尾に改行を付けなければならない。
-k [command]
-k (kill) オプションを単独で使うと、 sudo はユーザの保存された認証情報を無効にする。 次回 sudo を実行するとき、パスワードが要求されることになるわけだ。 このオプション自体はパスワードを必要としない。
-p prompt
-p (prompt) オプションを使うと、 デフォルトのパスワードプロンプトを変更して、好きな文句にすることができる。 sudoers ポリシーでは以下のパーセント (` %
') エスケープが使用できる。
sudo に-Sを指定すると標準入力からパスワードを受け取れるようです。