on
Using AWS IAM Authentication with JDBC and AWS RDS
Introduction
For applications using AWS Relational Database Service (RDS) we have the option to make use of AWS Identity and Access Management (IAM) credentials instead of the native authentication methods e.g. username/password credentials to connect to the RDS database.
IAM authentication is supported for MariaDB, MySQL and PostgreSQL.
ℹ️ This article focuses on an application connecting to MySQL using a JDBC database driver.
Prerequisites
To make use of IAM authentication a Secure Sockets Layer (SSL) connection is required with the appropriate SSL certificate available to the JDBC database driver. The SSL certificate can be sourced from the Amazon S3 bucket that’s identified in the Amazon RDS documentation.
Steps Required
- Configure IAM DB authentication on the RDS DB instance.
- Create a database user account that uses an AWS authentication token.
- Add an IAM policy that maps the database user to the IAM role configured for your application.
- Configure the JDBC driver to use IAM.
1. Configure IAM DB authentication on the RDS DB instance
To allow IAM authentication to the RDS instance we need to enable it. This can be done via the console, AWS CLI, or in our example making use of CloudFormation.
In CloudFormation set the EnableIAMDatabaseAuthentication
property to true for the AWS::RDS::DBCluster
instance.
...
Resources:
...
YourDatabaseCluster:
Type: AWS::RDS::DBCluster
Properties:
...
EnableIAMDatabaseAuthentication: true
2. Create a database user account that uses an AWS authentication token
CREATE USER my_db_user IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS';
ALTER USER my_db_user REQUIRE SSL;
GRANT SELECT, INSERT, UPDATE, DELETE, SHOW VIEW ON *.* TO 'my_db_user'@'%';
In the first statement, the IDENTIFIED WITH
clause allows MySQL to use the AWSAuthenticationPlugin to authenticate the database account my_db_user
.
The AS 'RDS'
clause maps the my_db_user
database account to the corresponding IAM user or role that is specified by the IAM policy.
The second statement enforces the use of SSL connections to the database and the third statement grants the user specific permissions on all the schemas.
3. Add an IAM policy that maps the database user to the IAM role
Assume the application already have an existing IAM role, if not you need to create the IAM role as well.
To allow the connection to RDS with IAM authentication modify your IAM policy. Note the database username needs to match with the user created in the previous
step e.g. my_db_user
Four parts are required:
- AWS Region of your cluster
- AWS account number
- The DB resource ID
- Database username
ℹ️ The resource ID is the identifier for the DB instance. This identifier is unique to an AWS Region and never changes.
To find a resource ID in the Amazon RDS console, choose the DB cluster that you want and the resource ID is shown in the Details section.
Alternatively, you can use the AWS CLI command to list the identifiers and resource IDs for all of your DB instances in the current AWS Region:
aws rds describe-db-instances --query "DBInstances[*].[DBInstanceIdentifier,DbiResourceId]"
CDK example
role.addToPolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [
'rds-db:connect'
],
resources: [`arn:aws:rds-db:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:dbuser:${props.dbClusterResourceId}/my_db_user`]
}));
CloudFormation example
{
"Version": "2012-10-17",
"Statement":
[
{
"Effect": "Allow",
"Action": [ "rds-db:connect" ],
"Resource": [
!Sub arn:aws:${ AWS::Region }:${ AWS::AccountId }:dbuser:${ dbClusterResourceId }/my_db_user
]
}
]
}
4. Configure the JDBC driver to use IAM
To connect to MySQL we can use the MariaDB ConnectorJ database driver or an alternative option is the AWS MySQL database driver. Both allow the use of IAM authentication when the appropriate properties are specified.
ℹ️ The
com.amazonaws:aws-java-sdk-rds
(AWS SDK v1) orsoftware.amazon.awssdk:rds
(AWS SDK v2) dependency must be provided on the classpath.
For MariaDB we can configure the connection string as follows
jdbc:mariadb://<cluster_endpoint_name>:3306/<database_schema>?credentialType=AWS-IAM&sslMode&serverSslCert=https://truststore.pki.rds.amazonaws.com/ap-southeast-2/ap-southeast-2-bundle.pem
The serverSslCert
property needs to be able to resolve to an URI otherwise it will fail. Sourcing the SSL certificate directly from AWS trust store means we
can get an updated copy by restating the application if required.
The AWS MySQL driver can be configured alike this
jdbc:mysql:aws://<cluster_endpoint_name>:3306/<database_schema>?useAwsIam=true
Note that the AWS driver do not require us to specify the SSL certificate path.
Connecting Locally
When running your application locally you need to be logged in to AWS. The database driver requires that the AWS credentials to be available locally. You can sign in locally by using the AWS CLI.
ℹ️ The database driver makes use of the DefaultAWSCredentialsProviderChain from the AWS SDK to find the credentials required to authenticate. Ensure that your local login provides the credentials as required. E.g. for the
ProfileCredentialsProvider
it expect to find credentials in your AWS configuration profiles${HOME}/.aws/credentials