Ansible: подключение в приватную сеть через Bastion хост

Автор: | 31/01/2018

Примеры подключения Ansible через Bastion хост (или jump-host) в публичной сети к EC2 в приватной сети.

По теме – SSH: подключение в приватную сеть через Bastion и немного про Multiplexing (только тут для .ssh/config используем ProxyJump вместо ProxyCommand, доступна в OpenSSH 7.3 и выше).

Для примера используем Bastion хост в публичной сети и DB хост в приватной сети из серии постов о миграции RTFM:

Инвентори файл hosts содержит две записи – одну для самого Bastion, и вторую – для DB:

[rtfm-dev-bastion]
dev.rtfm.co.ua

[rtfm-dev-db]
db.dev.rtfm.co.ua

dev.rtfm.co.ua направлен на EIP Bastion хоста:

[simterm]

$ dig dev.rtfm.co.ua +short
52.48.41.8

[/simterm]

А DB – на приватный IP DB хоста:

[simterm]

$ dig db.dev.rtfm.co.ua +short
10.0.129.166

[/simterm]

Проверяем подключение к Bastion:

[simterm]

$ ansible -i hosts rtfm-dev-bastion --private-key=~/Work/RTFM/Bitbucket/aws-credentials/rtfm-dev.pem -m ping
dev.rtfm.co.ua | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

[/simterm]

SSH ProxyCommand и Ansible ansible_ssh_common_args

ansible_ssh_common_args появился в Ansible 2.0, для более ранних версий – см. второй пример, с ssh.cfg.

Пробуем подключиться к DB сейчас:

[simterm]

$ ansible -i hosts rtfm-dev-db --private-key=Work/RTFM/Bitbucket/aws-credentials/rtfm-dev.pem -m ping
db.dev.rtfm.co.ua | UNREACHABLE! => {
    "changed": false, 
    "msg": "Failed to connect to the host via ssh: ssh: connect to host db.dev.rtfm.co.ua port 22: Connection timed out\r\n", 
    "unreachable": true
}

[/simterm]

Что бы Ansible добавил ProxyCommand при подключении к DB – обновляем файл hosts, и в переменные для хоста rtfm-dev-db добавляем ansible_ssh_common_args, в которой описываем подключение аналогично тому, как мы бы это делали в локальном .ssh/config:

[rtfm-dev-bastion]
dev.rtfm.co.ua

[rtfm-dev-db]
db.dev.rtfm.co.ua

[rtfm-dev-db:vars]
ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p -q [email protected] -i ~/Work/RTFM/Bitbucket/aws-credentials/rtfm-dev.pem"'

Пробуем ещё раз:

[simterm]

$ ansible -i hosts rtfm-dev-db --private-key=~/Work/RTFM/Bitbucket/aws-credentials/rtfm-dev.pem -m ping
db.dev.rtfm.co.ua | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

[/simterm]

Что бы не указывать путь к ключу в файле – можно вынести его в переменную, например host_key:

[rtfm-dev-bastion]
dev.rtfm.co.ua

[rtfm-dev-db]
db.dev.rtfm.co.ua

[rtfm-dev-db:vars]
ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p -q [email protected] -i {{ host_key }}"'

И вызываем ansible с --extra-vars:

[simterm]

$ ansible -i hosts rtfm-dev-db --private-key=~/Work/RTFM/Bitbucket/aws-credentials/rtfm-dev.pem --extra-vars host_key=~/Work/RTFM/Bitbucket/aws-credentials/rtfm-dev.pem -m ping
db.dev.rtfm.co.ua | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

[/simterm]

Потом добавим параметр в билд Jenkins, который будет передавать путь к ключу.

SSH ProxyJump и ssh.cfg

Другой вариант – использовать ssh.cfg (имя файла не имеет значения), как дополнение к ~/.ssh/config.

Создаём файл ssh.cfg, описываем подключение:

Host db.dev.rtfm.co.ua
  ProxyJump [email protected]
  IdentityFile ~/Work/RTFM/Bitbucket/aws-credentials/rtfm-dev.pem

Host dev.rtfm.co.ua
  IdentityFile ~/Work/RTFM/Bitbucket/aws-credentials/rtfm-dev.pem

Проверяем напрямую, через ssh клиент:

[simterm]

$ ssh -F ssh.cfg [email protected]
Linux ip-10-0-129-166 4.9.0-5-amd64 #1 SMP Debian 4.9.65-3+deb9u2 (2018-01-04) x86_64
...
Last login: Wed Jan 31 12:03:18 2018 from 10.0.1.155
admin@ip-10-0-129-166:~$

[/simterm]

Подключаем его в ansible.cfg, блок [ssh_connection]:

...
[ssh_connection]
ssh_args = -C -F ./ssh.cfg

И проверяем с ansible:

[simterm]

$ ansible -i hosts rtfm-dev-db -m ping 
db.dev.rtfm.co.ua | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

[/simterm]

Готово.

Ссылки по теме

Using Ansible with bastion host

How do I configure a jump host to access servers that I have no direct access to?

OpenSSH/Cookbook/Proxies and Jump Hosts