AWS RDS
Setup guide for the Common Fate AWS RDS integration.
Common Fate’s AWS RDS integration allows your end users to request Just-In-Time (JIT) access to RDS databases, leveraging AWS SSM to connect via the Common Fate AWS Proxy service deployed to ECS in your account. The proxy service captures audit logs of all SQL commands executed by the user during their session which can be viewed in real-time.
![](https://mintlify.s3-us-west-1.amazonaws.com/commonfate/images/rds/audit-logs-screenshot.png)
This guide will walk you through integrating Common Fate with AWS RDS. By the end of this guide, you’ll have a functioning integration with Common Fate with Databases available for access.
AWS RDS Overview
When a user requests access to a database in Common Fate, the provisioner creates a Permission Set in IAM Identity Center with the name set to the grant ID. This Permission Set is assigned to the user and the Account containing the Proxy. The Permission Set grants the user access to connect to the proxy using SSM StartSession for the AWS-StartPortForwardingSession document only.
The user then uses the Granted CLI granted rds proxy
to begin port-forwarding the database to their local machine.
![](https://mintlify.s3-us-west-1.amazonaws.com/commonfate/images/rds/infra.png)
Audit Logging Queries
The Common Fate RDS Proxy handles MySQL and Postgres connections at the wire protocol level. The proxy acts as a database server to the database client, and forwards commands to the target database after logging the queries to the session logs in Common Fate for the Grant.
![](https://mintlify.s3-us-west-1.amazonaws.com/commonfate/images/rds/connection-flow.png)
Deploying the Proxy
The proxy module is deployed into the account containing the target RDS instances. You will need to configure the network ingress from the proxy to your databases. In the below example we have shown how you can add aws_security_group_rule resources to permit this access.
To expose a database to Common Fate, you will configure each database and role using the databases configuration block. Some examples have been provided below for configuring a mysql and postgres database. The username field should match a user that exists in the database, you can consider creating a read only user in your database to limit the actions that can be taken while connected to the database.
data "aws_partition" "current" {}
data "aws_caller_identity" "current" {}
module "proxy" {
source = "common-fate/common-fate-proxy/ecs"
id = "<choose an id>"
aws_region = "us-west-2"
aws_account_id = data.aws_caller_identity.current.account_id
common_fate_aws_account_id = "12345678912" // the account where Common Fate is deployed
aws_partition = data.aws_partition.current.id
subnet_ids = [] // the proxy must be on a subnet with outbound internet access for AWS SSM to connect
vpc_id = "" // the VPC to deploy into
ecs_cluster_id = "" // the ECS Cluster to deploy into
ecs_cluster_name = "" // the ECS Cluster name
auth_issuer = module.common-fate-deployment.outputs.auth_issuer // fetch this from your Common Fate deployment
proxy_service_client_id = module.common-fate-deployment.outputs.provisioner_client_id // fetch this from your Common Fate deployment
proxy_service_client_secret = module.common-fate-deployment.provisioner_client_secret // fetch this from your Common Fate deployment
app_url = "https://commonfate.example.com" // Your Common Fate App url
databases = [{
instance_id = "example-mysql-db"
name = "Demo MySQL Database"
endpoint = aws_db_instance.mysql_db.endpoint
database = aws_db_instance.mysql_db.db_name
engine = aws_db_instance.mysql_db.engine
users = [{
name = "Root"
username = aws_db_instance.mysql_db.username
passwordSecretsManagerARN = aws_db_instance.mysql_db.master_user_secret[0].secret_arn
}]
},
{
instance_id = "example-postgres-db"
name = "Demo Postgres Database"
endpoint = "example-postgres-db.abcdef1234.us-west-2.rds.amazonaws.com:5432"
database = "postgres"
engine = "postgres"
users = [{
name = "Root"
username = "postgres"
passwordSecretsManagerARN = "arn:aws:secretsmanager:us-west-2:12345678912:secret:rds!db-1234-5678-9101112"
}, {
name = "Read Only"
username = "read_only"
passwordSecretsManagerARN = "arn:aws:secretsmanager:us-west-2:12345678912:secret:postgres-readonly-abcdefg"
}]
}]
}
// You will need to configure network access from the proxy to the database
// this example shows how to add a security group rule permitting the proxy security group to access the database on the database port
resource "aws_security_group_rule" "mysql_access_from_proxy" {
type = "ingress"
from_port = 3306
to_port = 3306
protocol = "tcp"
security_group_id = "sg-12345678912" // database security group id
source_security_group_id = module.proxy.security_group_id
}
resource "aws_security_group_rule" "postgres_access_from_proxy" {
type = "ingress"
from_port = 5432
to_port = 5432
protocol = "tcp"
security_group_id = "sg-12345678912" // database security group id
source_security_group_id = module.proxy.security_group_id
provider = aws.infra-region
}
Configuring Common Fate
In this section, you will add selectors and availabilities so that users can request access to the databases. You’ll need to have set up the Common Fate Application Configuration repository using our Terraform provider.
Inside your Application Configuration repository, update the following module:
resource "commonfate_webhook_provisioner" "aws" {
url = "http://common-fate-prod-builtin-provisioner.common-fate-prod-builtin.internal:9999"
capabilities = [
{
target_type = "AWS::RDS::Database"
role_type = "AWS::RDS::DatabaseUser"
belonging_to = {
type = "AWS::Organization"
id = "<Your AWS Organization ID>"
}
},
]
}
You can now create an access workflow and availabilities:
resource "commonfate_access_workflow" "rds" {
name = "RDS"
access_duration_seconds = 60
priority = 1
}
resource "commonfate_aws_rds_database_availabilities" "mysql" {
workflow_id = commonfate_access_workflow.rds.id
aws_rds_database_selector_id = commonfate_aws_rds_database_selector.mysql.id
// you can find the user id in the Common Fate console on the resources page
aws_rds_database_user_id = "test@arn:aws:rds:us-west-2:12345678912:db:example-mysql-db/test"
aws_identity_store_id = local.identity_store_id
}
resource "commonfate_aws_rds_database_availabilities" "postgres" {
workflow_id = commonfate_access_workflow.rds.id
aws_rds_database_selector_id = commonfate_aws_rds_database_selector.postgres.id
aws_rds_database_user_id = "postgres@arn:aws:rds:us-west-2:12345678912:db:example-postgres-db/postgres"
aws_identity_store_id = local.identity_store_id
}
resource "commonfate_aws_rds_database_availabilities" "postgres_read_only" {
workflow_id = commonfate_access_workflow.rds.id
aws_rds_database_selector_id = commonfate_aws_rds_database_selector.postgres.id
aws_rds_database_user_id = "read_only@arn:aws:rds:us-west-2:12345678912:db:example-postgres-db/postgres"
aws_identity_store_id = local.identity_store_id
}
AWS RDS database selectors
To make AWS RDS databases available for Just-In-Time (JIT) access you can add a commonfate_aws_rds_database_selector
Selector resource to your Common Fate application Terraform code. As shown below, the when
clause in the resource is a Cedar expression. You can use any Cedar operator in the when
clause, such as &&
and ||
to combine conditions.
You’ll need to use the commonfate_aws_rds_database_selector
in conjunction with a commonfate_aws_rds_database_availabilities
and commonfate_access_workflow
resources, as shown above.
We’ve included some examples below.
Select a database by Engine
resource "commonfate_aws_rds_database_selector" "mysql" {
id = "mysql"
name = "MySQL"
aws_organization_id = local.aws_organization_id
when = <<EOT
resource.engine == "mysql"
EOT
}
resource "commonfate_aws_rds_database_selector" "postgres" {
id = "postgres"
name = "Postgres"
aws_organization_id = local.aws_organization_id
when = <<EOT
resource.engine == "postgres"
EOT
}
Select a database by ID
resource "commonfate_aws_rds_database_selector" "mysql" {
id = "mysql"
name = "MySQL"
aws_organization_id = local.aws_organization_id
when = <<EOT
resource == AWS::RDS::Database::"example-mysql-db"
EOT
}
Select multiple databases by ID
resource "commonfate_aws_rds_database_selector" "example" {
id = "example"
name = "Example"
aws_organization_id = "<Your AWS Organization ID>"
when = <<EOT
resource == AWS::RDS::Database::"example-instance-identifier" || AWS::RDS::Database::"another-example-instance-identifier"
EOT
}
Select a database based on a naming pattern
Select databases with an instance_id ending in -prod
:
resource "commonfate_aws_rds_database_selector" "example" {
id = "example"
name = "Example"
aws_organization_id = "<Your AWS Organization ID>"
when = <<EOT
resource.instance_id like "*-prod"
EOT
}
Select databases with a name beginning with Develop
:
resource "commonfate_aws_rds_database_selector" "example" {
id = "example"
name = "Example"
aws_organization_id = "<Your AWS Organization ID>"
when = <<EOT
resource.name like "Develop*"
EOT
}
Select databases belonging to a particular Organizational Unit (OU)
resource "commonfate_aws_rds_database_selector" "example" {
id = "example"
name = "Example"
aws_organization_id = "<Your AWS Organization ID>"
when = <<EOT
resource in AWS::OrgUnit::"ou-123abc"
EOT
}
Connecting to a Database
Users connect to a database using Granted CLI.
Select a database
Some database requests may require approval, you can use the --wait
flag and
the CLI will wait for your request to be approved, then start the proxy.
❯ granted rds proxy
Select a database to connect to
Database Role
> Demo MySQL Database Root
Demo Postgres Database Read Only
Demo Postgres Database Root
Connect your database client
The CLI will provide the connection information, these are stable between grants for the same database and role.
If you need to run the portforward on an different port, use the flag
--port=1234
[i] Database proxy ready for connections on 127.0.0.1:5432
[i] You can connect now using this connection string: postgresql://read_only:password@127.0.0.1:5432/postgres?sslmode=disable
[i] Or using the postgres cli: psql "postgresql://read_only:password@127.0.0.1:5432/postgres?sslmode=disable"