Как использовать ansible с двухфакторной аутентификацией?

Я включил двухфакторную аутентификацию для ssh с использованием duosecurity (используя эту книгу https://github.com/CoffeeAndCode/ansible-duo).

Как я могу использовать ansible для управления сервером сейчас. Из-за этого вызовы SSH не могут собрать факты. Я хочу, чтобы человек, запускающий playbook, ввел двухфакторный код перед запуском playbook.

Отключение двух факторов для пользователя развертывания является возможным решением, но создает проблему безопасности, которой я хотел бы избежать.


person Harshil Mathur    schedule 16.04.2014    source источник
comment
Почти в каждом случае, который я могу придумать, было бы лучшим выбором дизайна заблокировать хост-бастион внутри вашей сети с двухфакторной аутентификацией и разрешить Ansible использовать ssh без него в этой сети. Как сказано в ответе (технически правильном!) ниже, любое решение, требующее такой тяжелой работы по настройке, будет настолько болезненным в масштабе, что в первую очередь лишит большую часть преимуществ использования Ansible.   -  person nikobelia    schedule 28.07.2016


Ответы (3)


Это хак, но вы можете туннелировать Ansible SSH-соединение без 2fac через SSH-соединение с поддержкой 2fac.

Обзор

Мы настроим двух пользователей: ansible будет пользователем Ansible. Он должен быть аутентифицирован способом, поддерживаемым Ansible (т. е. не 2fac). Этот пользователь будет ограничен, поэтому он не сможет подключаться откуда угодно, кроме 127.0.0.1, поэтому он недоступен снаружи машины.

Второй пользователь, ansible_tunnel, будет открыт для внешнего мира, но будет аутентифицирован двумя факторами и разрешит туннелирование SSH-соединений только с локальным компьютером.

Вы должны иметь возможность настроить двухфакторную аутентификацию только для некоторых пользователей (не для всех).

Некоторые информация о туннелях SSH.

На целевой машине:

  1. Создайте двух пользователей: ansible и ansible_tunnel
  2. Поместите свой открытый ключ в ~/.ssh/authorized_keys обоих пользователей
  3. Установите оболочку ansible_tunnel на /bin/false или заблокируйте пользователя - он будет использоваться исключительно для туннелирования, а не для запуска команд
  4. Добавьте следующее к /etc/ssh/sshd_config:

    AllowTcpForwarding no
    
    AllowUsers [email protected] ansible_tunnel
    
    Match User ansible_tunnel
      AllowTcpForwarding yes
      PermitOpen 127.0.0.1:22
      ForceCommand echo 'This account can only be used for tunneling SSH sessions'
    
  5. Настройте двухфакторную аутентификацию только для ansible_tunnel
  6. Перезапустите sshd

На машине под управлением Ansible:

  1. Перед запуском Ansible выполните следующее (на машине Ansible, а не на целевой машине):

    ssh -N -L 8022:127.0.0.1:22 ansible_tunnel@<host>
    

    Вы будете аутентифицированы с использованием двух факторов.

  2. Как только туннель будет запущен (проверьте с помощью netstat), запустите Ansible с помощью ansible_ssh_user=ansible, ansible_ssh_port=8022 и ansible_ssh_host=localhost.

Резюме

  • Только ansible_tunnel может подключиться извне, и он будет аутентифицирован с использованием двух факторов.
  • После настройки туннеля подключение к порту 8022 на локальном компьютере будет таким же, как подключение к sshd на удаленном компьютере.
  • Мы разрешаем ansible подключаться через SSH только тогда, когда это делается через локальный хост, поэтому разрешены только туннелированные подключения.

Шкала

Это не будет хорошо масштабироваться для нескольких серверов из-за необходимости открывать отдельный туннель для каждой машины, что требует ручного действия. Однако, если вы выбрали двухфакторную аутентификацию для своих серверов, вы уже готовы выполнить некоторые ручные действия для подключения к каждому серверу, и это решение лишь добавит немного накладных расходов из-за некоторого переноса скриптов.

[ОТРЕДАКТИРОВАНО ДОБАВИТЬ]

Бонус

Для удобства мы можем захотеть войти в учетную запись обслуживания напрямую, чтобы выполнить некоторую ручную работу, минуя процесс настройки туннеля. В этом случае мы можем настроить SSH на требование аутентификации 2fac, сохраняя при этом возможность подключения без 2fac через туннель:

# All users must authenticate using two factors
AuthenticationMethods publickey,keyboard-interactive

# Allow both maintenance user and tunnel user with no restrictions
AllowUsers ansible ansible_tunnel

# The maintenance user is allowed to authenticate using a single factor only
# when connecting from a local address - it should be impossible to connect to
# this user using a single factor from the outside (the only way to do that is
# having an existing access to the machine, or use the two-factor tunnel)
Match User ansible Address 127.0.0.1
  AuthenticationMethods publickey
person duvduv    schedule 27.09.2015
comment
Отличный ответ, это своего рода хак, но это кажется лучшим решением, чем все, что я смог найти в списках рассылки или проблемах github. Какая польза от отдельных пользователей, когда пользователь ansible_tunnel настроен только на туннелирование? Похоже, вы могли бы разрешить каждому пользователю использовать только аутентификацию с открытым ключом от 127.0.0.1, тогда будет задействован только один пользователь, а фактические команды обслуживания будут выполняться от вашего имени. - person danny; 13.02.2017
comment
Я думаю, вы можете настроить одного пользователя так, чтобы он разрешал только 2fac извне, но только pubkey из 127.0.0.1, и использовать этого пользователя как для туннелирования, так и для ansible (т. е. туннелировать этого пользователя самому себе, ха-ха). Мне просто нравится разделять роли — если я неправильно настроил SSH для пользователя туннеля, ему все равно не разрешено запускать команды. - person duvduv; 14.02.2017

Решение с использованием узла-бастиона

Даже используя хост-бастион ssh, мне потребовалось довольно много времени, чтобы заставить это работать. Если это поможет кому-то еще, вот что я придумал. Он использует параметры конфигурации ControlMaster ssh, и, поскольку ansible использует обычный ssh, его можно настроить на использование тех же функций ssh ​​и повторное использование соединения с хостом-бастионом независимо от того, сколько подключений он открывает к удаленным хостам. Я видел, что эти параметры управления рекомендуются в целом (предположительно из соображений производительности, если у вас много хостов), но не в контексте 2FA для хоста-бастиона.

При таком подходе вам не нужны какие-либо изменения конфигурации sshd, поэтому вам понадобится AuthenticationMethods publickey,keyboard-interactive в качестве единственного параметра метода аутентификации на сервере-бастионе, а publickey — только для всех других ваших серверов, к которым вы проксируете через бастион. Поскольку хост-бастион — единственный, который принимает внешние подключения из Интернета, он единственный, для которого требуется 2FA, а внутренние хосты полагаются на переадресацию агента для аутентификации с открытым ключом, но не используют 2FA.

На клиенте я создал новый файл конфигурации ssh для моей среды ansible в каталоге верхнего уровня, из которого я запускаю ansible (т. Это содержит:

Host bastion-persistent-connection
  HostName <bastion host>
  ForwardAgent yes
  IdentityFile ~/.ssh/my-key
  ControlMaster auto
  ControlPath ~/.ssh/ansible-%r@%h:%p
  ControlPersist 10m

Host 10.0.*.*
  ProxyCommand ssh -W %h:%p bastion-persistent-connection -F ./ssh.config
  IdentityFile ~/.ssh/my-key

Затем в ansible.cfg у меня есть:

[ssh_connection]
ssh_args = -F ./ssh.config

Несколько замечаний:

  • Моя частная подсеть в этом случае — 10.0.0.0/16, что соответствует параметру подстановочного знака хоста выше. Бастион проксирует все ssh-соединения с серверами в этой подсети.

  • Это немного хрупко, поскольку я могу запускать свои команды ssh или ansible только в этом каталоге из-за того, что ProxyCommand передает локальный путь к этому файлу конфигурации. К сожалению, я не думаю, что есть переменная ssh, которая сопоставляется с текущим используемым файлом конфигурации, чтобы я мог автоматически передать тот же файл конфигурации в ProxyCommand. В зависимости от вашей среды может быть лучше использовать для этого абсолютный путь.

Единственная загвоздка в том, что это делает запуск более сложным. К сожалению, из того, что я могу сказать, Ansible вообще не поддерживает 2FA. Поэтому, если у вас нет существующего ssh-соединения с бастионом, ansible будет распечатывать Verification code: один раз для каждого частного сервера, к которому он подключается, но на самом деле он не прослушивает входные данные, поэтому независимо от того, что вы делаете, соединения не будут выполнены.

Итак, я сначала запускаю: ssh -F ssh.config bastion-persistent-connection

Это создает файл сокета в ~/.ssh/ansible-*, и агент ssh локально закроет и удалит этот сокет по истечении настраиваемого времени (я установил 10 минут).

Как только сокет открыт, я могу запускать команды ansible, как обычно, например. ansible all -m ping и им это удается.

person danny    schedule 13.02.2017
comment
Небольшая поправка: в итоге я использовал ControlPath ~/.ansible/cp/ansible-ssh-%h-%p-%r, что соответствует стандартному Ansible control_path. docs.ansible.com/ansible/intro_configuration.html#control-path - person Aidan Feldman; 10.03.2017

Я могу использовать ansible с ssh и 2FA, используя функцию ControlMaster ssh и ansible.

Мой локальный клиент ssh настроен на дамп сокета ControlPath для мультиплексного соединения. Ansible настроен на использование того же сокета.

Локальный ssh-клиент

Эта конфигурация включает мультиплексирование для всех соединений. Лично я сохраняю эту конфигурацию в `~/.ssh/config:

Host *
    ControlMaster auto
    ControlPath ~/.ssh/master-%r@%h:%p.socket
    ControlPersist 1m

Когда соединение установлено, в каталоге $HOME/.ssh появляется сокет. Эти сокеты сохраняются в течение одной минуты после отключения.

Настроить доступный

Ansible настроен на повторное использование локального сокета.

Добавьте это в свой файл конфигурации ansible ( например, ~/.ansible.cfg):

[ssh_connection]

control_path=~/.ssh/master-%%r@%%h:%%p.socket

Обратите внимание на двойной % для замены переменной.

использование

  1. Подключитесь к вашему серверу с помощью обычной команды ssh (ssh user@server) и выполните 2FA;
  2. Запустите команду ansible, как обычно.

Шаг 2 необходимо выполнить в конфигурации ControlPersist или сохранить ssh-соединение в терминале, когда вы запускаете команду ansible в другом.

Вы также можете принудительно закрыть соединение, когда оно вам не нужно, используя: ssh -O exit user@server.

Обратите внимание, что если вы откроете третий терминал и запустите ssh user@server, у вас не будут запрашивать учетные данные: соединение, установленное в 1., будет использоваться повторно.

Недостатки

В случае плохих условий сети

Иногда, когда вы теряете соединение, сокет сохраняется. Каждое последующее соединение зависает. Вы должны вручную отключить это соединение, используя ssh -O exit user@server. Это единственный известный недостаток этого метода.

Рекомендации:

person Julien Fastré    schedule 03.11.2020