问题

问题

问题

使用最新的稳定版 Ansible 时,我遇到了一个奇怪的问题,我的剧本在“Gathering_Facts”期间在一台服务器上挂起,但在使用 Sudo 时在其他类似服务器上运行良好。在 Ansible 服务器上,我以我的用户(NIS 用户)身份运行并使用须藤(以 root 身份)在远程服务器上进行更改。如果我从此设置中删除 Sudo,则一切正常。

设置

软件版本

  • 操作系统:RHEL6.4
  • Ansible 版本:ansible 1.8.2
  • Sudo 版本
    Sudo 版本 1.8.6p3
    Sudoers 策略插件版本 1.8.6p3
    Sudoers 文件语法版本 42
    Sudoers I/O 插件版本 1.8.6p3
    
  • SSH 版本:OpenSSH_5.3p1,OpenSSL 1.0.0-fips 2010 年 3 月 29 日

服务器地图

                   -------- User1@Server1:sudo -H -S -p(挂在 Gathering_Facts 上)
                  /
用户1@Ansible ----
                  \
                   -------- User1@Server2:sudo -H -S -p(工作正常)

用户

  • 用户 1:服务器 1 和服务器 2 上均可访问 NIS 的用户。
  • root:每个服务器的本地 root 用户。

Ansible 配置

我的相关部分ansible.cfg

ansible.cfg

sudo           = true
sudo_user      = root
ask_sudo_pass  = True
ask_pass       = True
...
gathering = smart
....
# change this for alternative sudo implementations
sudo_exe = sudo

# what flags to pass to sudo
#sudo_flags = -H
...
# remote_user = ansible

这是一个简单的测试剧本,用于触摸一个空文件然后将其删除。实际上,我只是想测试我是否可以让 Ansible 在远程服务器上正确使用 sudo。如果剧本可以运行,那就没问题了。

测试文件

---
- hosts: Server1:Server2
  vars:
  - test_file: '/tmp/ansible_test_file.txt'
  sudo: yes
  tasks:
  - name: create empty file to test connectivity and sudo access
    file: dest={{ test_file }}
          state=touch
          owner=root group=root mode=0600
    notify:
    - clean
  handlers:
  - name: clean
    file: dest={{ test_file }}
          state=absent

Sudo 配置

/etc/sudoers

Host_Alias SRV     = Server1, Server2
User_Alias SUPPORT = User1, User2, User3
SUPPORT SRV=(root) ALL

此 sudo 配置在两个服务器上均能正常工作。 sudo 本身没有问题。

我如何管理这一切

很简单的:

$ ansible-playbook 测试.yml
SSH 密码:
sudo 密码 [默认为 SSH 密码]:

播放 [服务器1:服务器2] *************************************************

收集事实 ********************************************************************
确定:[服务器2]
失败:[Server1] => {“失败”:true,“已解析”:false}

抱歉,请再试一次。
[sudo via ansible,key=mxxiqyvztlfnbctwixzmgvhwfdarumtq] 密码:
sudo:1 次错误密码尝试


任务:[创建空文件来测试连接和 sudo 访问] ****************
已更改:[服务器2]

已通知:[清洁] *********************************************************************
已更改:[服务器2]

播放回顾 ************************************************************************
           要重试,请使用:--limit @/home/User1/test.retry

服务器1:正常=0 已更改=0 无法访问=0 失败=1   
服务器2:正常=3 已更改=2 无法访问=0 失败=0

无论我明确输入 SSH/Sudo 密码还是隐式输入(让 sudo 将默认值传递给 SSH),都会失败。

远程服务器日志

服务器 1(失败)

/var/log/安全

12 月 31 日 15:21:10 Server1 sshd[27093]: 从 xxxx 端口 51446 ssh2 接受 User1 的密码
12 月 31 日 15:21:10 Server1 sshd[27093]: pam_unix(sshd:session): 会话由 (uid=0) 为用户 User1 打开
12 月 31 日 15:21:11 Server1 sshd[27095]: sftp 子系统请求
12 月 31 日 15:21:11 Server1 sudo:pam_unix(sudo:auth):身份验证失败;logname=User1 uid=187 euid=0 tty=/dev/pts/1 ruser=User1 rhost=user=User1
12 月 31 日 15:26:13 Server1 sudo:pam_unix(sudo:auth):对话失败
12 月 31 日 15:26:13 Server1 sudo:pam_unix(sudo:auth):auth 无法识别 [User1] 的密码
12 月 31 日 15:26:13 Server1 sudo:用户 1:1 次密码尝试错误;TTY=pts/1;PWD=/home/User1;USER=root;COMMAND=/bin/sh -c echo SUDO-SUCCESS-mxxiqyvztlfnbctwixzmgvhwfdarumtq;LANG=C LC_CTYPE=C /usr/bin/python /tmp/.ansible/tmp/ansible-tmp-1420039272.66-164754043073536/setup;rm -rf /tmp/.ansible/tmp/ansible-tmp-1420039272.66-164754043073536/ >/dev/null 2>&1
12 月 31 日 15:26:13 Server1 sshd[27093]: pam_unix(sshd:session): 用户 User1 的会话已关闭

