Ansible не может аутентифицировать судо, даже если дан пропуск в судо

9

проблема

Используя последнюю стабильную сборку Ansible, у меня возникла странная проблема, когда моя playbook зависает на одном сервере во время «Gathering_Facts», но отлично работает на других подобных серверах при использовании Sudo. На сервере Ansible я работаю как мой пользователь (пользователь NIS) и использую sudo (как root) на удаленном сервере для внесения изменений. Если я удаляю Sudo из этой настройки, все работает нормально.

Настроить

Версии программного обеспечения

  • ОС : RHEL 6.4
  • Ansible версия : ansible 1.8.2
  • Судо версия :
    Судо версия 1.8.6p3
    Плагин политики Sudoers версии 1.8.6p3
    Судоеры файл грамматики версия 42
    Плагин Sudoers I / O версии 1.8.6p3
    
  • Версия SSH : OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 марта 2010

Карта сервера

                   -------- User1 @ Server1: sudo -H -S -p (зависает на Gathering_Facts)
                  /
User1 @ Ansible ----
                  \
                   -------- User1 @ Server2: sudo -H -S -p (работает нормально)

пользователей

  • Пользователь1: доступный по NIS пользователь как на Сервере1, так и на Сервере2.
  • root: локальный пользователь root для каждого сервера.

Ansible Configuration

Соответствующие части моего 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

Вот простой тестовый playbook, чтобы коснуться пустого файла и затем удалить его. На самом деле, я просто хочу проверить, могу ли я заставить Ansible правильно использовать sudo на удаленном сервере. Если пьеса работает, я в хорошей форме.

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

Конфигурация Судо

/ и т.д. / sudoers

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

Эта конфигурация sudo прекрасно работает на ОБАХ серверах. Никаких проблем с самой sudo.

Как я все это запускаю

Очень просто:

$ ansible-playbook test.yml
Пароль SSH: 
пароль sudo [по умолчанию пароль SSH]:

ИГРАТЬ [Сервер1: Сервер2] ******************************************** ** 

ФАКТЫ СБОРА ************************************************ *************** 
хорошо: [Server2]
fail: [Server1] => {"failed": true, "parsed": false}

Извините, попробуйте еще раз.
[sudo via ansible, key = mxxiqyvztlfnbctwixzmgvhwfdarumtq] пароль: 
sudo: 1 попытка неверного пароля


ЗАДАЧА: [создать пустой файл для проверки подключения и доступа sudo] **************** 
изменено: [Server2]

УВЕДОМЛЕНО: [чистый] ********************************************* **************** 
изменено: [Server2]

PLAY RECAP ************************************************* ******************** 
           чтобы повторить попытку, используйте: --limit @ / home / User1 / test.retry

Сервер1: нормально = 0 изменено = 0 недоступно = 0 не удалось = 1   
Сервер2: хорошо = 3 изменено = 2 недоступно = 0 не удалось = 0

Сбой независимо от того, если я явно ввожу оба пароля SSH / Sudo, а также неявно (позволяя sudo передать значение по умолчанию SSH).

Журналы удаленного сервера

Сервер1 (Сбой)

/ Вар / журнал / безопасный

31 декабря 15:21:10 Server1 sshd [27093]: принят пароль для пользователя User1 от порта xxxx 51446 ssh2
31 декабря 15:21:10 Server1 sshd [27093]: pam_unix (sshd: сеанс): сеанс открыт для пользователя User1 пользователем (uid = 0)
31 декабря 15:21:11 Server1 sshd [27095]: запрос подсистемы для sftp
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
31 декабря 15:26:13 Server1 sudo: pam_unix (sudo: auth): сбой диалога
31 декабря 15:26:13 Server1 sudo: pam_unix (sudo: auth): auth не удалось идентифицировать пароль для [User1]
31 декабря 15:26:13 Сервер1 sudo: Пользователь1: 1 попытка неверного пароля; TTY = pts / 1; PWD = / home / User1; ПОЛЬЗОВАТЕЛЬ = root; КОМАНДА = / 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 декабря 15:26:13 Server1 sshd [27093]: pam_unix (sshd: сеанс): сеанс закрыт для пользователя User1 

Server2 (работает нормально)

/ Вар / журнал / безопасный

31 декабря 15:21:12 Server2 sshd [31447]: принят пароль для пользователя User1 от порта xxxx 60346 ssh2
31 декабря 15:21:12 Server2 sshd [31447]: pam_unix (sshd: сеанс): сеанс открыт для пользователя User1 пользователем (uid = 0)
31 декабря 15:21:12 Server2 sshd [31449]: запрос подсистемы для sftp
31 декабря 15:21:12 Сервер2 sudo: Пользователь1: TTY = pts / 2; PWD = / home / User1; ПОЛЬЗОВАТЕЛЬ = root; КОМАНДА = / 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 декабря 15:21:14 Server2 sshd [31447]: pam_unix (sshd: сеанс): сеанс закрыт для пользователя User1 

Выход STrace

