LoginSignup
22
21

More than 5 years have passed since last update.

Ansibleのsudo ask-sudo-pass はどう実装されているか

Last updated at Posted at 2014-02-14

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を指定すると標準入力からパスワードを受け取れるようです。

22
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
21