Ansible kann Sudo nicht authentifizieren, selbst wenn ein Sudo-Pass ausgestellt wurde

9

Problem

Bei Verwendung des neuesten, stabilen Ansible-Builds habe ich ein seltsames Problem, bei dem mein Playbook während "Gathering_Facts" auf einem Server hängt, bei Verwendung von Sudo jedoch auf anderen ähnlichen Servern einwandfrei funktioniert. Auf dem Ansible-Server führe ich als mein Benutzer (NIS-Benutzer) aus und verwende sudo (als root) auf dem Remote-Server, um Änderungen vorzunehmen. Wenn ich Sudo aus diesem Setup entferne, funktioniert alles einwandfrei.

Konfiguration

Softwareversionen

  • Betriebssystem : RHEL 6.4
  • Ansible Version : Ansible 1.8.2
  • Sudo-Version :
    Sudo Version 1.8.6p3
    Sudoers Policy Plugin Version 1.8.6p3
    Sudoers Datei Grammatik Version 42
    Sudoers I / O Plugin Version 1.8.6p3
    
  • SSH-Version : OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29. März 2010

Server Map

                   -------- Benutzer1 @ Server1: sudo -H -S -p (hängt an Gathering_Facts)
                  /.
User1 @ Ansible ----
                  \.
                   -------- Benutzer1 @ Server2: sudo -H -S -p (Funktioniert einwandfrei)

Benutzer

  • Benutzer1: NIS-zugänglicher Benutzer auf Server1 und Server2.
  • root: lokaler Root-Benutzer für jeden Server.

Ansible Konfiguration

Relevante Teile meiner 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

Hier ist ein einfaches Test-Playbook, mit dem Sie eine leere Datei berühren und dann entfernen können. Eigentlich möchte ich nur testen, ob ich Ansible dazu bringen kann, sudo auf dem Remote-Server korrekt zu verwenden. Wenn das Spielbuch überhaupt läuft, bin ich in guter Verfassung.

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

Sudo-Konfiguration

/ etc / sudoers

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

Diese Sudo-Konfiguration funktioniert auf BEIDEN Servern einwandfrei. Keine Probleme mit sudo selbst.

Wie ich alles laufen lasse

Sehr einfach:

$ ansible-playbook test.yml
SSH-Passwort: 
sudo password [standardmäßig SSH-Passwort]:

PLAY [Server1: Server2] ************************************************ ** **. 

GATHERING FACTS ******************************************************** *************** 
ok: [Server2]
fehlgeschlagen: [Server1] => {"fehlgeschlagen": true, "analysiert": false}

Sorry, versuch es nochmal.
[sudo via ansible, key = mxxiqyvztlfnbctwixzmgvhwfdarumtq] Passwort: 
sudo: 1 falscher Passwortversuch


AUFGABE: [Leere Datei erstellen, um die Konnektivität und den Sudo-Zugriff zu testen] **************** 
geändert: [Server2]

NOTIFIED: [clean] **************************************************** **************** 
geändert: [Server2]

PLAY RECAP ******************************************************** ******************** 
           Verwenden Sie zum erneuten Versuch Folgendes: --limit @ / home / User1 / test.retry

Server1: ok = 0 geändert = 0 nicht erreichbar = 0 fehlgeschlagen = 1   
Server2: ok = 3 geändert = 2 nicht erreichbar = 0 fehlgeschlagen = 0

Schlägt fehl, unabhängig davon, ob ich sowohl die SSH / Sudo-Passwörter als auch implizit explizit eingebe (Sudo wird standardmäßig an SSH übergeben).

Remote-Server-Protokolle

Server1 (schlägt fehl)

/ var / log / secure

31. Dezember 15:21:10 Server1 sshd [27093]: Akzeptiertes Passwort für Benutzer1 von xxxx Port 51446 ssh2
31. Dezember 15:21:10 Server1 sshd [27093]: pam_unix (sshd: session): Sitzung für Benutzer User1 geöffnet von (uid = 0)
31. Dezember 15:21:11 Server1 sshd [27095]: Subsystemanforderung für SFTP
31. Dezember 15:21:11 Server1 sudo: pam_unix (sudo: auth): Authentifizierungsfehler; logname = User1 uid = 187 euid = 0 tty = / dev / pts / 1 ruser = User1 rhost = user = User1
31. Dezember 15:26:13 Server1 sudo: pam_unix (sudo: auth): Konversation fehlgeschlagen
31. Dezember 15:26:13 Server1 sudo: pam_unix (sudo: auth): auth konnte das Passwort für [User1] nicht identifizieren
31. Dezember 15:26:13 Server1 sudo: Benutzer1: 1 falscher Passwortversuch; TTY = pts / 1; PWD = / home / User1; USER = root; BEFEHL = / 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. Dezember 15:26:13 Server1 sshd [27093]: pam_unix (sshd: session): Sitzung für Benutzer User1 geschlossen 

