Monday, April 29, 2024
No menu items!
HomeDatabase ManagementAchieve auditability with Amazon RDS IAM authentication using attribute-based access control

Achieve auditability with Amazon RDS IAM authentication using attribute-based access control

Amazon Relational Database Service (Amazon RDS) supports several ways to authenticate database users, including password authentication, Amazon Identity and Access Management (IAM) database authentication, and Kerberos authentication. When working with MySQL, PostgreSQL, and Amazon Aurora database engines, you can authenticate to the database using IAM, which uses an authentication token instead of the password to connect to the database. For more information, refer to Connecting to your DB instance using IAM authentication. IAM database authentication is not the default option; you can select it when you create the RDS database instance or modify an existing instance.

If you already have your database running, you can enable IAM database authentication either from the AWS Management Console or the AWS Command Line Interface (AWS CLI). The benefit of using IAM authentication is that you don’t need to store any credentials within Amazon RDS because the token is externally managed by IAM. From a security perspective, the credentials are encrypted using Secure Socket Layer (SSL) or Transport Layer Security (TLS) when sent over the network for additional protection.

At the time of writing this blog, IAM database authentication is not available for all DB engines and also not on all versions of a DB engine or for a Multi-AZ database cluster. Before architecting the security model of your database, verify whether the IAM authentication feature is available for the selected DB engine and its corresponding deployment configuration.

Amazon RDS authentication using Amazon IAM allows you to control access to RDS instances using IAM roles and policies. AWS customers accessing AWS using a federated solution require users to select the account and role they wish to assume during the authentication process. In such a scenario, multiple users can be mapped to a single role, as shown in the following figure.

In the above diagram, all database activities performed by DB-Admin-Role will be tracked as having been executed by the database user DBAdmin and not by the federated users JohnDoe or JaneDoe (we will dive deeper why in the this section). From an audit tracing perspective, this makes it difficult to trace back which federated user performed what database operations because all operations will be logged as the same DBAdmin database user in the database audit logs. In addition, you want to audit the IAM users in the AWS Cloud Trail that invokes the generate-db-auth-token.

In this post, we show how you can configure auditability with Amazon RDS IAM authentication using attribute-based access control and AWS Lambda function. The federated user name can be retrieved using IAM attribute-based access control (ABAC) and mapped dynamically to the database user attribute for connecting to the DB instance in the IAM policy associated to that role.  We will explain how we can use AWS Lambda function to populate IAM user name that invokes the generate-db-auth-token call in AWS CloudTrail for that action.

Dynamic binding using IAM session tags

With IAM session tags, you can send user-specific attributes in the AWS session when users assume an IAM role during the login process. Enterprise customers manage their users’ identities using an identity provider such as Microsoft Active Directory (AD) and use a federation service such as Active Directory Federation Service (AD FS) to integrate with IAM using industry standards such as SAML and OpenID Connect (OIDC). This integration allows users to be federated into AWS using their corporate login credentials, such as their user name and password from Microsoft AD.

With AWS session tags, you can configure the federation service to send attributes in the AWS sessions when users federate into AWS and use these attributes in the IAM policies for controlling access to AWS resources.

Solution overview

In this section, we describe in detail how to implement full auditability while using RDS IAM database authentication.

Some customers use federation in conjunction with RDS IAM database authentication. Refer to the instructions in Use attribute-based access control with AD FS to simplify IAM permissions management to enable single sign-on (SSO) for your AWS account. When a federated identity authenticates, the identity is associated with the IAM role is granted the permissions that are defined by the role. By sending AD attributes to AWS during authentication, you can use the IAM ABAC approach to populate the dbusername in rds-db:connect, as shown in the following figure.

The workflow includes the following steps:

The user is authenticated by the SAML identity provider and pushed to AWS IAM Identity Center.
The user chooses an IAM role with the appropriate IAM authentication policy.
The IAM role invokes a Lambda function to generate a token.
The Lambda function call gets logged in CloudTrail.
The function generates a token.
The function returns the token to the user.
The user logs in to the database using the generated token and IAM authentication.
The database activity is logged and exported to Amazon CloudWatch.

Refer to Rely on employee attributes from your corporate directory to create fine-grained permissions in AWS for more details on how to implement this.

When using IAM authentication on Amazon RDS, you work with authentication tokens. An authentication token is a unique string of characters that Amazon RDS generates on request. Authentication tokens are generated using AWS Signature Version 4. Each token has a lifetime of 15 minutes. You don’t need to store user credentials in the database because authentication is managed externally using IAM. You can also still use standard database authentication. The token is only used for authentication and doesn’t affect the session after it is established. IAM database authentication provides the following benefits:

