Skip to content

Commit

Permalink
Merge pull request #20 from kunduso/add-rds-db-instance
Browse files Browse the repository at this point in the history
Add rds db instance
  • Loading branch information
kunduso authored Sep 18, 2024
2 parents cfeacff + 15868f9 commit 9e33855
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 48 deletions.
31 changes: 29 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
[![License: Unlicense](https://img.shields.io/badge/license-Unlicense-white.svg)](https://choosealicense.com/licenses/unlicense/) [![GitHub pull-requests closed](https://img.shields.io/github/issues-pr-closed/kunduso/rds-secretsmanager-rotation-lambda-terraform)](https://GitHub.com/kunduso/rds-secretsmanager-rotation-lambda-terraform/pull/) [![GitHub pull-requests](https://img.shields.io/github/issues-pr/kunduso/rds-secretsmanager-rotation-lambda-terraform)](https://GitHub.com/kunduso/rds-secretsmanager-rotation-lambda-terraform/pull/)
[![GitHub issues-closed](https://img.shields.io/github/issues-closed/kunduso/rds-secretsmanager-rotation-lambda-terraform)](https://github.com/kunduso/rds-secretsmanager-rotation-lambda-terraform/issues?q=is%3Aissue+is%3Aclosed) [![GitHub issues](https://img.shields.io/github/issues/kunduso/rds-secretsmanager-rotation-lambda-terraform)](https://GitHub.com/kunduso/rds-secretsmanager-rotation-lambda-terraform/issues/)
# terraform-rds-secretsmanager-rotation-lambda
[![GitHub issues-closed](https://img.shields.io/github/issues-closed/kunduso/rds-secretsmanager-rotation-lambda-terraform)](https://github.com/kunduso/rds-secretsmanager-rotation-lambda-terraform/issues?q=is%3Aissue+is%3Aclosed) [![GitHub issues](https://img.shields.io/github/issues/kunduso/rds-secretsmanager-rotation-lambda-terraform)](https://GitHub.com/kunduso/rds-secretsmanager-rotation-lambda-terraform/issues/) [![terraform-infra-provisioning](https://github.com/kunduso/rds-secretsmanager-rotation-lambda-terraform/actions/workflows/terraform.yml/badge.svg?branch=main)](https://github.com/kunduso/rds-secretsmanager-rotation-lambda-terraform/actions/workflows/terraform.yml) [![checkov-static-analysis-scan](https://github.com/kunduso/rds-secretsmanager-rotation-lambda-terraform/actions/workflows/code-scan.yml/badge.svg?branch=main)](https://github.com/kunduso/rds-secretsmanager-rotation-lambda-terraform/actions/workflows/code-scan.yml)
![Image](https://skdevops.files.wordpress.com/2024/09/101-image-0.png)
## Introduction
This repository contains the necessary Terraform configurations to deploy an Amazon RDS for PostgreSQL and all the supporting infrastructure components like Amazon VPC, Subnets, KMS keys, security group and IAM roles. Please refer to [Create Amazon RDS for PostgreSQL DB using Terraform and GitHub Actions](https://skundunotes.com/2024/09/18/create-amazon-rds-for-postgresql-db-using-terraform-and-github-actions/) for details.

The repository utilizes **Bridgecrew Checkov** to scan the Terraform code for security vulnerabilities. For those interested in adding code scanning capabilities to their GitHub Actions pipeline, a guide is available at [Automate Terraform Configuration Scan with Checkov and GitHub Actions](https://skundunotes.com/2023/04/12/automate-terraform-configuration-scan-with-checkov-and-github-actions/).

Infracost is employed to generate a cost estimate for building the architecture. To learn more about integrating Infracost estimates into a repository, refer to the note [Estimate AWS Cloud Resource Cost with Infracost, Terraform, and GitHub Actions](https://skundunotes.com/2023/07/17/estimate-aws-cloud-resource-cost-with-infracost-terraform-and-github-actions/).

The provisioning process of the resources is automated using a GitHub Actions pipeline. Detailed information on this can be found in the note [CI/CD with Terraform and GitHub Actions to Deploy to AWS](https://skundunotes.com/2023/03/07/ci-cd-with-terraform-and-github-actions-to-deploy-to-aws/).


## Prerequisites
To ensure the code functions without errors, an OpenID Connect identity provider must be created in Amazon Identity and Access Management (IAM) with a trust relationship established with the GitHub repository. A detailed explanation with steps can be found [here.](https://skundunotes.com/2023/02/28/securely-integrate-aws-credentials-with-github-actions-using-openid-connect/)

The `ARN` of the `IAM Role` is stored as a GitHub secret, which is referenced in the [`terraform.yml`](.github/workflows/terraform.yml) file.

Additionally, since Infracost is used in this repository, the `INFRACOST_API_KEY` is also stored as a repository secret and is referenced in the GitHub Actions workflow file. The cost estimate process is managed using a GitHub Actions variable, `INFRACOST_SCAN_TYPE`, where the value is either `hcl_code` or `tf_plan`, depending on the type of scan desired.
<br />You can read about that at [Integrate Infracost with GitHub Actions.](http://skundunotes.com/2023/07/17/estimate-aws-cloud-resource-cost-with-infracost-terraform-and-github-actions/)
## Usage
Ensure that the policy attached to the IAM role whose credentials are being used in this configuration has permission to create and manage all the AWS Cloud resources that are included in this repository.

If you want to check the pipeline logs, click on the **Build Badges** above the image in this ReadMe.

## Contributing
If you find any issues or have suggestions for improvement, feel free to open an issue or submit a pull request. Contributions are always welcome!

## License
This code is released under the Unlicense License. See [LICENSE](LICENSE).
106 changes: 100 additions & 6 deletions kms.tf
Original file line number Diff line number Diff line change
@@ -1,12 +1,106 @@
#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key
resource "aws_kms_key" "encryption_secret" {
resource "aws_kms_key" "encryption_rds" {
enable_key_rotation = true
description = "Key to encrypt secret"
description = "Key to encrypt the ${var.name} resources."
deletion_window_in_days = 7
#checkov:skip=CKV2_AWS_64: Not including a KMS Key policy
}
#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias
resource "aws_kms_alias" "encryption_secret" {
name = "alias/${var.name}"
target_key_id = aws_kms_key.encryption_secret.key_id
resource "aws_kms_alias" "encryption_rds" {
name = "alias/${var.name}-kms"
target_key_id = aws_kms_key.encryption_rds.key_id
}
data "aws_iam_policy_document" "encryption_rds_policy" {
statement {
sid = "Enable IAM User Permissions"
effect = "Allow"
principals {
type = "AWS"
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
}
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey",
"kms:Create*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion",
"kms:TagResource",
"kms:UntagResource"
]
resources = [aws_kms_key.encryption_rds.arn]
}
statement {
sid = "Allow RDS to use the key"
effect = "Allow"
principals {
type = "Service"
identifiers = ["rds.amazonaws.com"]
}
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey",
"kms:CreateGrant"
]
resources = [aws_kms_key.encryption_rds.arn]
}
statement {
sid = "Allow Secrets Manager to use the key"
effect = "Allow"
principals {
type = "Service"
identifiers = ["secretsmanager.amazonaws.com"]
}
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey",
"kms:CreateGrant"
]
resources = [aws_kms_key.encryption_rds.arn]
}
statement {
sid = "Allow SSM to use the key"
effect = "Allow"
principals {
type = "Service"
identifiers = ["ssm.amazonaws.com"]
}
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
]
resources = [aws_kms_key.encryption_rds.arn]
condition {
test = "StringEquals"
variable = "kms:CallerAccount"
values = [data.aws_caller_identity.current.account_id]
}
condition {
test = "StringEquals"
variable = "kms:ViaService"
values = ["ssm.${var.region}.amazonaws.com"]
}
}
}
resource "aws_kms_key_policy" "encryption_rds" {
key_id = aws_kms_key.encryption_rds.id
policy = data.aws_iam_policy_document.encryption_rds_policy.json
}
1 change: 0 additions & 1 deletion network.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc
resource "aws_vpc" "this" {
#checkov:skip=CKV2_AWS_11: This is non prod and hence disabled.
Expand Down
72 changes: 43 additions & 29 deletions rds.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,52 @@ resource "aws_db_subnet_group" "rds" {
resource "aws_db_parameter_group" "postgres" {
name = var.name
family = "postgres16"
parameter {
name = "log_statement"
value = "all"
}
parameter {
name = "log_min_duration_statement"
value = "1"
}
parameter {
name = "rds.force_ssl"
value = "1"
}
}
#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance
resource "aws_db_instance" "postgresql" {
allocated_storage = 100
storage_type = "gp3"
engine = "postgres"
engine_version = "16.3"
instance_class = "db.t3.large"
identifier = var.name
username = "postgres"
# password = aws_secretsmanager_secret_version.secure_one_version.secret_string
skip_final_snapshot = true # Change to false if you want a final snapshot
db_subnet_group_name = aws_db_subnet_group.rds.id
storage_encrypted = true
parameter_group_name = aws_db_parameter_group.postgres.name
multi_az = true
vpc_security_group_ids = [aws_security_group.rds.id]
allocated_storage = 100
storage_type = "gp3"
engine = "postgres"
engine_version = "16.3"
instance_class = "db.t3.large"
identifier = var.name
username = "postgres"
skip_final_snapshot = true # Change to false if you want a final snapshot
db_subnet_group_name = aws_db_subnet_group.rds.id
storage_encrypted = true
parameter_group_name = aws_db_parameter_group.postgres.name
multi_az = true
vpc_security_group_ids = [aws_security_group.rds.id]
iam_database_authentication_enabled = true
#checkov: CKV_AWS_161: "Ensure RDS database has IAM authentication enabled"
auto_minor_version_upgrade = true
#checkov: Check: CKV_AWS_226: "Ensure DB instance gets all minor upgrades automatically"
#checkov: CKV_AWS_226: "Ensure DB instance gets all minor upgrades automatically"
enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"]
# CKV_AWS_129: "Ensure that respective logs of Amazon Relational Database Service (Amazon RDS) are enabled"
#monitoring_interval = 5
# CKV_AWS_118: "Ensure that enhanced monitoring is enabled for Amazon RDS instances"
deletion_protection = false
#CKV_AWS_293: "Ensure that AWS database instances have deletion protection enabled"
copy_tags_to_snapshot = true
performance_insights_enabled = true
manage_master_user_password = true
master_user_secret_kms_key_id = aws_kms_key.encryption_secret.arn
# master_user_secret_kms_key_id = aws_kms_key.example.arn
# kms_key_id = aws_kms_key.example.arn
# performance_insights_kms_key_id = aws_kms_key.example.arn
ca_cert_identifier = "rds-ca-rsa2048-g1"
apply_immediately = true
#checkov: CKV_AWS_129: "Ensure that respective logs of Amazon Relational Database Service (Amazon RDS) are enabled"
monitoring_interval = 10
monitoring_role_arn = aws_iam_role.rds_monitoring_role.arn
#checkov: CKV_AWS_118: "Ensure that enhanced monitoring is enabled for Amazon RDS instances"
deletion_protection = true
#checkov: CKV_AWS_293: "Ensure that AWS database instances have deletion protection enabled"
copy_tags_to_snapshot = true
manage_master_user_password = true
master_user_secret_kms_key_id = aws_kms_key.encryption_rds.arn
kms_key_id = aws_kms_key.encryption_rds.arn
performance_insights_enabled = true
performance_insights_retention_period = 31
performance_insights_kms_key_id = aws_kms_key.encryption_rds.arn
ca_cert_identifier = "rds-ca-rsa2048-g1"
apply_immediately = true
}
22 changes: 22 additions & 0 deletions rds_iam_role.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
##https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role
resource "aws_iam_role" "rds_monitoring_role" {
name = "${var.name}-rds-monitoring-role"

assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Effect = "Allow",
Principal = {
Service = "monitoring.rds.amazonaws.com"
}
}
]
})
}
#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment
resource "aws_iam_role_policy_attachment" "managed_rds_monitoring_policy_attachement" {
role = aws_iam_role.rds_monitoring_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
}
4 changes: 1 addition & 3 deletions security_group.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ resource "aws_security_group" "rds" {
description = "Security group for RDS in ${var.name}"
vpc_id = aws_vpc.this.id
tags = {
"Name" = "${var.name}-sg"
"Name" = "${var.name}-rds-sg"
}
# checkov:skip=CKV2_AWS_5: "Ensure that Security Groups are attached to another resource"
# This security group is attached to the Amazon ElastiCache Serverless resource
}
#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule
resource "aws_security_group_rule" "ingress_rds_sg" {
Expand Down
26 changes: 19 additions & 7 deletions ssm_parameter.tf
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter
resource "aws_ssm_parameter" "rds_secret_arn" {
name = "/${var.name}/rds-password-arn"
type = "SecureString"
value = aws_db_instance.postgresql.master_user_secret[0].secret_arn
resource "aws_ssm_parameter" "rds_connection" {
name = "/${var.name}/rds-connection"
type = "SecureString"
key_id = aws_kms_key.encryption_rds.id
value = jsonencode({
rds_endpoint = split(":", aws_db_instance.postgresql.endpoint)[0],
rds_port = split(":", aws_db_instance.postgresql.endpoint)[1],
secret_arn = aws_db_instance.postgresql.master_user_secret[0].secret_arn
})
}
#Create a policy to read from the specific parameter store
#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy
resource "aws_iam_policy" "ssm_parameter_policy" {
name = "${var.name}-ssm-parameter-read-policy"
name = "${var.name}-rds-connection-read-policy"
path = "/"
description = "Policy to read the RDS Password ARN stored in the SSM Parameter Store."
description = "Policy to read the RDS Endpoint and Password ARN stored in the SSM Parameter Store."
# Terraform's "jsonencode" function converts a
# Terraform expression result to valid JSON syntax.
policy = jsonencode({
Expand All @@ -21,7 +26,14 @@ resource "aws_iam_policy" "ssm_parameter_policy" {
"ssm:GetParameters",
"ssm:GetParameter"
],
Resource = [aws_ssm_parameter.rds_secret_arn.arn]
Resource = [aws_ssm_parameter.rds_connection.arn]
},
{
Effect = "Allow",
Action = [
"kms:Decrypt"
],
Resource = [aws_kms_key.encryption_rds.id]
}
]
})
Expand Down

0 comments on commit 9e33855

Please sign in to comment.