Reputation: 3720
I have an AWS RDS DB running MySQL 5.6.39, with IAM DB Authentication Enabled.
First of all, I completed with success the Tutorial: Configuring a Lambda Function to Access Amazon RDS in an Amazon VPC and this was my starting point for the next steps.
I want to log in with IAM credentials and so, following this and this tutorials, I did:
When I created the RDS MySQL instance, I selected Enabling IAM database authentication
.
Created a user named lambda
:
CREATE USER 'lambda' IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS';
GRANT ALL PRIVILEGES ON test_db.* TO 'lambda'@'%';
FLUSH PRIVILEGES;
Created an IAM policy, and attached it to the role I was using as an Execution role for my lambda function:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"rds-db:connect"
],
"Resource": [
"<DB-ARN>/lambda"
]
}
]
}
Created a lambda function:
import sys
import boto3
import logging
import pymysql
#rds settings
rds_host = "<RDS-ENDPOINT>"
username = "lambda"
db_name = "test_db"
logger = logging.getLogger()
logger.setLevel(logging.INFO)
client = boto3.client('rds',region_name='eu-west-2')
token = client.generate_db_auth_token(rds_host,3306, name)
ssl = {'ca': 'rds-combined-ca-bundle.pem'}
logger.info("token: "+ token)
conn = pymysql.connect(rds_host, user=username, passwd=token, db=db_name, connect_timeout=5, ssl=ssl)
logger.info("SUCCESS: Connection to RDS mysql instance succeeded")
def handler(event, context):
...
I got the following error:
error: (1045, "Access denied for user 'lambda'@'<LAMBDA_IP>' (using password: YES)")
In an attempt to find If it was a python error I used AWS CLI, from an EC2 instance with the policy attached.
Get the token:
aws rds generate-db-auth-token --hostname <RDS-ENDPOINT> --port 3306 --username lambda
Connect to the DB, using the token I got in the last step:
mysql -h <RDS-ENDPOINT> -u lambda --enable-cleartext-plugin --password='<TOKEN>'
I got the same error:
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'lambda'@'<EC2_IP>' (using password: YES)
Upvotes: 5
Views: 6654
Reputation: 1696
I was seeing this error as well after triple-checking the configuration of the database as well as IAM and role attachments. It turned out to be my connector inside my Python lambda function.
My goal was to connect to my RDS MySQL database using sqlalchemy
+ pymysql
. I first figured out the necessary parameters for pymysql
and then converted them over to use in sqlalchemy
.
Here is my pymysql
solution:
conn = pymysql.connect(
# Maybe this was the parameter I was missing, to tell it to connect without a standard password
auth_plugin_map={'mysql_clear_password':None},
host=ENDPOINT,
user=USER,
password=token,
port=PORT,
database=DBNAME,
ssl_ca='RDS_Certificate.pem',
ssl_verify_identity=False)
and the sqlalchemy
solution:
DBHostname = DBCLUSTER_HOSTNAME
DBPort = DBCLUSTER_PORT
DBUsername = DBCLUSTER_USER
DBName = DBCLUSTER_NAME
engine = sqlalchemy.create_engine(
"mysql+pymysql:///"
) # connection params will be set by the event callback
@sqlalchemy.event.listens_for(engine, "do_connect")
def provide_token(dialect, conn_rec, cargs, cparams):
client = boto3.client("rds")
token = client.generate_db_auth_token(
DBHostname=DBHostname,
Port=int(DBPort),
DBUsername=DBUsername,
Region=REGION,
)
# set up db connection parameters, alternatively we can get these from boto3 describe_db_instances
cparams["host"] = DBHostname
cparams["port"] = int(DBPort)
cparams["user"] = DBUsername
cparams["password"] = token
cparams["database"] = DBName
cparams["ssl"] = {
"ca": "ssl-ca-bundle.pem",
"verify_identity": False,
}
cparams["auth_plugin_map"] = {
"mysql_clear_password": None,
}
Upvotes: 0
Reputation: 3720
The policy is not correct!
The Resource
is not the DB ARN, but "arn:aws:rds-db:<AWS_REGION>:<AWS_ACCOUNT_ID>:dbuser:<AWS_DB_RESOURCE_ID>/<DB_USERNAME>"
To get this information from the management console, you can go to:
eu-west-2
or any other from here.Details\Configuration\Resource ID
in the DB page and it starts with db-
.lambda
because it was the one created in step 2.By the way, and as Michael - sqlbot pointed out here and in this answer, the generation of the token is local so getting it should not be interpreted as getting a correct password.
Upvotes: 4