====== Ansible SSH аутентификация и повышение привилегий ======

===== Аутентификация на основе ключей в Ansible =====

Первое, что вы должны понять при изучении Ansible, это то, как происходит обмен данными между контроллером и управляемыми нодами.

Ansible использует протокол SSH для подключения к управляемым нодам и выполнения задач.

Каждый раз, когда вы запускаете playbook или специальные команды, вам необходимо указать пароль SSH, чтобы Ansible мог аутентифицироваться на управляемых нодах по SSH.

Чтобы избежать этого, рекомендуется создать пару ключей SSH и поделиться открытым ключом со всеми узлами, чтобы ansible мог взаимодействовать с помощью пары ключей.

Я создал две пары ключей с именами first_key и second_key с помощью приведенного ниже скрипта для демонстрации.

<code bash>#!/usr/bin/env bash

# THIS SCRIPT WILL CREATE SSH KEY PAIR AND DISTRIBUTE ACROSS ALL NODES

read -p "Enter the name for the key : " KEY_NAME
ssh-keygen -b 2048 -t rsa -f /home/vagrant/.ssh/${KEY_NAME} -q -N ""

# LOOPING THROUGH AND DISTRIBUTING THE KEY

for val in controller managed1 managed2; do
    echo "-------------------- COPYING KEY TO ${val^^} NODE ------------------------------"
    sshpass -p 'vagrant' ssh-copy-id -f -i /home/vagrant/.ssh/${KEY_NAME}.pub -o "StrictHostKeyChecking=no" vagrant@$val
done</code>
Дайте разрешение на выполнение скрипту и запустите его.

<code bash>$ chmod +x path/to/create_keypair.sh</code>
<code bash>$ ./create_keypair.sh</code>
Вы можете отредактировать раздел цикла for и добавить имена управляемых нод соответствующим образом.

<code bash>$ tree .ssh/
.ssh/
├── authorized_keys
├── first_key
├── first_key.pub
├── known_hosts
├── second_key
└── second_key.pub</code>
Если у вас созданы ключи с именами, отличными от имени по умолчанию (id_rsa), ssh попытается найти имена ключей по умолчанию и, если не найдет, запросит аутентификацию на основе пароля.

<code bash>debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Trying private key: /home/vagrant/.ssh/id_rsa
debug1: Trying private key: /home/vagrant/.ssh/id_dsa
debug1: Trying private key: /home/vagrant/.ssh/id_ecdsa
debug1: Trying private key: /home/vagrant/.ssh/id_ecdsa_sk
debug1: Trying private key: /home/vagrant/.ssh/id_ed25519
debug1: Trying private key: /home/vagrant/.ssh/id_ed25519_sk
debug1: Trying private key: /home/vagrant/.ssh/id_xmss
debug1: Next authentication method: password
vagrant@managed1's password:</code>
В этом случае необходимо явно указать файл закрытого ключа с помощью флага **-i**.

<code bash>$ ssh -v -i /home/vagrant/.ssh/first_key vagrant@managed1</code>

Когда вы запускаете специальную команду или playbook, вы можете использовать флаг –key-file или –private-key и передать файл закрытого ключа в качестве аргумента.

В приведенном ниже примере видно, что я использовал оба ключа (first_key & second_key) для успешной связи с управляемыми узлами.

<code bash># USING --key-file FLAG

$ ansible managed1 -m ping --key-file /home/vagrant/.ssh/second_key

managed1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
# USING --private-key FLAG

$ ansible managed1 -m ping --private-key /home/vagrant/.ssh/first_key

managed1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}</code>

Вы также можете добавить параметр “private_key_file” в конфигурационный файл ansible.cfg, который будет применяться к adhoc-командам и всем задачам playbook.

<code bash>$ vim ansible.cfg</code>
Добавьте следующую строку:

<code bash>Private_key_file = /home/vagrant/.ssh/first_key</code>
Замените /home/vagrant/.ssh/first_key на свой собственный.

Вы также можете добавить параметр “ansible_ssh_private_key” в файл inventory, который будет иметь больший приоритет над файлом ansible.cfg.

Ниже показано, как настроен мой инвентари.

Нода managed1 будет использовать “first_key”, а managed2 – “second_key”.

<code bash>[ubuntu1]
managed1 ansible_ssh_private_key_file=/home/vagrant/.ssh/first_key

[ubuntu2]
managed2 ansible_ssh_private_key_file=/home/vagrant/.ssh/second_key</code>

Теперь, если вы снова запустите команду adhoc или playbook, вы увидите, что оба ключа успешно пройдут аутентификацию.

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

$ ansible -vvv all -m ping
Теперь вы должны хорошо понимать, как работает аутентификация на основе ключей в ansible.

Важно понимать приоритет при добавлении параметра в различные файлы.

Параметр командной строки имеет больший приоритет, за ним следует файл инвентори и файл конфигурации ansible.cfg.

===== Аутентификация на основе пароля SSH в Ansible =====

Когда вы запускаете любую задачу, Ansible будет использовать текущего пользователя на ноде контроллера для связи с управляемыми нодами по SSH.

Вы можете использовать модуль shell и выполнить команду “whoami” для проверки имени пользователя на управляемых нодах.

В моем случае имя пользователя – “vagrant”.

Пользователь vagrant проходит аутентификацию с помощью ключей, которые я настроил в предыдущем разделе.

<code bash>$ whoami
vagrant
$ ansible all -m shell -a "whoami"
managed2 | CHANGED | rc=0 >>
vagrant
managed1 | CHANGED | rc=0 >>
vagrant</code>
Если вы хотите подключиться к управляемым нодам под другим пользователем, вы можете использовать флаг –u или –user и передать имя пользователя в качестве аргумента.

