Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do RDS IAM Authentication with Django?

I want my django application connect to RDS postgres using IAM authentication. That means the db password expires every 15min and should be re-generated. The problem is how can I change the database password in the runtime? Or should I update my database URL environment?

like image 735
Nasir Avatar asked Sep 10 '19 07:09

Nasir


People also ask

How do I use IAM authentication with RDS?

You can activate IAM database authentication by using the Amazon RDS console, AWS Command Line Interface (AWS CLI), or the Amazon RDS API. If you use the Amazon RDS console to modify the DB instance, then choose Apply Immediately to activate IAM database authentication right away.

How does IAM database authentication work?

IAM database authentication works with MariaDB, MySQL, and PostgreSQL. With this authentication method, you don't need to use a password when you connect to a DB instance. Instead, you use an authentication token. An authentication token is a unique string of characters that Amazon RDS generates on request.


1 Answers

We implemented a package for this functionality and published to PyPi. You can check it here https://github.com/labd/django-iam-dbauth

But in principle here are the steps:

First enable IAM Authentication.

Then add the policy and attach it to the role or user that connects to the DB.

{
"Version": "2012-10-17",
"Statement": [
    {
        "Effect": "Allow",
        "Action": [
            "rds-db:connect"
        ],
        "Resource": [
            "arn:aws:rds-db:us-east-2:1234567890:dbuser:db-ABCDEFGHIJKL01234/db_userx"
        ]
    }
]
}

Then create a user on your AWS postgres and grant rds_iam role to it:

CREATE USER db_userx WITH LOGIN; 
GRANT rds_iam TO db_userx;

For Django, you need a custom backend to allow generating credentials on the fly.

Create a package such as your.package.postgresql with a base.py in it

import boto3
from django.db.backends.postgresql import base

class DatabaseWrapper(base.DatabaseWrapper):
    def get_connection_params(self):
        params = super().get_connection_params()
        rds_client = boto3.client("rds")
        params["password"] = rds_client.generate_db_auth_token(
            DBHostname=params.get("host", "localhost"),
            Port=params.get("port", 5432),
            DBUsername=params.get("user") or getpass.getuser(),
        )

        return params

Then use a settings like:

DATABASES = {
    "default": {
        "HOST": "<hostname>",
        "USER": "<user>",
        "PORT": 5432,
        "ENGINE": "your.package.postgresql"
    }
}
like image 180
Nasir Avatar answered Sep 22 '22 14:09

Nasir