Вот результат работы strace при нацеливании на команду пользователя root. Команда:

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: аутентичные" ..., 124, 0, {sa_family = AF_NETLINK, pid = 0, группы = 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 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 выберите (8, [5 7], [], NULL, NULL) =? ERESTARTNOHAND (будет перезапущен)
6625 --- SIGCHLD (ребенок вышел) @ 0 (0) ---
6625 записать (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, группы = 00000000}, 12) = 120
6625 опрос ([{fd = 6, события = 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 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 читать (6, "# \ n # Это конфигурация fi" ..., 4096) = 2980
6625 читать (6, "", 4096) = 0
6625 закрыть (6) = 0
6625 munmap (0x7fbc3a59a000, 4096) = 0
6625 open ("/ etc / environment", O_RDONLY) = 6

Мое предположение

Сервер1 не получает пароль правильно или неправильно запрашивает / ждет пароль. Это не похоже на проблему Sudo или Ansible (в одиночку они оба прекрасно работают), но Server1, похоже, не получает учетные данные (или придерживается их) так же, как Server2. Серверы 1 и 2 служат разным целям, поэтому возможно, что они имеют некоторые различия в аутентификации или версии пакета, но оба они были созданы из одного и того же хранилища; следовательно, они не должны быть такими разными.

PAM Auth

Я подумал, что, возможно, системы имеют разные конфигурации PAM, поэтому пароли обрабатываются немного по-разному. Я сравнил файлы /etc/pam.d/ (используя md5sum [file]), и они одинаковы для двух систем.

тесты

Судо СТДИН

Протестировал еще одну проблему, когда sudo не считывал пароль из STDIN, но это прекрасно работало на обоих серверах.

Тест Судо Ad-Hoc

-bash-4.1 $ ansible Server1 -m файл -a "dest = / tmp / ansible_test.txt state = touch" -sK
Пароль SSH: 
пароль sudo [по умолчанию пароль SSH]: 
Сервер1 | успех >> {
    «изменилось»: правда, 
    "dest": "/tmp/ansible_test.txt", 
    "gid": 0, 
    "группа": "корень", 
    «mode»: «0644», 
    "владелец": "корень", 
    «размер»: 0, 
    "состояние": "файл", 
    "UID": 0
}

Успех! Но почему?!

TL; DR

  1. Server1, похоже, ожидает запроса sudo password, а Server2 работает просто отлично.
  2. Запуск ansiblead-hoc на сервере Server1 работает нормально. Запустить его как playbook не удается.

Вопросов)

  • Что может заставить мою конфигурацию Ansible Sudo нормально работать на одном сервере и быть отклоненной на другом?
  • По-разному ли Ansible «передает» пароль с локального на удаленный компьютер при запуске ad-hoc и playbook? Я предполагал, что они будут такими же.

Я думаю, что это близко к тому, чтобы просто отправить отчет об ошибке на страницу GitHub исключительно на том факте, что доступ sudo имеет разные результаты, в зависимости от того, запущен ли я ad-hoc или нет.

BrM13
источник

Ответы:

4

Что бы я сделал, это использовать

strace -vfp `pidof sshd`

и посмотрим, где он терпит неудачу.

Проверьте также и учетную запись, возможно, она ограничена или что-то в этом роде, но я уверен, что с вашим файлом / etc / hosts что-то не так или оно изменилось в процессе.

Юлиан
источник
Спасибо, Лулиан. Я применил несколько правок к вопросу, один из которых был выводом STrace. Ясно, что между этими двумя серверами есть разница в том, как они работают после того, как на удаленном сервере запускается процесс ansible. Последующие прогоны и следы были согласованы.
BrM13
Я думаю, что вам нужно больше из этого strace -vfp, сделайте это вручную в верхнем sshd-процессе и выполните вывод. Я не думаю, что после прочтения пароля он просто закрывает канал перед тем, как пройти через PAM и т. Д. В этот момент, пожалуйста, взгляните на файл sshd_config и hosts.deny ... посмотрите, сможете ли вы найти там что-нибудь.
Юлиан
Я пробовал ваше предложение раньше, но я, должно быть, пропустил ключевой элемент (поэтому я решил посмотреть, что происходит на начальном этапе STACE). После другого перехода я нашел пустую переменную {{password}}, вместо реального пароля. Решил отправить еще один «Ответ» отдельно, так как ваш ответ в итоге заставил меня встать на правильный путь.
BrM13
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который на первый взгляд казался нелогичным. В конце концов, это ошибка пользователя, но методология @ lulian в отладке взаимодействия SSH, а также обнаружение отношений между ними ansible_sudo_passи --ask-sudo-passдолжна быть очень полезной для других. (С надеждой!)

BrM13
источник
1
Я считаю , что анзибль давая приоритет для файлов определенных переменных над опциями командной строки , является нелогичным, и плохое поведение. Любопытно, что он распознает, что это не работает, когда вы передаете опции с -e, и вы можете обойти это, передав соответствующую опцию с -e.
Кристофер Кашелл