Ansible nie powiedzie się w celu uwierzytelnienia Sudo, nawet jeśli podana jest przepustka Sudo

9

Problem

Korzystając z najnowszej, stabilnej wersji Ansible, mam dziwny problem polegający na tym, że mój playbook zawiesza się na jednym serwerze podczas „Gathering_Facts”, ale działa dobrze na innych podobnych serwerach podczas korzystania z Sudo. Na serwerze Ansible uruchamiam się jako mój użytkownik (użytkownik NIS) i używam sudo (jako root) na serwerze zdalnym, aby wprowadzać zmiany. Jeśli usunę Sudo z tej konfiguracji, wszystko działa dobrze.

Ustawiać

Wersje oprogramowania

  • System operacyjny : RHEL 6.4
  • Wersja Ansible : ansible 1.8.2
  • Wersja Sudo :
    Wersja Sudo 1.8.6p3
    Sudoers policy plugin wersja 1.8.6p3
    Gramatyka pliku Sudoers wersja 42
    Sudoers I / O plugin version 1.8.6p3
    
  • Wersja SSH : OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 marca 2010

Mapa serwera

                   -------- Użytkownik1 @ Serwer1: sudo -H -S -p (zawiesza się na Gathering_Facts)
                  /
Użytkownik1 @ Ansible ----
                  \
                   -------- Użytkownik1 @ Serwer2: sudo -H -S -p (działa dobrze)

Użytkownicy

  • Użytkownik 1: użytkownik dostępny w systemie NIS zarówno na serwerze 1, jak i na serwerze 2.
  • root: lokalny użytkownik root dla każdego serwera.

Konfiguracja Ansible

Odpowiednie części mojego 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

Oto prosty testowy podręcznik, aby dotknąć pustego pliku, a następnie go usunąć. Naprawdę, chcę tylko przetestować, czy mogę uzyskać Ansible, aby poprawnie używać sudo na zdalnym serwerze. Jeśli w ogóle działa podręcznik, jestem w dobrej formie.

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

Konfiguracja Sudo

/ etc / sudoers

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

Ta konfiguracja sudo działa dobrze na OBU serwerach. Żadnych problemów z samym sudo.

Jak to wszystko uruchomić

Bardzo prosta:

$ ansible-playbook test.yml
Hasło SSH: 
hasło sudo [domyślnie hasło SSH]:

ZAGRAJ [Server1: Server2] ******************************************** ** 

ZGODNE FAKTY ************************************************ *************** 
ok: [Server2]
failed: [Server1] => {„failed”: true, „parsowany”: false}

Przepraszamy, spróbuj jeszcze raz.
[sudo przez ansible, key = mxxiqyvztlfnbctwixzmgvhwfdarumtq] hasło: 
sudo: 1 niepoprawna próba hasła


ZADANIE: [utwórz pusty plik, aby przetestować łączność i dostęp do sudo] **************** 
zmieniono: [Server2]

ZGŁOSZONE: [czyste] ********************************************* **************** 
zmieniono: [Server2]

ZAGRAJ RECAP ************************************************ ********************** 
           aby spróbować ponownie, użyj: --limit @ / home / User1 / test.retry

Serwer 1: ok = 0 zmieniony = 0 nieosiągalny = 0 nieudany = 1   
Serwer2: ok = 3 zmienione = 2 nieosiągalne = 0 nieudane = 0

Nie działa niezależnie od tego, czy jawnie wprowadzę zarówno hasło SSH / Sudo, jak i niejawnie (pozwalając sudo przejść domyślnie na SSH).

Dzienniki zdalnego serwera

Serwer1 (nie działa)

/ var / log / secure

31 grudnia 15:21:10 Serwer1 sshd [27093]: Akceptowane hasło dla użytkownika 1 z portu xxxx 51446 ssh2
31 grudnia 15:21:10 Serwer1 sshd [27093]: pam_unix (sshd: session): sesja otwarta dla użytkownika User1 przez (uid = 0)
31 grudnia 15:21:11 Serwer1 sshd [27095]: żądanie podsystemu dla sftp
31 grudnia 15:21:11 Serwer1 sudo: pam_unix (sudo: auth): błąd uwierzytelnienia; logname = identyfikator użytkownika 1 = 187 identyfikator użytkownika = 0 tty = / dev / pts / 1 ruser = użytkownik 1 rhost = użytkownik = użytkownik 1
31 grudnia 15:26:13 Serwer1 sudo: pam_unix (sudo: auth): konwersacja nie powiodła się
31 grudnia 15:26:13 Serwer1 sudo: pam_unix (sudo: auth): auth nie mógł zidentyfikować hasła dla [Użytkownik1]
31 grudnia 15:26:13 Serwer1 sudo: Użytkownik1: 1 próba niepoprawnego hasła; 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
31 grudnia 15:26:13 Serwer1 sshd [27093]: pam_unix (sshd: session): sesja zamknięta dla użytkownika User1 

