Two Authentication Methods for RDS Proxy
The following page shows how to access RDS from Lambda through RDS Proxy.
In the above page, we chose password authentication when connecting from Lambda to RDS Proxy.
Once again, the following is a summary of the authentication flow when using RDS Proxy.
Two methods are available for clients to connect to the RDS Proxy.
The first is password authentication. The first is password authentication, similar to a typical RDB connection.
The second is IAM authentication, which is an IAM policy-based method for specifying which DB users can connect.
Regardless of which authentication method is selected, the connection between RDS Proxy and RDS will be authenticated using the Secret Manager secret (user name and password).
In this article, we will compare the two authentication methods.
Environment
The basic structure is the same as in the previous page.
The difference is that we are creating two RDS Proxies for two authentications and preparing a Lambda function to use them.
The following is a brief description of the behavior of the configuration we are creating.
Create a table to store date/time data in a DB instance.
When an HTTP request arrives at the API Gateway, the back-end Lambda is called to retrieve the current date and time.
The acquired date/time data is stored in the DB instance via RDS Proxy.
In addition, all data stored in the DB instance is retrieved and returned as an HTTP response.
CloudFormation Template Files
The above configuration is built using CloudFormation.
The CloudFormation template is located at the following URL
https://github.com/awstut-an-r/awstut-fa/tree/main/039
Explanation of key points of the template files
The basic configuration is the same as the following page.
This page focuses on the RDS Proxy and the contents related to connecting to DB instances through the RDS Proxy.
Two authentication methods for RDS Proxy
RDS Proxy with password authentication
Let’s start with password authentication.
Resources:
DBProxy1:
Type: AWS::RDS::DBProxy
Properties:
Auth:
- IAMAuth: DISABLED
AuthScheme: SECRETS
SecretArn: !Ref Secret
DBProxyName: !Sub "${Prefix}-DBProxy-01"
EngineFamily: !Ref DBProxyEngineFamily
IdleClientTimeout: !Ref IdleClientTimeout
RequireTLS: false
RoleArn: !GetAtt DBProxyRole.Arn
VpcSecurityGroupIds:
- !Ref DBProxySecurityGroup
VpcSubnetIds:
- !Ref DBSubnet1
- !Ref DBSubnet2
Code language: YAML (yaml)
There are two points.
The first is the Auth property.
Since IAM authentication is not used here, set the IAMAuth property to “DISABLED”.
The second is the RequireTLS property.
In the case of password authentication, there is no need to enable TLS, so set it to “FALSE”.
RDS Proxy for IAM Authentication
Next, check IAM authentication.
Resources:
DBProxy2:
Type: AWS::RDS::DBProxy
Properties:
Auth:
- IAMAuth: REQUIRED
AuthScheme: SECRETS
SecretArn: !Ref Secret
DBProxyName: !Sub "${Prefix}-DBProxy-02"
EngineFamily: !Ref DBProxyEngineFamily
IdleClientTimeout: !Ref IdleClientTimeout
RequireTLS: true
RoleArn: !GetAtt DBProxyRole.Arn
VpcSecurityGroupIds:
- !Ref DBProxySecurityGroup
VpcSubnetIds:
- !Ref DBSubnet1
- !Ref DBSubnet2
Code language: YAML (yaml)
Check the two previous points.
In the first point, the IAMAuth property in the Auth property should be set to “REQUIRED”.
This will enable IAM authentication.
The RequireTLS property in the second point should be set to “true”.
This is a requirement for IAM authentication.
Make sure that you use Transport Layer Security (TLS)/Secure Sockets Layer (SSL) when connecting to a proxy using IAM authentication.
Connecting to a proxy using IAM authentication
Lambda functions connecting to the RDS Proxy
Lambda Layer
The two Lambda functions each use mysql-connector-python to connect to a MySQL type DB instance.
This time, the same package is prepared as a Lambda layer and referenced by the two functions.
Resources:
LambdaLayer:
Type: AWS::Lambda::LayerVersion
Properties:
CompatibleRuntimes:
- !Ref Runtime
Content:
S3Bucket: !Ref CodeS3Bucket
S3Key: !Ref CodeS3Key3
Description: !Ref Prefix
LayerName: !Ref Prefix
Code language: YAML (yaml)
The following command creates a ZIP file for the Lambda layer and uploads it to the S3 bucket
$ pip3 install mysql-connector-python -t ./python
$ zip -r layer.zip python
$ aws s3 cp layer.zip s3://[s3-bucket-name]/
Code language: Bash (bash)
For more information on Lambda layers, please refer to the following page
Lambda functions for password authentication
Check the Lambda function to connect with password authentication.
Resources:
Function1:
Type: AWS::Lambda::Function
Properties:
Environment:
Variables:
DB_ENDPOINT_PORT: !Ref MySQLPort
DB_NAME: !Ref DBName
DB_PASSWORD: !Ref DBMasterUserPassword
DB_PROXY_ENDPOINT_ADDRESS: !Ref DBProxyEndpointAddress1
DB_TABLENAME: !Ref DBTableName
DB_USER: !Ref DBMasterUsername
REGION: !Ref AWS::Region
Code:
S3Bucket: !Ref CodeS3Bucket
S3Key: !Ref CodeS3Key1
FunctionName: !Sub "${Prefix}-function-01"
Handler: !Ref Handler
Layers:
- !Ref LambdaLayer
Runtime: !Ref Runtime
Role: !GetAtt FunctionRole1.Arn
Timeout: !Ref Timeout
VpcConfig:
SecurityGroupIds:
- !Ref FunctionSecurityGroup
SubnetIds:
- !Ref FunctionSubnet
Code language: YAML (yaml)
The point is the environment variables.
The Environment property allows you to define environment variables that can be used within a function.
A particularly important variable is the password (DB_PASSWORD) for connecting to the DB instance.
This function is for password authentication.
The IAM role for this function is as follows
Resources:
FunctionRole1:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
Code language: YAML (yaml)
No special configuration is required.
Only the AWS management policy prepared for Lambda is specified.
Check the contents of the function.
In particular, we will focus on the part that creates the MySQL connection object.
import mysql.connector
import os
db_endpoint_port = os.environ['DB_ENDPOINT_PORT']
db_name = os.environ['DB_NAME']
db_password = os.environ['DB_PASSWORD']
db_proxy_endpoint_address = os.environ['DB_PROXY_ENDPOINT_ADDRESS']
db_tablename = os.environ['DB_TABLENAME']
db_user = os.environ['DB_USER']
region = os.environ['REGION']
def lambda_handler(event, context):
conn = mysql.connector.connect(
host=db_proxy_endpoint_address,
port=db_endpoint_port,
user=db_user,
password=db_password,
database=db_name
)
Code language: Python (python)
Use mysql-connector-python (mysql.connector) provided in the Lambda layer.
This is password authentication, so in addition to the RDS Proxy endpoint, etc. to which you are connecting, you must specify a password.
Lambda function for IAM authentication
Check the Lambda function to connect with IAM authentication.
Resources:
Function2:
Type: AWS::Lambda::Function
Properties:
Environment:
Variables:
DB_ENDPOINT_PORT: !Ref MySQLPort
DB_NAME: !Ref DBName
#DB_PASSWORD: !Ref DBMasterUserPassword
DB_PROXY_ENDPOINT_ADDRESS: !Ref DBProxyEndpointAddress2
DB_TABLENAME: !Ref DBTableName
DB_USER: !Ref DBMasterUsername
REGION: !Ref AWS::Region
SSLCERTIFICATE: AmazonRootCA1.pem
Code:
S3Bucket: !Ref CodeS3Bucket
S3Key: !Ref CodeS3Key2
FunctionName: !Sub "${Prefix}-function-02"
Handler: !Ref Handler
Layers:
- !Ref LambdaLayer
Runtime: !Ref Runtime
Role: !GetAtt FunctionRole2.Arn
Timeout: !Ref Timeout
VpcConfig:
SecurityGroupIds:
- !Ref FunctionSecurityGroup
SubnetIds:
- !Ref FunctionSubnet
Code language: YAML (yaml)
The difference from the previous function for password authentication is the environment variable to be defined.
Since this is IAM authentication, the password is not needed, so it is commented out.
As described later, the file name of the certificate to be included in the deployment package for the Lambda function is also defined as a variable.
The IAM role for this function is as follows
Resources:
FunctionRole2:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
Policies:
- PolicyName: AllowRDSDBConnectPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- rds-db:connect
Resource:
- !Sub "arn:aws:rds-db:${AWS::Region}:${AWS::AccountId}:dbuser:${DBProxyId2}/${DBMasterUsername}"
Code language: YAML (yaml)
In addition to the AWS management policies discussed earlier, define an inline policy.
The content of this policy is to allow the “rds-db:connect” action for the DB user specified at DB instance creation.
This policy was defined by referring to the following page
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.IAMPolicy.html
Check the contents of the function.
In particular, we will focus on the creation of the MySQL connection object.
import mysql.connector
import os
db_endpoint_port = os.environ['DB_ENDPOINT_PORT']
db_name = os.environ['DB_NAME']
#db_password = os.environ['DB_PASSWORD']
db_proxy_endpoint_address = os.environ['DB_PROXY_ENDPOINT_ADDRESS']
db_tablename = os.environ['DB_TABLENAME']
db_user = os.environ['DB_USER']
region = os.environ['REGION']
ssl_certificate = os.environ['SSLCERTIFICATE']
os.environ['LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN'] = '1'
client = boto3.client('rds', region_name=region)
def lambda_handler(event, context):
token = client.generate_db_auth_token(
DBHostname=db_proxy_endpoint_address,
Port=db_endpoint_port,
DBUsername=db_user,
Region=region)
conn = mysql.connector.connect(
host=db_proxy_endpoint_address,
user=db_user,
password=token,
port=db_endpoint_port,
database=db_name,
ssl_ca=ssl_certificate)
Code language: Python (python)
Refer to the following page to implement object creation during IAM authentication.
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.Connecting.Python.html
There are two points.
The first is to create a temporary token and use it as the password, rather than setting the password directly.
The token is created with client.generate_db_auth_token.
The second point is the specification of the certificate.
When connecting to a DB instance with IAM authentication, a certificate must be specified.
This certificate can be downloaded from AWS.
For the .pem file to use, download all root CA PEMs from Amazon Trust Services and place them into a single .pem file.
RDS Proxy concepts and terminology
The following command is an example of downloading a certificate
$ curl -OL https://www.amazontrust.com/repository/AmazonRootCA1.pem
Code language: Bash (bash)
When creating the package for the Lambda function, zip and deploy this certificate (AmazonRootCA1.pem) as well.
Architecting
Using CloudFormation, build this environment and check the actual behavior.
Create CloudFormation stacks and check resources in stacks
Create a CloudFormation stack.
For information on how to create stacks and check each stack, please refer to the following page
After checking the resources in each stack, information on the main resources created this time is as follows
- API Gateway endpoints: https://6ug0w6jg5b.execute-api.ap-northeast-1.amazonaws.com
The resource creation status is also checked from the AWS Management Console.
Check the items related to RDS Proxy authentication.
The RDS Proxy is configured for password authentication and IAM authentication, respectively.
Confirmation of Operation
Now that everything is ready, access the API Gateway.
First, check the operation of the Lambda function that connects with password authentication.
/func1 is the URL of this function.
The response is returned normally.
We have confirmed that we can connect with password authentication.
Next, check the operation of the Lambda function that connects with IAM authentication.
/func2 is the URL of this function.
The response was returned normally.
We have confirmed that we can connect with IAM authentication.
Summary
We confirmed two authentication methods when connecting from Lambda to DB instance via RDS Proxy.