Skip to content

Commit

Permalink
Use secret manager for db master password (#461)
Browse files Browse the repository at this point in the history
## Ticket

Resolves #286 

## Changes

- Adjust get_password to decode associated json
- Update param name

## Context for reviewers

Update for security

## Testing

Tested in
[platform-test](navapbc/platform-test#61)
  • Loading branch information
charles-nava authored Oct 6, 2023
1 parent 7bcfb4a commit fe5c7cd
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 27 deletions.
30 changes: 9 additions & 21 deletions infra/modules/database/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ resource "aws_rds_cluster" "db" {
# https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.CreateInstance.html
cluster_identifier = var.name

engine = "aurora-postgresql"
engine_mode = "provisioned"
database_name = var.database_name
port = var.port
master_username = local.master_username
master_password = aws_ssm_parameter.random_db_password.value
storage_encrypted = true
kms_key_id = aws_kms_key.db.arn
engine = "aurora-postgresql"
engine_mode = "provisioned"
database_name = var.database_name
port = var.port
master_username = local.master_username
manage_master_user_password = true
storage_encrypted = true
kms_key_id = aws_kms_key.db.arn

# checkov:skip=CKV_AWS_128:Auth decision needs to be ironed out
# checkov:skip=CKV_AWS_162:Auth decision needs to be ironed out
Expand Down Expand Up @@ -61,18 +61,6 @@ resource "aws_rds_cluster_instance" "primary" {
monitoring_interval = 30
}

resource "random_password" "random_db_password" {
length = 48
# Remove '@' sign from allowed characters since only printable ASCII characters besides '/', '@', '"', ' ' may be used.
override_special = "!#$%&*()-_=+[]{}<>:?"
}

resource "aws_ssm_parameter" "random_db_password" {
name = "/db/${var.name}/master-password"
type = "SecureString"
value = random_password.random_db_password.result
}

resource "aws_kms_key" "db" {
description = "Key for RDS cluster ${var.name}"
enable_key_rotation = true
Expand All @@ -83,7 +71,7 @@ resource "aws_kms_key" "db" {

resource "aws_rds_cluster_parameter_group" "rds_query_logging" {
name = var.name
family = "aurora-postgresql13"
family = "aurora-postgresql14"
description = "Default cluster parameter group"

parameter {
Expand Down
10 changes: 7 additions & 3 deletions infra/modules/database/role-manager.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ resource "aws_lambda_function" "role_manager" {
DB_PORT = aws_rds_cluster.db.port
DB_USER = local.master_username
DB_NAME = aws_rds_cluster.db.database_name
DB_PASSWORD_PARAM_NAME = aws_ssm_parameter.random_db_password.name
DB_PASSWORD_PARAM_NAME = "/aws/reference/secretsmanager/${data.aws_secretsmanager_secret.db_pass.name}"
DB_SCHEMA = var.schema_name
APP_USER = var.app_username
MIGRATOR_USER = var.migrator_username
Expand Down Expand Up @@ -94,6 +94,10 @@ resource "aws_iam_role" "role_manager" {
]
}

data "aws_secretsmanager_secret" "db_pass" {
arn = aws_rds_cluster.db.master_user_secret[0].secret_arn
}

resource "aws_iam_role_policy" "ssm_access" {
name = "${var.name}-role-manager-ssm-access"
role = aws_iam_role.role_manager.id
Expand All @@ -103,8 +107,8 @@ resource "aws_iam_role_policy" "ssm_access" {
Statement = [
{
Effect = "Allow"
Action = ["ssm:GetParameter*"]
Resource = "${aws_ssm_parameter.random_db_password.arn}"
Action = ["secretsmanager:GetSecretValue"]
Resource = [data.aws_secretsmanager_secret.db_pass.arn]
},
{
Effect = "Allow"
Expand Down
9 changes: 6 additions & 3 deletions infra/modules/database/role_manager/role_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
def lambda_handler(event, context):
if event == "check":
return check()
elif event == "password_ts":
connect_as_master_user()
return "Succeeded"
else:
return manage()

Expand Down Expand Up @@ -115,11 +118,11 @@ def get_password() -> str:
ssm = boto3.client("ssm")
param_name = os.environ["DB_PASSWORD_PARAM_NAME"]
logger.info("Fetching password from parameter store")
result = ssm.get_parameter(
result = json.loads(ssm.get_parameter(
Name=param_name,
WithDecryption=True,
)
return result["Parameter"]["Value"]
)["Parameter"]["Value"])
return result["password"]


def get_roles(conn: Connection) -> list[str]:
Expand Down

0 comments on commit fe5c7cd

Please sign in to comment.