Я пытаюсь использовать пользователя “karthick”, у которого не настроен SSH-ключ и ключи не распределены по управляемым узлам, поэтому подключение не происходит.

$ ansible all -m shell -a "whoami" -u karthick
$ ansible all -m shell -a "whoami" --user karthick
Чтобы использовать аутентификацию на основе пароля, можно использовать флаг -k или –ask-pass.

Будет предложено ввести пароль SSH для пользователя (karthick).

Убедитесь, что пароль одинаковый на всех нодах для данного пользователя.

<code bash>$ ansible all -m shell -a "whoami" -u karthick -k
$ ansible all -m shell -a "whoami" -u karthick --ask-pass</code>
Вы также можете хранить пароль в файле и передавать имя файла в качестве аргумента для флага –connection-password-file или –conn-pass-file.

Этот способ не рекомендуется, поскольку вы храните пароль в обычном текстовом файле.
Вы можете использовать ansible vault для шифрования файла паролей, но это отдельная тема для обсуждения.
<code bash>$ ansible all -m shell -a "whoami" -u karthick --connection-password-file pass.txt
$ ansible all -m shell -a "whoami" -u karthick --conn-pass-file pass.txt</code>
Вы также можете передать имя пользователя и пароль в качестве параметров в файле инвентари.

Опять же, это не лучший способ хранения пароля.

Ниже показано, как настроен мой файл инвентари.

<code bash>[ubuntu1]
managed1 ansible_ssh_private_key_file=/home/vagrant/.ssh/first_key ansible_user=vagrant

[ubuntu2]
managed2 ansible_user=karthick ansible_ssh_pass=password
$ ansible all -m shell -a "whoami" -u karthick

managed1 | CHANGED | rc=0 >>
vagrant
managed2 | CHANGED | rc=0 >>
karthick</code>

===== Повышение привилегий в Ansible =====

Бывают случаи, когда для успешного выполнения задачи требуется повышенная привилегия (root). Например, управление пакетами.

Вы можете устанавливать, удалять или обновлять пакеты только от имени пользователя root или с привилегиями sudo.

Если вы запустите флаг help вместе с ansible или ansible-playbook, вы найдете раздел об эскалации привилегий, как показано на рисунке.

<code bash>$ ansible --help
$ ansible-playbook --help</code>



Если вы хотите запустить какое-либо задание с привилегиями root, вам следует использовать флаг -b или –become.

<code bash>$ ansible ubuntu1 -m service -a "name=sshd state=restarted" -b</code>

<code bash>managed1 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": true,
    "name": "sshd",
    "state": "started",</code>
По умолчанию в качестве метода эскалации привилегий будет использоваться sudo.

Вы можете изменить метод, установив флаг –become-method.

Список поддерживаемых методов можно получить, выполнив следующую команду.

<code bash>$ ansible-doc -t become -l</code>

<code bash>ansible.netcommon.enable     Switch to elevated permissions on a network device                                                             
community.general.doas       Do As user                                                                                                     
community.general.dzdo       Centrify's Direct Authorize                                                                                    
community.general.ksu        Kerberos substitute user                                                                                       
community.general.machinectl Systemd's machinectl privilege escalation                                                                      
community.general.pbrun      PowerBroker run                                                                                                
community.general.pfexec     profile based execution                                                                                        
community.general.pmrun      Privilege Manager run                                                                                          
community.general.sesu       CA Privileged Access Manager                                                                                   
community.general.sudosu     Run tasks using sudo su -                                                                                  
runas                        Run As user                                                                                                   
su                           Substitute User                                                                                               
sudo                         Substitute User DO</code>
Вы можете задать или не задавать пароль sudo для управляемых нод в зависимости от того, как настроен пользователь.

В моем случае я настроил пользователя vagrant для запуска sudo без запроса пароля.

Если ваш пользователь sudo требует пароль для работы, то вам следует использовать флаг -K или –ask-become-pass, который запросит пароль sudo.

Как видно из приведенной ниже ошибки, когда я пытаюсь запустить sudo без указания пароля sudo для пользователя “karthick”, выдает ошибку “Missing sudo password”.

<code bash>$ ansible ubuntu1 -m service -a "name=sshd state=restarted" -i inventory -u karthick -k -b</code>

<code bash>SSH password:
managed1 | FAILED! => {
    "msg": "Missing sudo password"
}</code>
<code bash>$ ansible ubuntu1 -m service -a "name=sshd state=restarted" -i inventory -u karthick -k -b -K</code>
Пароль Sudo может храниться в файле и передаваться в качестве аргумента для флага –become-password-file или –become-pass-file.

Для шифрования этого файла можно использовать Ansible vault, но это не рекомендуется.

<code bash>$ ansible ubuntu1 -m service -a "name=sshd state=restarted" -i inventory -u karthick -k -b --become-password-file pass.txt</code>

<code bash>$ ansible ubuntu1 -m service -a "name=sshd state=restarted" -i inventory -u karthick -k -b --become-pass-file pass.txt</code>
Вы также можете включить директиву “become” в плейбук.

Как видно из вывода, служба ssh перезапущена нормально на ноде managed1.

<code bash>$ ansible-playbook restart_service.yml</code>

<code bash>PLAY [Restart SSHD service] ***************************************************************************

TASK [Restart SSHD in managed1.anslab.com] ************************************************************
changed: [managed1]

PLAY RECAP ********************************************************************************************
managed1 : ok=1 changed=1    unreachable=0     failed=0 skipped=0    rescued=0 ignored=0</code>
Директива “become” также может быть установлена в конфигурационном файле ansible.cfg и в файле инвентари.

Но рекомендуется устанавливать директиву в плейбуке.