Serwer2 (działa dobrze)

/ var / log / secure

31 grudnia 15:21:12 Serwer2 sshd [31447]: Akceptowane hasło użytkownika 1 z portu xxxx 60346 ssh2
31 grudnia 15:21:12 Serwer2 sshd [31447]: pam_unix (sshd: session): sesja otwarta dla użytkownika User1 przez (uid = 0)
31 grudnia 15:21:12 Serwer2 sshd [31449]: żądanie podsystemu dla sftp
31 grudnia 15:21:12 Serwer2 sudo: Użytkownik1: TTY = pts / 2; PWD = / home / User1; USER = root; POLECENIE = / 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 grudnia 15:21:14 Serwer2 sshd [31447]: pam_unix (sshd: session): sesja zamknięta dla użytkownika User1 

Wyjście STrace

Oto dane wyjściowe strace podczas celowania w komendę użytkownika root. Komenda:

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`

Serwer 1

23650 wybierz (0, NULL, NULL, NULL, {1, 508055}) = 0 (Limit czasu)
Gniazdo 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: autentyczne" ..., 124, 0, {sa_family = AF_NETLINK, pid = 0, grupy = 00000000}, 12) = 124
23650 ankieta ([{fd = 10, events = POLLIN}], 1, 500) = 1 ([{fd = 10, revents = POLLIN}])
Odwołanie 23650 (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, grupy = 00000000}, [12]) = 36
Odwołanie 23650 (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, grupy = 00000000}, [12]) = 36
23650 zamknij (10) = 0
23650 zapisu (2, „Przepraszamy, spróbuj ponownie. \ N”, 18) = 18
23650 gettimeofday ({1420050850, 238344}, NULL) = 0
Gniazdo 23650 (PF_FILE, SOCK_STREAM, 0) = 10
23650 connect (10, {sa_family = AF_FILE, path = "/ var / run / dbus / system_bus_socket"}, 33) = 0

Serwer 2

6625 wybierz (8, [5 7], [], NULL, NULL) =? ERESTARTNOHAND (do ponownego uruchomienia)
6625 --- SIGCHLD (dziecko zakończone) @ 0 (0) ---
6625 zapis (8, „\ 21”, 1) = 1
6625 rt_sigreturn (0x8) = -1 EINTR (przerwane wywołanie systemowe)
6625 wybierz (8, [5 7], [], NULL, NULL) = 1 (w [7])
6625 przeczytane (7, „\ 21”, 1) = 1
6625 wait4 (6636, [{WIFEXITED (s) && WEXITSTATUS (s) == 0}], WNOHANG | WSTOPPED, NULL) = 6636
6625 rt_sigprocmask (SIG_BLOCK, NULL, [], 8) = 0
Gniazdo 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, grupy = 00000000}, 12) = 120
6625 ankieta ([{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, grupy = 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, grupy = 00000000}, [12]) = 36
6625 zamknij (6) = 0
6625 otwarty („/ 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 przeczytane (6, „# \ n # To jest konfiguracja fi” ..., 4096) = 2980
6625 odczytany (6, „”, 4096) = 0
6625 zamknij (6) = 0
6625 Munmap (0x7fbc3a59a000, 4096) = 0
6625 otwarty („/ etc / environment”, O_RDONLY) = 6

Zgaduję że

Serwer 1 nie otrzymuje poprawnie hasła lub niepoprawnie pyta / czeka na hasło. Nie wygląda to na problem Sudo lub Ansible (same, oba działają dobrze), ale Serwer1 nie wydaje się otrzymywać poświadczeń (ani się do nich stosować) w podobny sposób jak Serwer2. Serwer 1 i 2 służą różnym celom, więc możliwe jest, że mają pewne różnice w uwierzytelnianiu lub wersjach pakietów, ale oba zostały zbudowane z tego samego repozytorium; dlatego nie powinny być TAKIE różne.

PAM Auth

Pomyślałem, że może systemy mają różne konfiguracje PAM, co powoduje, że hasła są traktowane nieco inaczej. Porównałem pliki /etc/pam.d/ (za pomocą md5sum [file]) i są one takie same między dwoma systemami.

Testy

Sudo STDIN

Przetestowano inny problem, w którym sudo nie czytało hasła ze STDIN, ale działało dobrze na obu serwerach.

Test Sudo Ad-Hoc

-bash-4.1 $ ansible Serwer1 -m plik -a "dest = / tmp / ansible_test.txt state = touch" -sK
Hasło SSH: 
hasło sudo [domyślnie hasło SSH]: 
Serwer1 | sukces >> {
    „zmieniono”: prawda, 
    „dest”: „/tmp/ansible_test.txt”, 
    „gid”: 0, 
    „group”: „root”, 
    „mode”: „0644”, 
    „owner”: „root”, 
    „rozmiar”: 0, 
    „state”: „file”, 
    „uid”: 0
}

Sukces! Ale dlaczego?!

TL; DR

  1. Serwer 1 wydaje się czekać na monit sudo o hasło, a Serwer 2 działa dobrze.
  2. Uruchamianie ansible„ad-hoc” na serwerze Server1 działa dobrze. Uruchomienie go jako playbooka kończy się niepowodzeniem.

Pytania)

  • Co może spowodować, że moja konfiguracja Ansible Sudo będzie działać poprawnie na jednym serwerze i zostać odrzucona na innym?
  • Czy Ansible wykonuje hasło „przekazuj” z komputera lokalnego do zdalnego w inny sposób, gdy działa ad-hoc w porównaniu do podręcznika? Zakładałem, że będą takie same.

Myślę, że zbliża się to do wysłania raportu o błędzie na stronie GitHub wyłącznie z tego powodu, że dostęp do sudo ma różne wyniki, w zależności od tego, czy korzystam z ad-hoc, czy nie.

BrM13
źródło

Odpowiedzi:

4

Chciałbym użyć

strace -vfp `pidof sshd`

i zobacz, gdzie się nie udaje.

Sprawdź również konto, może jest ograniczone lub coś, ale założę się, że coś jest nie tak z plikiem / etc / hosts lub że się zmienia.

Iulian
źródło
Dzięki, Lulian. Wprowadziłem kilka zmian do pytania, jedną sekcją jest wyjście STrace. Oczywiste jest, że istnieje różnica między dwoma serwerami w sposobie ich działania po uruchomieniu procesu ansible na serwerze zdalnym. Kolejne przebiegi i przechwyty śledzenia były spójne.
BrM13
Myślę, że potrzebujesz więcej z tego strace -vfp, zrób to ręcznie na najwyższym procesie sshd i śledź dane wyjściowe. Nie sądzę, że po przeczytaniu hasła to po prostu zamyka kanał przed przejściem przez PAM itp. W tym momencie spójrz na plik sshd_config i hosts.deny .. Sprawdź, czy możesz tam coś znaleźć.
Iulian
Próbowałem już wcześniej Twojej sugestii, ale musiałem przeoczyć kluczowy element (dlatego zdecydowałem się obserwować proces ansible w początkowym STrace). Po kolejnym przejściu znalazłem przekazywaną pustą zmienną {{hasło}} zamiast prawdziwego hasła. Zdecydowałem się przesłać osobno „Odpowiedź” osobno, ponieważ Twoja odpowiedź ostatecznie doprowadziła mnie do właściwego wyniku.
BrM13,
4

Wykorzystując @lulian jako podstawę w tej odpowiedzi, problem sprowadził się do nieuczciwego ansible_sudo_pass:zdefiniowanego w group_vars, który przesłaniał wprowadzone hasło --ask-sudo-pass.

Wykorzystując następujące:

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

Udało mi się znaleźć, write(4, "{{ password }}\n", 15)że przekazywano zamiast wprowadzonego hasła. Po szybkim wyszukiwaniu rzeczywiście znalazłem ansible_sudo_passzdefiniowane w moich group_vars, które przesłaniały moje wprowadzone hasło.

ansible_sudo_pass:Definicja wydaje się mieć pierwszeństwo dla wszystkich innych, --ask-sudo-passdlatego wydaje się , że z początku wydawała się sprzeczna z intuicją. W końcu jest to błąd użytkownika, ale metodologia @ lulian w debugowaniu interakcji SSH, a także odkrywanie relacji między ansible_sudo_passi --ask-sudo-passpowinna być bardzo pomocna dla innych. (Ufnie!)

BrM13
źródło
1
Twierdziłbym, że Ansible dający pierwszeństwo zmiennym zdefiniowanym w pliku przed opcjami wiersza poleceń jest sprzeczny z intuicją i złym zachowaniem. Co ciekawe, zdaje sobie sprawę, że jest to zepsute, gdy przekazujesz opcje za pomocą -e, i możesz być w stanie obejść ten problem, przekazując odpowiednią opcję za pomocą -e.
Christopher Cashell