问题
使用最新的稳定版 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 }
成功了!但是为什么呢?!
总结
- Server1 似乎正在等待 sudo 密码提示,而 Server2 运行正常。
- 在 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
对其他人非常有帮助。(希望如此!)