Подключение к Amazon Aurora с помощью SQLAlchemy

Я пытаюсь подключиться к Amazon Aurora с помощью SQLAlchemy, используя SSL-соединение, указав роль IAM в качестве учетной записи пользователя базы данных и токен аутентификации в качестве пароля, как описано здесь в [AWS docs] (http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html#UsingWithRDS.IAMDBAuth.Connecting)

Вот шаги, которым я следовал.

wget https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem

export LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN=1

aws rds generate-db-auth-token --hostname 'datadbcluster-1.cluster-xxxxxxxxxxxx.us-west-2.rds.amazonaws.com' --port 3306 --username dt_analyst --region us-west-2 > /home/ubuntu/dt_analyst.pem

mysql -h datadbinstance2nd. xxxxxxxxxxxx.us-west-2.rds.amazonaws.com--ssl-ca /home/ubuntu/rds-combined-ca-bundle.pem -u dt_analyst --ssl-verify-server-cert --enable-cleartext-plugin -p'<token>'

Я подтвердил, что могу подключиться через SSL с помощью клиента mysql.

Но я хочу подключиться с помощью sqlalchemy, а не клиента mysql. Следующий код составлен из десятка советов, найденных в Интернете, но дает только следующую ошибку.

‘Sqlalchemy.exc.OperationalError: (_mysql_exceptions.OperationalError) (1045,« Доступ запрещен для пользователя… »)’

Мой код выглядит следующим образом.

import boto3

client = boto3.client('rds', region_name='us-west-2')

dialect='mysql'
user = ‘dt_analyst’
host = 'datadbcluster-1.cluster-xxxxxxxxxxxx.us-west-2.rds.amazonaws.com'
port = 3306
data = ‘datadb’
region='us-west-2'

token = client.generate_db_auth_token(host,port,user,region)
host1 = 'datadbinstance2nd. xxxxxxxxxxxx.us-west-2.rds.amazonaws.com'
conn_str = '%s://%s:%s@%s:%d/%s'%(dialect,user,token,host1,port,data)
conn_str += '?ssl_key=%s'%token
conn_str += '&ssl_cert=’/home/ubuntu/rds-combined-ca-bundle.pem'

ssl_args = {
    'ssl': {
        'ca_cert': '/home/ubuntu/rds-combined-ca-bundle.pem',
        'sslmode': 'require',
        'verify_ssl_cert': True
    }
}

engine = create_engine(conn_str,connect_args=ssl_args, echo=True)

person vrlkm17    schedule 20.09.2017    source источник
comment
Мне нравится ваше взаимодействие, поэтому я бы порекомендовал обратиться в службу поддержки AWS по этому поводу. Если смогли разобраться, поделитесь! Спасибо.   -  person The-Big-K    schedule 25.10.2018
comment
Во фрагменте кода есть одно упущение: откуда взято create_engine. Я проследил его до sqlalchemy.create_engine, который пересылает connect_args как kwarg в базовую библиотеку коннекторов PyMySQL или mysqlclient.   -  person Freek Wiekmeijer    schedule 09.02.2019


Ответы (1)


Мой ответ тройной:

Роли IAM

Есть один шаг, который здесь не упоминался: вам нужно назначить роль IAM, которая дает вашему клиенту право подключаться к RDS.

Под «клиентом» я подразумеваю любой ресурс AWS, на котором выполняется код из этого вопроса. Это может быть лямбда-функция, экземпляр EC2 или что-то еще. Как бы то ни было, у него есть ARN, и ему должно быть разрешено действие rds-db:connect.

Строка подключения для цитирования URL

Тогда может быть проблема с учетными данными RDS. Возможно, вам придется указать пароль в кавычках, если он содержит символы, недопустимые в URL-адресе.

  • Python 3: passwd = urllib.parse.quote(rds_password)
  • Python 2: passwd = urllib.quote(rds_password)

Временные учетные данные RDS

Наконец, возможно, вашей базе данных RDS требуются временные учетные данные. В этом примере кода показано, как их получить:

# get RDS config, often done through environment variables
import os

rds_host = os.environ.get("RDS_HOST")  
rds_port = os.environ.get("RDS_PORT")
rds_username = os.environ.get("RDS_USER")   

# get temp credential
import boto3

temp_passwd = boto3.client('rds').generate_db_auth_token(
    DBHostname=rds_host,
    Port=rds_port,
    DBUsername=rds_username 
)

rds_credentials = {'user': rds_username, 'passwd': temp_passwd}

Собираем вместе:

def create_sqlalchemy_engine(self):
    conn_str = f"{protocol}://{rds_host}:{rds_port}/{database}"

    kw = dict()
    kw.update(rds_credentials)
    # kw.update({'ssl': {'ca': /path/to/pem-file.pem}})  # MySQL
    # kw.update({'sslmode': 'verify-full', 'sslrootcert /path/to/pem-file.pem})  # PostgreSQL

    return create_engine(conn_str, connect_args=kw)

Я переместил параметры user и passwd из строки соединения в connect_args. Это устраняет необходимость в цитировании URL.

См. Также: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.IAMPolicy.html

person Freek Wiekmeijer    schedule 09.02.2019