Skip to content

initial pass at how-to for rds-proxy #289

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 214 additions & 0 deletions docs/how-to/aws-rds-proxy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
# AWS RDS Proxy Role and Proxy Provisioning

This document describes the pattern we use to provision the `r-rds-proxy` IAM role and then create an Amazon RDS Proxy that uses that role.

The goal is to keep the setup simple and repeatable:

* the `r-rds-proxy` role is created in Terraform
* the SC-DBA SSO permission set is allowed to assume that role
* the RDS Proxy is created with the role ARN and the correct network and authentication settings

## Related Documents

* [How To Documents](../README.md)
* [AWS Identity Center (SSO)](../aws-sso/README.md)
* [sc-dba permission set](../../../../infrastructure/global/sso/permissionsets/sc-dba/sc-dba.permissionset.tf)
* [Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html)
* [Getting started with RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-setup.html)
* [Configuring IAM authentication for RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-iam-setup.html)
* [Creating a proxy for Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-creating.html)
* [Setting up database credentials for RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-secrets-arns.html)
* [Create a role to delegate permissions to an AWS service](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-service.html)

## Overview

RDS Proxy sits between your application and your database and manages connection pooling, failover handling, and authentication behavior.

In this repo, the operational pattern is:

1. create an IAM role named `r-rds-proxy`
1. attach the permissions required for the proxy workflow
1. allow the `AWSReservedSSO_sc-dba*` role to assume it
1. create the proxy and point it at that role

The current `sc-dba` permission set already includes the permission required for SSO users to assume the role. See [sc-dba.permissionset.tf](../../../../infrastructure/global/sso/permissionsets/sc-dba/sc-dba.permissionset.tf).

## Prerequisites

Before provisioning the role or proxy, make sure you have:

* access to the Terraform workspace that owns the account and region
* SC-DBA access through AWS Identity Center
* the database target already provisioned or at least planned
* network prerequisites in place, including VPC subnets and security groups for the proxy
* a decision about how the proxy authenticates to the database:
* Secrets Manager credentials
* IAM authentication
* a mixed model, where the proxy uses a secret and the application uses IAM

For AWS guidance on prerequisites, see [Getting started with RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-setup.html).

## Create The Role

The simplest way to provision the role is to keep it in Terraform and let the same stack manage both the trust policy and the inline permissions.

The existing pattern uses two trust principals:

* `rds.amazonaws.com`, so the RDS service can assume the role when the proxy needs it
* the SC-DBA Identity Center role, so operators can assume the same role when they administer the proxy and related resources

An example trust policy looks like this:

```hcl
data "aws_iam_policy_document" "assume" {
statement {
sid = "STSAssumeRole"
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["rds.amazonaws.com"]
}
}
statement {
sid = "STSAssumeRoleScDbaSSO"
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "AWS"
identifiers = [one(data.aws_iam_roles.sc_dba_sso.arns)]
}
}
}
```

The role should also have the inline policy bundle it needs for database work. In the current pattern that bundle is `sc-dba-combined`, which combines the database permissions and the Secrets Manager permissions.

If you are creating the role with the same module pattern used elsewhere in the repo, the shape is:

```hcl
module "rds-proxy" {
source = "git@github.e.it.census.gov:terraform-modules/aws-iam-role.git?ref=tf-upgrade"
role_name = "rds-proxy"
assume_policy_document = data.aws_iam_policy_document.assume.json
inline_policies = [{
name = "sc-dba-combined"
policy = data.aws_iam_policy_document.sc-dba-combined.json
}]
}
```

### What To Put In The Role Policy

The policy attached to the role should be as narrow as possible for your use case.

For this repository’s current `sc-dba` pattern, the policy includes access for:

* KMS alias lookup and KMS key use for RDS and Secrets Manager
* RDS and Performance Insights read and connect operations
* Secrets Manager secret management operations
* CloudWatch, CloudWatch Logs, CloudTrail, Config, and related operational visibility

If your deployment only needs a subset of those permissions, split them into smaller policies rather than widening the role further.

## Allow SSO Users To Assume The Role

The `sc-dba` permission set must explicitly allow `sts:AssumeRole` on the `r-rds-proxy` role.

That permission already exists in [sc-dba.permissionset.tf](../../../../infrastructure/global/sso/permissionsets/sc-dba/sc-dba.permissionset.tf). The important part is the IAM resource ARN and the organization guard:

```hcl
statement {
sid = "STSAssumeRoleRDSProxy"
actions = ["sts:AssumeRole"]
effect = "Allow"
resources = [format("arn:%v:%v:%v:%v:%v", data.aws_arn.current.partition, "iam", "", "*", "role/r-rds-proxy")]
condition {
test = "StringEquals"
variable = "aws:PrincipalOrgID"
values = [data.aws_organizations_organization.org.id]
}
}
```

This keeps the role assumable only within the organization and only for the explicitly named role.

## Create The RDS Proxy

Once the role exists, create the proxy and pass the role ARN into the proxy resource.

At a minimum, you need to define:

* the proxy name
* the target engine family
* the IAM role ARN
* the VPC subnet IDs
* the VPC security group IDs
* the authentication mode for the database backend
* whether TLS is required

AWS documents the full setup flow in [Creating a proxy for Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-creating.html).

### Authentication Choices

Use the path that matches your database and security model:

* **Secrets Manager authentication** if the proxy should use stored database credentials
* **IAM authentication** if you want the proxy and database path to use IAM-based auth
* **mixed or phased setups** if you are migrating from one model to another

If you are using IAM authentication, review [Configuring IAM authentication for RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-iam-setup.html).

If you are using Secrets Manager, review [Setting up database credentials for RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-secrets-arns.html).

### Terraform Example Shape

The exact resource arguments vary by engine and by whether you are using secrets or IAM auth, but the important part is always the same: the proxy receives the role ARN created above.

```hcl
resource "aws_db_proxy" "rds_proxy" {
name = "rds-proxy"
engine_family = "POSTGRESQL"
role_arn = aws_iam_role.rds_proxy.arn
vpc_subnet_ids = var.proxy_subnet_ids
vpc_security_group_ids = [aws_security_group.rds_proxy.id]
require_tls = true
}
```

When you use Secrets Manager or IAM auth, attach the corresponding `auth` configuration and secret ARN(s) according to the AWS provider documentation and the AWS RDS Proxy guide.

## Validation

After provisioning, verify the following:

* the IAM role exists with the expected trust policy
* the `sc-dba` permission set can assume the role
* the proxy is created in the intended region and VPC
* the proxy can reach the database target subnets and security groups
* the proxy shows as available in the RDS console or via the AWS CLI

Useful checks:

```console
aws iam get-role --role-name r-rds-proxy
aws rds describe-db-proxies
aws sts assume-role --role-arn <role-arn> --role-session-name rds-proxy-check
```

If the proxy cannot connect, check the trust policy, the secret/KMS permissions, the DB security group rules, and any IAM auth settings on the database side.

## References

* [Amazon RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy.html)
* [Getting started with RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-setup.html)
* [Configuring IAM authentication for RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-iam-setup.html)
* [Creating a proxy for Amazon RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-creating.html)
* [Setting up database credentials for RDS Proxy](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/rds-proxy-secrets-arns.html)
* [IAM role delegation for AWS services](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-service.html)

# CHANGELOG

* 1.0.0 -- 2026-07-02
- initial version