Как сделать Python SSH-туннелирование с 2FA? - PullRequest
0 голосов
/ 29 августа 2018

Я пытаюсь написать скрипт на python, который подключается к базе данных, но эта база данных доступна только в том случае, если вы впервые подключитесь к хосту бастиона. Из командной строки вот что мне нужно сделать для настройки туннеля:

$ ssh -i /path/to/my/key/file.pem -A -L 3307:mydb1.fsd23rqr.us-east-1.rds.amazonaws.com:3306 my_ssh_username1@my-bastion-host.without.2fa
[ec2-user@ip-X-X-X-X ~]$ 

Я создал скрипт Python, используя эту библиотеку sshtunnel , чтобы сделать то же самое. Работает:

#!/usr/bin/env python
from sshtunnel import SSHTunnelForwarder
import MySQLdb as db
import pandas as pd

print('\nAbout to try connecting')
with SSHTunnelForwarder(
    ('my-ssh-host.without.2fa', 22),
    ssh_username='my_ssh_username1',
    ssh_pkey='/path/to/my/key/file.pem',
    remote_bind_address=('mydb1.fsd23rqr.us-east-1.rds.amazonaws.com', 3306),
    local_bind_address=('0.0.0.0', 3307)
) as tunnel:
    print "Connection Established"
    print pd.read_sql_query(
        "select 'Hello' from dual",
        db.connect(
            host='127.0.0.1',
            port=tunnel.local_bind_port,
            user='my_db_username1',
            passwd='****************',
            db='my_db_instance_1'
        )
    )

Производит:

About to try connecting
Connection Established
   Hello
0  Hello

Но теперь мне нужно использовать другую комбинацию БД и бастиона. Этот бастион имеет настройку 2-факторной аутентификации (2FA), так что когда я ssh к нему, он спрашивает меня, какой метод 2FA я выбираю. Если я выберу метод № 1, он отправит push-уведомление на мой телефон Android, которое я должен утвердить:

$ ssh -i /path/to/my/key/rsa -A -L 3307:mydb2.fsd23rqr.us-east-1.rds.amazonaws.com:3306 my_ssh_username2@my-bash-host.with.2fa
Duo two-factor login for my_ssh_username2

Enter a passcode or select one of the following options:

 1. Duo Push to XXX-XXX-9671
 2. Phone call to XXX-XXX-9671
 3. SMS passcodes to XXX-XXX-9671 (next code starts with: 1)


Passcode or option (1-3): 1

<WAIT FOR ME TO CLICK APPROVE ON MY ANDROID>

Success. Logging you in...
[my_ssh_username2@ip-X-X-X-1X ~]$

Но когда я пытаюсь настроить туннель, используя sshtunnel точно так же, как к бастиону с 2FA, он не работает:

About to try connecting
Connection Established
Enter DB password:
2018-08-29 15:31:43,985| ERROR   | Could not establish connection from ('127.0.0.1', 3307) to remote side of the tunnel
Traceback (most recent call last):
  <stack-trace snipped>
  File "python2.7/site-packages/MySQLdb/__init__.py", line 81, in Connect
    return Connection(*args, **kwargs)
  File "python2.7/site-packages/MySQLdb/connections.py", line 193, in __init__
    super(Connection, self).__init__(*args, **kwargs2)
_mysql_exceptions.OperationalError: (2013, "Lost connection to MySQL server at 'reading initial communication packet', system error: 0")

Как мне написать скрипт на python для подключения к базе данных MySQL через SSH-туннель, если для sshing на этот хост требуется 2FA ??

1 Ответ

0 голосов
/ 04 сентября 2018

Вам необходимо настроить интерактивный сеанс SSH, чтобы ввести параметры, предоставляемые сервером 2fa. Кратко рассмотрим код для библиотеки sshtunnel - кажется, что они используют библиотеку paramiko для подключения к шлюзу, а также для настройки туннеля. Методы, реализующие оба из них, не имеют возможности для предоставления интерактивного tty для пользовательского ввода.

Например, метод, выполняющий подключение к шлюзу, говорит следующее:

def _connect_to_gateway(self):
    Open connection to SSH gateway
     - First try with all keys loaded from an SSH agent (if allowed)
     - Then with those passed directly or read from ~/.ssh/config
     - As last resort, try with a provided password

Как видите, здесь нет опции для выполнения интерактивных команд сеанса SSH.

Таким образом, вы можете либо расширить код с помощью paramiko для настройки интерактивного сеанса, либо написать собственный код с помощью paramiko для управления как соединением шлюза, так и настройкой туннеля. Например, paramiko укажите , этот пример для выполнения интерактивных сеансов.

...