Let me help you systematically troubleshoot this IAM database authentication issue. The problem involves three key areas: IAM role configuration, RDS IAM auth setup, and proper policy attachment to the execution context.
IAM Role and Policy Verification:
Your policy syntax looks correct, but let’s verify the complete setup:
- Check the IAM Role Trust Relationship:
The role must allow EC2 service to assume it:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}
- Verify Instance Profile Attachment:
The IAM role must be attached to EC2 via instance profile:
aws ec2 describe-instances --instance-ids i-xxxxx \
--query 'Reservations[0].Instances[0].IamInstanceProfile'
If this returns null, the role isn’t attached. Attach it:
aws ec2 associate-iam-instance-profile \
--instance-id i-xxxxx \
--iam-instance-profile Name=your-instance-profile
- Validate Policy Resource ARN:
The format is critical. Use this command to get the exact DBI resource ID:
aws rds describe-db-instances \
--db-instance-identifier your-db-name \
--query 'DBInstances[0].DbiResourceId'
Your policy resource should be:
arn:aws:rds-db:us-east-1:123456789012:dbuser:db-ABCD1234EFGH5678/iamuser
Note: Account ID should be 12 digits, and DBI resource ID format is db-XXXXX (mix of letters/numbers).
RDS IAM Authentication Setup:
- Database User Configuration (PostgreSQL):
Connect to the database as master user and verify:
-- Check if user exists and has rds_iam role
SELECT r.rolname, r.rolcanlogin,
ARRAY(SELECT b.rolname FROM pg_roles b
WHERE pg_has_role(r.oid, b.oid, 'member')) as memberof
FROM pg_roles r
WHERE r.rolname = 'iamuser';
The output should show iamuser with rds_iam in the memberof array. If not:
CREATE USER iamuser WITH LOGIN;
GRANT rds_iam TO iamuser;
GRANT CONNECT ON DATABASE your_database TO iamuser;
GRANT USAGE ON SCHEMA public TO iamuser;
-- Add additional grants as needed
Application Auth Token Generation:
- Verify Token Generation Code:
For Python/boto3:
import boto3
client = boto3.client('rds')
token = client.generate_db_auth_token(
DBHostname='your-db.xxx.us-east-1.rds.amazonaws.com',
Port=5432,
DBUsername='iamuser',
Region='us-east-1'
)
Critical points:
- Use the RDS endpoint hostname, not IP address
- Port must match RDS instance port (5432 for PostgreSQL)
- Username must exactly match database user (‘iamuser’)
- Region must match RDS instance region
- Connection String Format:
For PostgreSQL with psycopg2:
import psycopg2
conn = psycopg2.connect(
host='your-db.xxx.us-east-1.rds.amazonaws.com',
port=5432,
database='your_database',
user='iamuser',
password=token,
sslmode='require',
sslrootcert='rds-ca-2019-root.pem'
)
Critical Requirements:
- SSL must be enabled (sslmode=‘require’)
- Token is used as password parameter
- Token expires after 15 minutes - generate new token for each connection
- Download RDS SSL certificate from AWS and specify path
Common Issues and Solutions:
A. Token Expiration: Auth tokens are valid for 15 minutes. If your app caches connections longer, regenerate tokens.
B. Security Group: Ensure EC2 instance can reach RDS on port 5432. Security group on RDS must allow inbound from EC2’s security group.
C. Subnet Routing: EC2 and RDS should be in same VPC or have proper routing configured.
D. CloudTrail Verification: Check if IAM role is being assumed correctly:
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceName,AttributeValue=your-role-name \
--max-results 10
Testing Procedure:
- SSH to EC2 instance
- Verify IAM role credentials are available:
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
- Generate token using AWS CLI:
aws rds generate-db-auth-token \
--hostname your-db.xxx.us-east-1.rds.amazonaws.com \
--port 5432 \
--username iamuser \
--region us-east-1
- Test connection with psql:
psql "host=your-db.xxx.us-east-1.rds.amazonaws.com port=5432 \
dbname=your_database user=iamuser password=$TOKEN sslmode=require"
If step 2 fails, the instance profile isn’t attached. If step 3 fails, IAM permissions are wrong. If step 4 fails with “password authentication failed”, the database user setup is incorrect.
Based on your description, most likely issues are:
- Instance profile not properly attached to EC2
- Token not being regenerated frequently enough
- SSL not properly configured in connection string
Verify these three areas and the connection should succeed.