Server2(运行良好)

/var/log/安全

12 月 31 日 15:21:12 Server2 sshd[31447]: 从 xxxx 端口 60346 ssh2 接受 User1 的密码
12 月 31 日 15:21:12 Server2 sshd[31447]: pam_unix(sshd:session): 由 (uid=0) 为用户 User1 打开会话
12 月 31 日 15:21:12 Server2 sshd[31449]: sftp 子系统请求
12 月 31 日 15:21:12 Server2 sudo:用户 1:TTY=pts/2;PWD=/home/User1;USER=root;COMMAND=/bin/sh -c echo SUDO-SUCCESS-vjaypzeocvrdlqalxflgcrcoezhnbibs;LANG=C LC_CTYPE=C /usr/bin/python /tmp/.ansible/tmp/ansible-tmp-1420039272.68-243930711246149/setup;rm -rf /tmp/.ansible/tmp/ansible-tmp-1420039272.68-243930711246149/ >/dev/null 2>&1
12 月 31 日 15:21:14 Server2 sshd[31447]: pam_unix(sshd:session): 用户 User1 的会话已关闭

STrace 输出

以下是针对 root 用户的 ansible 命令时 strace 的输出。命令:

while [[ -z $(ps -fu root|grep [a]nsible|awk '{print $2}') ]]; do
    continue
