O Ansible falha ao autenticar o Sudo mesmo quando o Sudo Pass é fornecido

9

Problema

Usando a versão mais recente e estável do Ansible, tenho um problema estranho em que meu manual fica travado em um servidor durante "Gathering_Facts", mas funciona bem em outros servidores similares ao usar o Sudo. No servidor Ansible, eu executo como meu usuário (usuário NIS) e uso o sudo (como root) no servidor remoto para fazer alterações. Se eu remover o Sudo dessa configuração, tudo funcionará bem.

Configuração

Versões de software

  • SO : RHEL 6.4
  • Versão Ansible : ansible 1.8.2
  • Versão Sudo :
    Sudo versão 1.8.6p3
    Sudoers policy plugin version 1.8.6p3
    Sudoers versão gramatical do arquivo 42
    Sudoers I / O plugin versão 1.8.6p3
    
  • Versão SSH : OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 de março de 2010

Mapa do servidor

                   -------- User1 @ Server1: sudo -H -S -p (Trava em fatos de coleta)
                  /
Usuário1 @ Ansible ----
                  \
                   -------- User1 @ Server2: sudo -H -S -p (funciona bem)

Comercial

  • Usuário1: usuário acessível ao NIS nos Servidores1 e Servidores2.
  • root: usuário root local para cada servidor.

Configuração Ansible

Partes relevantes do meu 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

Aqui está um manual de teste simples para tocar em um arquivo vazio e removê-lo. Realmente, só estou querendo testar se consigo que o Ansible use corretamente o sudo no servidor remoto. Se o manual funcionar, estou em boa forma.

TEST.yml

---
- 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

Configuração do Sudo

/ etc / sudoers

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

Essa configuração do sudo funciona bem em ambos os servidores. Sem problemas com o próprio sudo.

Como eu corro tudo

Muito simples:

$ ansible-playbook test.yml
Senha SSH: 
senha sudo [o padrão é senha SSH]:

PLAY [Servidor1: Servidor2] ******************************************** ** 

FATOS DE RECOLHA ************************************************** *************** 
ok: [Server2]
falhou: [Server1] => {"falhou": true, "analisou": false}

Desculpe, tente novamente.
[sudo via ansible, key = mxxiqyvztlfnbctwixzmgvhwfdarumtq] senha: 
sudo: 1 tentativa incorreta de senha


TAREFA: [crie um arquivo vazio para testar a conectividade e o acesso ao sudo] **************** 
alterado: [Server2]

NOTIFICADO: [limpo] ********************************************* **************** 
alterado: [Server2]

PLAY RECAP ************************************************** ******************** 
           para tentar novamente, use: --limit @ / home / User1 / test.retry

Server1: ok = 0 alterado = 0 inacessível = 0 falhou = 1   
Server2: ok = 3 alterado = 2 inacessível = 0 falhou = 0

Falha, independentemente de eu digitar explicitamente as senhas SSH / Sudo e implicitamente (deixando o sudo passar o padrão para SSH).

Logs de servidor remoto

Servidor1 (falha)

/ var / log / secure

31 de dezembro 15:21:10 Server1 sshd [27093]: Senha aceita para User1 da porta xxxx 51446 ssh2
31 de dezembro 15:21:10 Server1 sshd [27093]: pam_unix (sshd: session): sessão aberta para o usuário User1 por (uid = 0)
31 de dezembro 15:21:11 Server1 sshd [27095]: solicitação do subsistema para sftp
31 de dezembro 15:21:11 Server1 sudo: pam_unix (sudo: auth): falha de autenticação; logname = Usuário1 uid = 187 euid = 0 tty = / dev / pts / 1 ruser = Usuário1 rhost = usuário = Usuário1
31 de dezembro 15:26:13 Server1 sudo: pam_unix (sudo: auth): falha na conversa
31 de dezembro 15:26:13 Server1 sudo: pam_unix (sudo: auth): auth não pôde identificar a senha para [User1]
31 de dezembro 15:26:13 Server1 sudo: User1: 1 tentativa de senha incorreta; TTY = pts / 1; PWD = / home / Usuário1; USUÁRIO = raiz; COMANDO = / 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
31 de dezembro 15:26:13 Server1 sshd [27093]: pam_unix (sshd: session): sessão fechada para o usuário User1 