Network traffic to and from the database is encrypted using SSL/TLS. For more information about using SSL/TLS with Amazon RDS, see Using SSL/TLS to encrypt a connection to a DB instance.
You can use IAM to centrally manage access to your database resources instead of managing access individually on each DB instance.
For applications running on Amazon Elastic Compute Cloud (Amazon EC2), you can use profile credentials specific to your EC2 instance to access your database instead of a password for greater security.

We explain how to use this technique to audit access to your database using IAM, CloudTrail, and Lambda.

First, you need to set up IAM database authentication. For full details, refer to How do I allow users to authenticate to an Amazon RDS for MySQL DB instance using their IAM credentials?

After the setup is complete, you can use rds generate-db-auth-token to connect to your DB instance. In many cases, you can use the generate-db-auth-token call directly from your laptop and then connect to Amazon RDS using your preferred client tool.

Note that generate-db-auth-token is a client-side function, which gives the caller a token and is not recorded in CloudTrail. To see who used the function, we describe an approach with a Lambda wrapper.

The following are the high-level steps to achieve this:

Create an IAM role for Lambda to generate a token for Amazon RDS authentication.
Create a Lambda function that can generate a token on the user’s behalf.
Create a script that invokes the Lambda function.
Enable CloudTrail for Lambda function invocations.

Create an IAM role for Lambda

Let’s start with the first step and a create Lambda execution role. Replace the following placeholders with actual values from your AWS account:

AWS_REGION – The AWS Region the Lambda function is in.
ACCOUNT_NUMBER – The AWS account number the Lambda function is in.
DB_RESOURCE_ID – Your RDS instance resource ID, which you can find on the RDS Configuration tab. An example of the format is db-AG2ZZOFRT7RWHHZ6ODVFGHGSDAY.
${aws:username} – The variable that will be substituted for an actual user name when the Lambda function is called. This is very useful to dynamically bind users instead of hardcoding.

See the following IAM Policy:

{
“Version”: “2012-10-17”,
“Statement”: [
{
“Sid”: “LamdaTokenGenRole”,
“Effect”: “Allow”,
“Action”: “rds-db:connect”,
“Resource”: “arn:aws:rds-db:<AWS_REGION>:<ACCOUNT_NUMBER>:dbuser:<DB_RESOURCE_ID>/${aws:username}
}
]
}

Create a Lambda function

Now you create the Lambda function to generate a token for Amazon RDS authentication. We provided a sample Python 3.8 Lambda function. The function takes the Region and RDS DB host name from environmental variables, but the user is passed as a variable from the command line script that users can run on their local environment.

After you obtain the variables you create the RDS client and run a generate-db-auth-token command with the actual values of the DB host name, port, and user. The user is an RDS user that has permission to your database. See the following code:

import os
import boto3

def lambda_handler(event, context):
# Get RDS credentials from environment variables
REGION = os.environ[‘REGION’]
DB_HOSTNAME = os.environ[‘DB_HOSTNAME’]
#the usser from the CLI command
db_user_cli=event.get(‘db_user_cli’)
# Create an RDS client
rds = boto3.client(‘rds’, region_name=REGION)

# Generate an RDS authentication token
token = rds.generate_db_auth_token(DBHostname=DB_HOSTNAME, Port=3306, DBUsername=db_user_cli)

print(token)
# Return the authentication token (for testing purposes only)
return {
‘token’: token
}

Create a script to invoke the Lambda function

Now you create a command line script that invokes your Lambda function and returns the token for your developers to use when using their preferred DB client. The following is an example AWS CLI script(replace DB_USER with the user name that will be executing this command):

aws lambda invoke –region <YOUR_REGION> –function-name generate-token –payload ‘{“db_user_cli”:<DB_USER>}’  output.txt

For more information about how to invoke Lambda functions, refer to the AWS CLI Command Reference. The script doesn’t check the validity of the user, but you can add input validation to further enhance the function. Additionally, the user that runs the script must have the appropriate permission for Lambda function invocation. Refer to Identity-based IAM policies for Lambda for more details. The following is an example of a least privilege policy:

{
“Version”: “2012-10-17”,
“Statement”: [
{
“Action”: “lambda:InvokeFunction”,
“Effect”: “Allow”,
“Resource”: “<ARN of the function which is allowed to be invoked>
}
]
}