Server2 (läuft gut)

/ var / log / secure

31. Dezember 15:21:12 Server2 sshd [31447]: Akzeptiertes Passwort für Benutzer1 von xxxx Port 60346 ssh2
31. Dezember 15:21:12 Server2 sshd [31447]: pam_unix (sshd: session): Sitzung für Benutzer User1 geöffnet von (uid = 0)
31. Dezember 15:21:12 Server2 sshd [31449]: Subsystemanforderung für SFTP
31. Dezember 15:21:12 Server2 sudo: Benutzer1: TTY = pts / 2; PWD = / home / User1; USER = root; BEFEHL = / 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. Dezember 15:21:14 Server2 sshd [31447]: pam_unix (sshd: session): Sitzung für Benutzer User1 geschlossen 

STrace-Ausgabe

Hier ist die Ausgabe von strace, wenn auf den ansible-Befehl des Root-Benutzers abgezielt wird. Befehl:

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`

Server 1

23650 select (0, NULL, NULL, NULL, {1, 508055}) = 0 (Timeout)
23650-Socket (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 close(10)                         = 0
23650 write(2, "Sorry, try again.\n", 18) = 18
23650 gettimeofday({1420050850, 238344}, NULL) = 0
23650 socket(PF_FILE, SOCK_STREAM, 0)   = 10
23650 connect (10, {sa_family = AF_FILE, path = "/ var / run / dbus / system_bus_socket"}, 33) = 0

Server2

6625 select (8, [5 7], [], NULL, NULL) =? ERESTARTNOHAND (Neustart)
6625 --- SIGCHLD (Kind verlassen) @ 0 (0) ---
6625 write (8, "\ 21", 1) = 1
6625 rt_sigreturn (0x8) = -1 EINTR (Unterbrochener Systemaufruf)
6625 select (8, [5 7], [], NULL, NULL) = 1 (in [7])
6625 read (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-Socket (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 Umfrage ([{fd = 6, Ereignisse = 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 close (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_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 # Dies ist die Konfiguration fi" ..., 4096) = 2980
6625 read (6, 4096) = 0
6625 close (6) = 0
6625 Munmap (0x7fbc3a59a000, 4096) = 0
6625 open ("/ etc / environment", O_RDONLY) = 6

Meine Vermutung

Server1 erhält das Passwort nicht richtig oder fragt / wartet fälschlicherweise auf ein Passwort. Dies sieht nicht nach einem Sudo- oder Ansible-Problem aus (allein funktionieren beide einwandfrei), aber Server1 scheint die Anmeldeinformationen nicht auf ähnliche Weise wie Server2 zu erhalten (oder sie einzuhalten). Server1 und 2 dienen unterschiedlichen Zwecken, sodass es möglich ist, dass sie einige Authentifizierungs- oder Paketversionsunterschiede aufweisen, beide jedoch aus demselben Repository erstellt wurden. Daher sollten sie nicht so unterschiedlich sein.

PAM Auth

Ich dachte, vielleicht hatten die Systeme unterschiedliche PAM-Konfigurationen, wodurch die Passwörter etwas anders behandelt wurden. Ich habe die Dateien /etc/pam.d/ (mit md5sum [file]) verglichen und sie sind zwischen den beiden Systemen gleich.

Tests

Sudo STDIN

Testete ein anderes Problem, bei dem sudo kein Passwort von STDIN lesen würde, aber das funktionierte auf beiden Servern einwandfrei.

Testen Sie Sudo Ad-Hoc

-bash-4.1 $ ansible Server1 -m Datei -a "dest = / tmp / ansible_test.txt state = touch" -sK
SSH-Passwort: 
sudo password [standardmäßig SSH-Passwort]: 
Server1 | Erfolg >> {
    "geändert": wahr, 
    "dest": "/tmp/ansible_test.txt", 
    "gid": 0, 
    "Gruppe": "Wurzel", 
    "mode": "0644", 
    "Besitzer": "Wurzel", 
    "Größe": 0, 
    "state": "file", 
    "uid": 0
}}

Erfolg! Aber warum?!

TL; DR

  1. Server1 scheint auf die Eingabeaufforderung von sudo password zu warten, während Server2 einwandfrei läuft.
  2. Das Ausführen von ansible"Ad-hoc" auf Server1 funktioniert einwandfrei. Das Ausführen als Playbook schlägt fehl.

Fragen)

  • Was kann dazu führen, dass meine Ansible Sudo-Konfiguration auf einem Server einwandfrei funktioniert und auf einem anderen abgelehnt wird?
  • Führt Ansible das Kennwort "Weitergeben" vom lokalen zum Remote-Computer anders aus, wenn Ad-hoc oder Playbook ausgeführt wird? Ich nahm an, dass sie gleich sein würden.

Ich denke, dies kommt der einfachen Übermittlung eines Fehlerberichts an die GitHub-Seite nahe, nur weil der Sudo-Zugriff unterschiedliche Ergebnisse hat, je nachdem, ob ich ad-hoc bin oder nicht.

BrM13
quelle

Antworten:

4

Was ich tun würde, ist zu verwenden

strace -vfp `pidof sshd`

und sehen, wo es versagt.

Überprüfen Sie auch das Konto, vielleicht ist es eingeschränkt oder so, aber ich wette, dass etwas mit Ihrer / etc / hosts-Datei nicht stimmt oder sich dabei ändert.

Iulian
quelle
Danke, Lulian. Ich habe einige Änderungen an der Frage vorgenommen, wobei ein Abschnitt die STrace-Ausgabe ist. Es ist klar, dass es einen Unterschied zwischen den beiden Servern gibt, wie sie nach dem Start des ansible-Prozesses auf dem Remote-Server vorgehen. Nachfolgende Läufe und Trace-Erfassungen waren konsistent.
BrM13
Ich denke, Sie brauchen mehr von diesem strace -vfp, machen Sie es manuell im obersten sshd-Prozess und folgen Sie der Ausgabe. Ich glaube nicht, dass nach dem Lesen des Passworts der Kanal einfach so geschlossen wird, bevor PAM usw. durchlaufen wird. Dann schauen Sie sich bitte die Datei sshd_config und hosts.deny an. Sehen Sie, ob Sie dort etwas finden können.
Iulian
Ich hatte Ihren Vorschlag schon einmal ausprobiert, aber ich muss das entscheidende Element darin übersehen haben (daher habe ich mich entschieden, den ansiblen Prozess im ersten STrace zu beobachten). Nach einem weiteren Versuch fand ich eine leere {{password}} Variable, die anstelle des echten Passworts übergeben wurde. Ich habe mich dafür entschieden, eine weitere "Antwort" separat einzureichen, da Ihre Antwort mich schließlich auf den richtigen Weg gebracht hat.
BrM13
4

Mit @lulian als Grundlage in dieser Antwort kam das Problem auf einen Schurken zurück ansible_sudo_pass:, der in den group_vars definiert wurde und das eingegebene Passwort überschrieb --ask-sudo-pass.

Verwenden Sie Folgendes:

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

Ich konnte feststellen, write(4, "{{ password }}\n", 15)dass anstelle des eingegebenen Passworts übergeben wurde. Nach einer kurzen Suche fand ich tatsächlich ansible_sudo_passin meinen group_vars definiert, was mein eingegebenes Passwort überschrieb.

Als FYI für alle anderen ansible_sudo_pass:scheint die Definition Vorrang zu haben, --ask-sudo-passwas zunächst kontraintuitiv schien. Letztendlich ist dies ein Benutzerfehler, aber die Methode von @ lulian beim Debuggen der SSH-Interaktion sowie die Beziehungserkennung zwischen ansible_sudo_passund --ask-sudo-passsollte für andere da draußen sehr hilfreich sein. (Hoffnungsvoll!)

BrM13
quelle
1
Ich würde behaupten , dass ansible Vorrang Datei definierten Variablen über Kommandozeilenoptionen geben ist kontraintuitiv und schlechtes Verhalten. Seltsamerweise erkennt es, dass dies nicht funktioniert, wenn Sie Optionen mit übergeben -e, und Sie können dies möglicherweise umgehen, indem Sie eine entsprechende Option mit übergeben -e.
Christopher Cashell