Server2 (funciona bem)

/ var / log / secure

31 de dezembro 15:21:12 Server2 sshd [31447]: senha aceita para User1 da porta xxxx 60346 ssh2
31 de dezembro 15:21:12 Server2 sshd [31447]: pam_unix (sshd: session): sessão aberta para o usuário User1 por (uid = 0)
31 de dezembro 15:21:12 Server2 sshd [31449]: solicitação do subsistema para sftp
31 de dezembro 15:21:12 Server2 sudo: Usuário1: TTY = pts / 2; PWD = / home / Usuário1; USUÁRIO = raiz; COMANDO = / 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
31 de dezembro 15:21:14 Server2 sshd [31447]: pam_unix (sshd: session): sessão fechada para o usuário User1 

Saída STrace

Aqui está a saída do strace ao direcionar o comando ansible do usuário root. Comando:

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`

Servidor1

23650 select (0, NULL, NULL, NULL, {1, 508055}) = 0 (Tempo limite)
Soquete 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: autêntico" ..., 124, 0, {sa_family = AF_NETLINK, pid = 0, grupos = 00000000}, 12) = 124
Pesquisa 23650 ([{fd = 10, eventos = 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, grupos = 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, grupos = 00000000}, [12]) = 36
23650 fechar (10) = 0
23650 write (2, "Desculpe, tente novamente. \ N", 18) = 18
23650 gettimeofday ({1420050850, 238344}, NULL) = 0
Soquete 23650 (PF_FILE, SOCK_STREAM, 0) = 10
23650 connect (10, {sa_family = AF_FILE, caminho = "/ var / run / dbus / system_bus_socket"}, 33) = 0

Servidor2

6625 select (8, [5 7], [], NULL, NULL) =? ERESTARTNOHAND (a ser reiniciado)
6625 --- SIGCHLD (saída da criança) @ 0 (0) ---
6625 gravação (8, "\ 21", 1) = 1
6625 rt_sigreturn (0x8) = -1 EINTR (chamada do sistema interrompida)
6625 selecione (8, [5 7], [], NULL, NULL) = 1 (em [7])
6625 leitura (7, "\ 21", 1) = 1
6625 wait4 (6636, [{WIFEXITED (s) && WEXITSTATUS (s) == 0}], WNOHANG | WSTOPPED, NULL) = 6636
6625 rt_sigprocmask (SIG_BLOCK, NULL, [], 8) = 0
Soquete 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, grupos = 00000000}, 12) = 120
Pesquisa 6625 ([{fd = 6, eventos = 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, grupos = 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, grupos = 00000000}, [12]) = 36
6625 fechar (6) = 0
6625 open ("/ 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_sblue = 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 # Esta é a configuração fi" ..., 4096) = 2980
6625 lido (6, "", 4096) = 0
6625 fechar (6) = 0
6625 munmap (0x7fbc3a59a000, 4096) = 0
6625 aberto ("/ etc / environment", O_RDONLY) = 6

Meu palpite

O Server1 não está recebendo a senha corretamente ou está solicitando / aguardando incorretamente uma senha. Isso não parece um problema do Sudo ou do Ansible (sozinhos, ambos funcionam muito bem), mas o Server1 parece não receber as credenciais (ou aderir a elas) de maneira semelhante ao Server2. Os servidores 1 e 2 servem a propósitos diferentes; portanto, é possível que eles tenham algumas diferenças de autenticação ou versão de pacote, mas ambos foram criados a partir do mesmo repositório; portanto, eles não devem ser tão diferentes.

Autenticação PAM

Eu pensei que talvez os sistemas tivessem configurações diferentes de PAM, fazendo com que as senhas fossem tratadas de maneira um pouco diferente. Comparei os arquivos /etc/pam.d/ (usando md5sum [file]) e eles são os mesmos entre os dois sistemas.

Testes

Sudo STDIN

Testou outro problema em que o sudo não lia uma senha do STDIN, mas funcionava bem nos dois servidores.

Teste Sudo Ad-Hoc

-bash-4.1 $ ansible Server1 -m arquivo -a "dest = / tmp / ansible_test.txt state = touch" -sK
Senha SSH: 
senha sudo [o padrão é senha SSH]: 
Servidor1 | sucesso >> {
    "alterado": verdadeiro, 
    "dest": "/tmp/ansible_test.txt", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "proprietário": "raiz", 
    "tamanho": 0, 
    "state": "file", 
    "uid": 0
}

Sucesso! Mas por que?!

TL; DR

  1. O Servidor1 parece estar aguardando o prompt da senha do sudo, enquanto o Servidor2 é executado corretamente.
  2. A execução de ansible"ad-hoc" no Server1 funciona bem. A execução como um manual falha.

Questões)

  • O que poderia fazer com que minha configuração do Ansible Sudo funcionasse bem em um servidor e fosse rejeitada em outro?
  • O Ansible executa a senha "passar" da máquina local para a remota de maneira diferente quando executa ad-hoc versus playbook? Eu assumi que eles seriam os mesmos.

Eu estou pensando que isso está chegando perto de simplesmente enviar um relatório de bug para a página do GitHub apenas pelo fato de o acesso ao sudo ter resultados diferentes, dependendo se eu estiver executando ad-hoc ou não.

BrM13
fonte

Respostas:

4

O que eu faria é usar

strace -vfp `pidof sshd`

e veja onde está falhando.

Verifique a conta também, talvez seja restrita ou algo assim, mas minha aposta é que algo está errado com o seu arquivo / etc / hosts ou se foi alterado no processo.

Iulian
fonte
Obrigado, Lulian. Apliquei algumas edições à pergunta, sendo uma seção a saída do STrace. É claro que há uma diferença entre os dois servidores no modo como eles prosseguem após o início do processo ansible no servidor remoto. As execuções subseqüentes e as capturas de rastreamento foram consistentes.
BrM13
Eu acho que você precisa mais desse strace -vfp, faça manualmente no processo sshd superior e siga a saída. Acho que depois de ler a senha, é só fechar o canal assim antes de passar pelo PAM etc. Nesse momento, dê uma olhada no arquivo sshd_config e no hosts.deny ... veja se você encontra alguma coisa lá.
Julian
Eu já havia tentado sua sugestão antes, mas devo ter perdido o elemento crucial (por isso, optei por assistir ao processo ansível no STrace inicial). Após outra tentativa, encontrei uma variável {{password}} vazia sendo passada em vez da senha real. Optou por enviar outra "Resposta" separadamente, pois sua resposta acabou me colocando no caminho certo.
BrM13 5/01
4

Usando o @lulian como ponto de apoio nesta resposta, o problema se reduziu a um invasor ansible_sudo_pass:definido nos group_vars que estava substituindo a senha digitada --ask-sudo-pass.

Usando o seguinte:

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

Consegui descobrir que write(4, "{{ password }}\n", 15)estava sendo passado em vez da senha digitada. Após algumas pesquisas rápidas, encontrei ansible_sudo_passdefinido nos meus group_vars que estavam substituindo minha senha digitada.

Como um FYI para todos os outros, a ansible_sudo_pass:definição parece ter precedência sobre a --ask-sudo-passqual, a princípio, parecia contra-intuitiva. No final, esse é um erro do usuário, mas a metodologia da @ lulian em depurar a interação SSH, bem como a descoberta de relacionamentos entre ansible_sudo_passe --ask-sudo-passdeve ser muito útil para outras pessoas por aí. (Esperançosamente!)

BrM13
fonte
1
Eu argumentaria que o Ansible, dando prioridade às variáveis ​​definidas pelo arquivo sobre as opções da linha de comando, é contra-intuitivo e tem um comportamento ruim. Curiosamente, ele reconhece que isso está quebrado quando você passa as opções com -ee você pode contornar isso passando uma opção apropriada com -e.
Christopher Cashell