Connect Django to Amazon RDS With IAM Authentication

Connect Django to Amazon RDS PostgreSQL or Aurora with IAM database authentication instead of a static password: grant rds_iam, create an rds-db:connect policy, generate auth tokens in a custom database backend, and require TLS.

Problem statement

A static database password in an environment variable or Secrets Manager works, but it is a long-lived credential that must be rotated, can leak in logs or dumps, and is shared by every process. RDS IAM authentication replaces it with short-lived tokens generated from the IAM role your EC2 instance, ECS task, or EKS pod already has. Django needs a small extension to request a fresh token when it opens a connection, plus the right IAM policy and database grants.

IAM auth to RDSApp roleEC2, ECS, or EKSGenerate tokenvalid 15 minutesConnect with TLStoken as passwordRDS checks IAMrds_iam roleThe token replaces the password and is only needed when a new connection opens.
  1. Enable IAM database authentication on the RDS instance or Aurora cluster.
  2. In PostgreSQL: CREATE USER app; GRANT rds_iam TO app; (no password).
  3. Attach an IAM policy allowing rds-db:connect on arn:aws:rds-db:<region>:<account>:dbuser:<DbiResourceId>/app to the app's role.
  4. Subclass Django's PostgreSQL backend to generate a token with boto3 in get_connection_params.
  5. Require TLS (sslmode=verify-full with the RDS CA bundle).
  6. Keep CONN_MAX_AGE moderate; tokens are only checked at connect time.

Step-by-step solution

1. Enable IAM authentication and create the user

Enable "IAM database authentication" on the instance (console, CLI --enable-iam-database-authentication, or IaC). Then, connected as the master user:

CREATE USER app;
GRANT rds_iam TO app;
GRANT CONNECT ON DATABASE appdb TO app;
\c appdb
GRANT USAGE, CREATE ON SCHEMA public TO app;

A user in rds_iam can only log in with IAM tokens. Keep a separate migration or admin user if your process needs one.

2. Allow the role to connect

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": "rds-db:connect",
    "Resource": "arn:aws:rds-db:eu-west-1:123456789012:dbuser:db-ABCDEFGHIJKL0123/app"
  }]
}

The resource uses the instance's DbiResourceId (shown in the console), not its name. Attach the policy to the EC2 instance role, ECS task role, or the pod's IAM role.

every layer must agreeIAM role on the computeEC2, ECS task, EKS podPolicy rds-db:connectdbuser ARN with resource IDCustom Django backendtoken as password on connectTLS to RDSverify-full with RDS CADB user with rds_iamno password setA missing piece shows up as PAM authentication faileddjango-deployment.com
Check the policy resource ID first; it is the most common mistake.

3. Generate tokens in a custom backend

# myproject/db/rds_iam/base.py
import boto3
from django.db.backends.postgresql import base

class DatabaseWrapper(base.DatabaseWrapper):
    def get_connection_params(self):
        params = super().get_connection_params()
        client = boto3.client("rds", region_name=self.settings_dict["OPTIONS"].get("region", "eu-west-1"))
        params["password"] = client.generate_db_auth_token(
            DBHostname=params["host"], Port=int(params.get("port") or 5432), DBUsername=params["user"],
        )
        params.pop("region", None)
        return params
DATABASES = {
    "default": {
        "ENGINE": "myproject.db.rds_iam",
        "HOST": env("DB_HOST"), "PORT": "5432",
        "NAME": "appdb", "USER": "app",
        "CONN_MAX_AGE": 300,
        "CONN_HEALTH_CHECKS": True,
        "OPTIONS": {"sslmode": "verify-full", "sslrootcert": "/etc/ssl/rds/global-bundle.pem", "region": "eu-west-1"},
    }
}

generate_db_auth_token signs the request locally with the role's credentials; it does not call AWS, so it is fast. The token is valid for 15 minutes, but only for opening a connection; an open connection stays valid afterwards.

4. Require TLS

IAM authentication requires SSL. Download the RDS CA bundle into the image (global-bundle.pem from AWS) and use verify-full so the client also checks the server's identity.

5. Tune connection reuse

Generating a token is cheap, but creating connections has a cost and RDS limits the rate of new IAM-authenticated connections. Persistent connections (CONN_MAX_AGE of a few minutes) with health checks keep the connect rate low. RDS Proxy also supports IAM authentication from clients and pools connections, which helps with many workers or Lambda.

credential lifecycleStatic password✕long-lived, must be rotated✕shared by every process✕leaks in env dumps and logsIAM token✓expires after 15 minutes✓derived from the compute role✓access revoked by editing IAMRevoking access becomes an IAM change instead of a password rotationdjango-deployment.com
CloudTrail records who obtained database access through IAM.

Verification check: from the app environment, python manage.py dbshell -c "select current_user, ssl_is_used();" returns app and t; removing the policy from the role makes new connections fail with PAM authentication failed, and restoring it fixes them.

Explanation

With IAM authentication, RDS delegates the password check for users in the rds_iam role to AWS IAM. The client builds a presigned token (a SigV4 signature over the hostname, port, and user) with its current AWS credentials and sends it as the password over TLS. RDS validates the signature and the caller's rds-db:connect permission. Because the signature derives from short-lived role credentials, no stored secret exists to leak, and access follows IAM policy changes.

Edge cases / notes

  • Migrations can use the same IAM user if it owns the schema, or a separate admin user from Secrets Manager.
  • Local development can generate tokens with your own AWS credentials, or use a normal password-based local database.
  • Connection storms after deploys can hit IAM connection rate limits; stagger restarts or use RDS Proxy.
  • MySQL on RDS supports IAM auth too, with the same approach and the MySQL backend.

Next steps

FAQ

Can Django use RDS IAM authentication?

Yes, with a small custom backend that sets a fresh token as the password when connecting.

How long is an RDS IAM token valid?

Fifteen minutes for opening connections. Existing connections are not affected when it expires.

Does IAM auth require TLS?

Yes. Use sslmode=verify-full with the RDS CA bundle.

Does generating a token call AWS?

No. It is signed locally with the role's credentials, so it is fast.

Keep going