done
strace -vfp $(ps -fu root|grep [a]nsible|awk '{print $2}') -o /root/strace.out`

服务器1

23650 选择(0,NULL,NULL,NULL,{1,508055})= 0(超时)
23650 套接字(PF_NETLINK, SOCK_RAW, 9) = 10
23650 fcntl(10,F_SETFD,FD_CLOEXEC)= 0
23650 读取链接(“/ proc / self / exe”,“ / usr / bin / sudo”,4096)= 13
23650 发送至(10,“|\0\0\0L\4\5\0\1\0\0\0\0\0\0\0op=PAM:authentic”...,124,0,{sa_family=AF_NETLINK,pid=0,groups=00000000},12)= 124
23650 民意调查 ([{fd=10, 事件=POLLIN}], 1, 500) = 1 ([{fd=10, revents=POLLIN}])
23650 recvfrom(10, "$\0\0\0\2\0\0\0\1\0\0\0b\\\0\0\0\0\0\0|\0\0\0L\4\5\0\1\0\0\0"..., 8988, MSG_PEEK|MSG_DONTWAIT, {sa_family=AF_NETLINK, pid=0, groups=00000000}, [12]) = 36
23650 recvfrom(10, "$\0\0\0\2\0\0\0\1\0\0\0b\\\0\0\0\0\0\0|\0\0\0L\4\5\0\1\0\0\0"..., 8988, MSG_DONTWAIT, {sa_family=AF_NETLINK, pid=0, groups=00000000}, [12]) = 36
23650 关闭(10) = 0
23650 写入(2,“抱歉,请重试。\n”,18)= 18
23650 获取时间 ({1420050850, 238344}, NULL) = 0
23650 套接字(PF_FILE,SOCK_STREAM,0)= 10
23650 连接(10,{sa_family = AF_FILE,路径“/ var / run / dbus / system_bus_socket”},33)= 0

服务器2

6625 select(8, [5 7], [], NULL, NULL) = ? ERESTARTNOHAND(要重新启动)
6625 --- SIGCHLD(子进程退出)@0(0)---
6625 写入(8,“\21”, 1)= 1
6625 rt_sigreturn(0x8) = -1 EINTR (中断系统调用)
6625 选择(8,[5 7],[],NULL,NULL)= 1(在[7]中)
6625 读取(7,“\21”, 1)= 1
6625 wait4(6636,[{WIFEXITED(s) && WEXITSTATUS(s) == 0}],WNOHANG|WSTOPPED,NULL)= 6636
6625 rt_sigprocmask (SIG_BLOCK,NULL,[],8) = 0
6625 套接字(PF_NETLINK, SOCK_RAW, 9) = 6
6625 fcntl (6, F_SETFD, FD_CLOEXEC) = 0
6625 读取链接(“/proc/self/exe”,“/usr/bin/sudo”,4096)= 13
6625 发送至(6,“x\0\0\0R\4\5\0\6\0\0\0\0\0\0\0op=PAM:session_c”...,120,0,{sa_family=AF_NETLINK,pid=0,groups=00000000},12)= 120
6625 轮询 ([{fd=6, events=POLLIN}], 1, 500) = 1 ([{fd=6, revents=POLLIN}])
6625 recvfrom(6, "$\0\0\0\2\0\0\0\6\0\0\0\330\355\377\377\0\0\0\0x\0\0\0R\4\5\0\6\0\0\0"..., 8988, MSG_PEEK|MSG_DONTWAIT, {sa_family=AF_NETLINK, pid=0, groups=00000000}, [12]) = 36
6625 recvfrom(6, "$\0\0\0\2\0\0\0\6\0\0\0\330\355\377\377\0\0\0\0x\0\0\0R\4\5\0\6\0\0\0"..., 8988, MSG_DONTWAIT, {sa_family=AF_NETLINK, pid=0, groups=00000000}, [12]) = 36
6625 关闭(6)= 0
6625 打开(“/etc/security/pam_env.conf”,O_RDONLY)= 6
6625 fstat (6, {st_dev=makedev(253, 1), st_ino=521434, st_mode=S_IFREG|0644, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=8, st_size=2980, st_atime=2014/12/31-16:10:01, st_mtime=2012/10/15-08:23:52, st_ctime=2014/06/16-15:45:35}) = 0
6625 mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0)= 0x7fbc3a59a000
6625 read(6, "#\n# 这是配置文件"..., 4096) = 2980
6625 读取(6,“”,4096)= 0
6625 关闭(6)= 0
6625 munmap(0x7fbc3a59a000, 4096) = 0
6625 打开(“/etc/environment”,O_RDONLY)= 6

我猜

Server1 没有正确获取密码或错误地询问/等待密码。这看起来不像是 Sudo 或 Ansible 的问题(单独来看,它们都运行良好),但 Server1 似乎没有以与 Server2 类似的方式接收凭据(或遵守凭据)。Server1 和 Server2 的用途不同,因此它们可能存在一些身份验证或软件包版本差异,但它们都是从同一个存储库构建的;因此,它们不应该有那么大的差异。

PAM 认证

我认为可能是系统具有不同的 PAM 配置,导致密码处理方式略有不同。我比较了 /etc/pam.d/ 文件(使用md5sum [file]),发现两个系统的文件相同。

测试

须藤STDIN

已测试另一个问题其中 sudo 不会从 STDIN 读取密码,但这在两台服务器上都能正常工作。

测试 Sudo Ad-Hoc

-bash-4.1$ ansible Server1 -m 文件 -a "dest=/tmp/ansible_test.txt state=touch" -sK
SSH 密码:
sudo 密码 [默认为 SSH 密码]:
服务器1 | 成功 >> {
    “已更改”:真实,
    “目标”:“/tmp/ansible_test.txt”,
    “gid”:0,
    “组”:“根”,
    “模式”:“0644”,
    “所有者”:“root”,
    “尺寸”:0,
    “状态”:“文件”,
    “uid”: 0
}

成功了!但是为什么呢?!

总结

  1. Server1 似乎正在等待 sudo 密码提示,而 Server2 运行正常。
  2. 在 Server1 上运行ansible“ad-hoc”可以正常工作。将其作为剧本运行会失败。

问题)

  • 什么原因导致我的 Ansible Sudo 配置在一台服务器上运行良好,而在另一台服务器上被拒绝?
  • 当临时运行与剧本运行时,Ansible 从本地到远程机器的密码“传递”方式是否不同?我以为它们是一样的。

我认为这接近于简单地向 GitHub 页面提交错误报告,纯粹是因为 sudo 访问会产生不同的结果,这取决于我是否运行临时程序。

答案1

我会做的是使用

strace -vfp `pidof sshd`

看看它失败在哪里。

也检查一下帐户,也许它受到了限制或者其他什么,但我敢打赌,你的 /etc/hosts 文件有问题或者在过程中发生了变化。

答案2

在这个答案中使用@lulian 作为立足点,问题归结为ansible_sudo_pass:group_vars 中定义的流氓,它覆盖了输入的密码--ask-sudo-pass

使用以下内容:

while [[ -z $(ps -eaf|grep 'sshd: [U]ser1@pts/1') ]]; do
    continue
done
strace -ff -vfp $(ps -eaf|grep 'sshd: [U]ser1@pts/1'|awk '{print $2}') -o /root/strace_sshd1_2.out

我发现write(4, "{{ password }}\n", 15)传递的是密码,而不是输入的密码。经过一番快速搜索,我确实ansible_sudo_pass在 group_vars 中找到了定义,它覆盖了我输入的密码。

作为对其他人的参考,ansible_sudo_pass:定义似乎优先于--ask-sudo-pass哪个,乍一看似乎违反直觉。最后,这是用户错误,但@lulian 在调试 SSH 交互以及发现和之间的关系方面的方法ansible_sudo_pass应该--ask-sudo-pass对其他人非常有帮助。(希望如此!)

相关内容