Enable CloudTrail for Lambda function invocations

The final step is to enable CloudTrail for Lambda function invocations, which are CloudTrail data events so you can audit who ran the generate-token function and when. For more information, refer to Logging Lambda API calls with CloudTrail.

After you enable the data events for Lambda, you can see the CloudTrail event with the user that invoked the Lambda function and received the Amazon RDS authentication token.

The following is a snippet of what the CloudTrail event looks like. Replace the placeholders with the actual values in your AWS account:

{
“eventVersion”: “1.08”,
“userIdentity”:
{
“type”: “IAMUser”,
“principalId”: “AIDASH1234567891234”,
“arn”: “arn:aws:iam::ACCOUNT_ID:user/ACTUAL_USER”,
“accountId”: “ACCOUNT_ID”,
“accessKeyId”: “AKIASH1234567891234”,
“userName”: “ACTUAL_USER”
},
“eventTime”: “2024-03-26T10:20:04Z”,
“eventSource”: “lambda.amazonaws.com”,
“eventName”: “Invoke”,
“awsRegion”: “us-east-1”,
“sourceIPAddress”: “12.123.123.12”,
“userAgent”: “aws-cli/1.29.57 md/Botocore#1.31.57 ua/2.0 os/macos#23.3.0 md/arch#arm64 lang/python#3.11.7 md/pyimpl#CPython cfg/retry-mode#legacy botocore/1.31.57”,
“requestParameters”:
{
“functionName”: “arn:aws:lambda:us-east-1:ACCOUNT_ID:function:generate-token”
},
“responseElements”: null,
“additionalEventData”:
{
“customerEniId”: “eni-12345678912”,
“functionVersion”: “arn:aws:lambda:us-east-1:ACCOUNT_ID:function:generate-token:$LATEST”
},
“requestID”: “0dd5b957-242e-4feb-bde0-b4214b837714”,
“eventID”: “faceeac7-3b3c-4765-b38b-5f9e004fe5dc”,
“readOnly”: false, “resources”:
[
{
“accountId”: “ACCOUNT_ID”,
“type”: “AWS::Lambda::Function”,
“ARN”: “arn:aws:lambda:us-east-1:ACCOUNT_ID:function:generate-token”
}
],
“eventType”: “AwsApiCall”,
“managementEvent”: false,
“recipientAccountId”: “ACCOUNT_ID”,
“eventCategory”: “Data”,
“tlsDetails”:
{
“tlsVersion”: “TLSv1.2”,
“clientProvidedHostHeader”: “lambda.us-east-1.amazonaws.com”
}
}

Clean up

To avoid incurring additional costs on the resources created during this post, complete the following steps to remove them:

Delete the IAM role for Lambda to generate a token for Amazon RDS authentication.
Delete the Lambda function that can generate a token on the user’s behalf.
Disable CloudTrail logging for Lambda function invocations.
Delete the CloudTrail log that stores the Lambda function invocations.

Conclusion

IAM authentication for Amazon RDS simplifies the authentication to Amazon RDS open source and Aurora databases. It also provides robust security with identity federation mechanisms such as SAML. By configuring SAML with IAM authentication, you can use dynamic mapping between IAM and database users to avoid manually removing and adding database users in the IAM policy. In this post, we walked you through how to use a custom Lambda function to get complete auditability of database logs while performing IAM authentication to your RDS databases. By reviewing the CloudTrail API calls by the Lambda function and database login events in the database audit log, you can get end-to-end auditability from IAM and a database login perspective while using Amazon RDS IAM authentication. In this post we walked you through auditability for federated users, but it can also work as a standalone Amazon RDS IAM authentication if your environment is not set up with SSO.

Now you are ready to try out auditability with Amazon RDS IAM authentication using attribute-based access control. If you have any questions, comments, or suggestions, leave a comment.

About the Authors

Niko Borodachuk is a Sr. Partner Solutions Architect at Amazon Web Services. At AWS, he provides technical guidance, architectural advice, and thought leadership to AWS’s partners across the North and South East regions in the US, focusing on security.

Saikat Banerjee is a Sr. Database Solutions Architect with Amazon Web Services. He works with customers to modernize their database architecture on Amazon Web Services.

Muthuvelan Swaminathan is an Enterprise Solutions Architect based out of New York. He works with enterprise customers, providing architectural guidance in building resilient, cost-effective, innovative solutions that address their business needs and help them operate at scale using AWS products and services.

Read MoreAWS Database Blog

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments