即使给出了Sudo通行证,Ansible也无法验证Sudo


9

问题

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

设定

软件版本

  • 作业系统:RHEL 6.4
  • Ansible版本Ansible 1.8.2
  • 须藤版本
    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上)
                  /
User1 @ Ansible ----
                  \
                   -------- User1 @ Server2:sudo -H -S -p(工作正常)

用户数

  • User1:Server1和Server2上的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 test.yml
SSH密码: 
sudo password [默认为SSH密码]:

播放[Server1:Server2] ************************************************ ** 

汇总事实**************************************************** *************** 
好的:[Server2]
失败:[Server1] => {“失败”:true,“已分析”:false}

抱歉,请再试一次。
[通过ansudo的sudo,密钥= mxxiqyvztlfnbctwixzmgvhwfdarumtq]密码: 
sudo:1次错误的密码尝试


任务:[创建空文件以测试连接性和sudo访问] **************** 
更改为:[Server2]

通知:[干净] ************************************************* **************** 
更改为:[Server2]

PLAY RECAP ************************************************ ******************** 
           要重试,请使用:--limit @ / home / User1 / test.retry

服务器1:确定= 0更改= 0 =无法访问= 0失败= 1   
Server2:ok = 3更改= 2无法访问= 0失败= 0

无论我是否显式输入SSH / Sudo密码以及隐式输入(将sudo pass默认设置为SSH)都失败。

远程服务器日志

Server1(失败)

/ var / log / secure

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:User1: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 / secure

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:User1: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的会话已关闭 

轨迹输出

这是针对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 select(0,NULL,NULL,NULL,{1,508055})= 0(超时)
23650套接字(PF_NETLINK,SOCK_RAW,9)= 10
23650 fcntl(10,F_SETFD,FD_CLOEXEC)= 0
23650 readlink(“ / proc / self / exe”,“ / usr / bin / sudo”,4096)= 13
23650 sendto(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 poll([{fd = 10,events = 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 write(2,“对不起,再试一次。\ n”,18)= 18
23650 gettimeofday({1420050850,238344},NULL)= 0
23650套接字(PF_FILE,SOCK_STREAM,0)= 10
23650 connect(10,{sa_family = AF_FILE,path =“ / var / run / dbus / system_bus_socket”},33)= 0

服务器2

6625 select(8,[5 7],[],NULL,NULL)=?ERESTARTNOHAND(要重新启动)
6625-SIGCHLD(孩子退出)@ 0(0)-
6625 write(8,“ \ 21”,1)= 1
6625 rt_sigreturn(0x8)= -1 EINTR(系统调用中断)
6625 select(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 readlink(“ / proc / self / exe”,“ / usr / bin / sudo”,4096)= 13
6625 sendto(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 poll([{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 \ 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 \ 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#这是配置fi” ...,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和2具有不同的用途,因此它们可能在身份验证或程序包版本方面有所不同,但它们都是从同一存储库构建的;因此,它们应该没什么不同。

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 password [默认为SSH密码]: 
服务器1 | 成功>> {
    “已更改”:是, 
    “ dest”:“ /tmp/ansible_test.txt”, 
    “ gid”:0, 
    “ group”:“ root”, 
    “ mode”:“ 0644”, 
    “ owner”:“ root”, 
    “大小”:0, 
    “ state”:“文件”, 
    “ uid”:0
}

成功!但为什么?!

TL; DR

  1. Server1看起来很好,而Server1似乎正在等待sudo密码提示。
  2. ansible在Server1上运行“临时”工作正常。将其作为剧本运行失败。

问题

  • 是什么导致我的Ansible Sudo配置在一台服务器上正常工作而在另一台服务器上被拒绝?
  • 当运行临时脚本和剧本时,Ansible从本地计算机到远程计算机的密码“传递”是否不同?我以为他们会是一样的。

我认为这接近于仅向GitHub页面提交错误报告,纯粹是基于sudo访问具有不同的结果,这取决于我是否临时运行。

Answers:


4

我会做的是使用

strace -vfp `pidof sshd`

并查看失败的地方。

还要检查该帐户,可能是受限制的或其他原因,但是我敢打赌,您的/ etc / hosts文件有问题,或者在此过程中确实有所更改。


谢谢,露莲 我对问题进行了一些编辑,其中一部分是STrace输出。显然,在远程服务器上启动ansible进程后,两台服务器之间的处理方式有所不同。随后的运行和跟踪捕获是一致的。
BrM13

我认为您需要从strace -vfp中获取更多信息,在顶级sshd进程中手动执行此操作,并按照输出进行操作。我不认为在阅读密码之后,它只是像在通过PAM等之前那样关闭了通道。在那一点上,请看一下sshd_config文件和hosts.deny ..看看是否可以在其中找到一些东西。
尤里安

我之前曾尝试过您的建议,但我一定错过了其中的关键要素(因此,为什么我选择在最初的STrace中观看这个烦人的过程)。另一遍,我发现传递了一个空的{{password}}变量,而不是真实的密码。由于您的回答最终使我步入正轨,因此选择单独提交另一个“答案”。
BrM13 2015年

4

使用@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于首先看起来违反直觉的原则。最后,这是用户错误,但@吕梁在调试SSH相互作用以及之间的关系发现方法ansible_sudo_pass以及--ask-sudo-pass应该为别人是非常有帮助那里。(希望!)


1
我认为Ansible优先于文件定义的变量而不是命令行选项违反直觉的,并且是不良行为。奇怪的是,它确实认识到当您通过传递选项时已损坏-e,并且您可以通过传递适当的选项来解决此问题-e
Christopher Cashell15年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.