Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AWS RDS configuration with PostgreSQL instance, security group #17

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,25 @@ uv.lock
local-test-data/*
dsst_etl.log
debug.log


# Local .terraform directories
**/.terraform/*

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log

# Exclude sensitive variables files
*.tfvars
*.tfvars.json

# Ignore override files
override.tf
override.tf.json
*_override.tf
*_override.tf.json
*lock.hcl
65 changes: 65 additions & 0 deletions terraform/modules/iam/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
terraform {
required_version = ">= 1.0.0, < 2.0.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

provider "aws" {
region = var.region
}

data "aws_iam_policy_document" "assume_role" {
statement {
effect = "Allow"

principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}

actions = ["sts:AssumeRole"]
}
}

resource "aws_iam_role" "profile" {
name = "${var.instance_profile_role_name}-${var.environment}"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}

resource "aws_iam_role_policy_attachment" "profile" {
role = aws_iam_role.profile.name
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
}

resource "aws_iam_instance_profile" "profile" {
name = "${var.instance_profile_name}-${var.environment}"
role = aws_iam_role.profile.name
}

resource "aws_iam_policy" "cd" {
name = "${var.cd_iam_policy_name}-dsst-${var.environment}"
policy = file("${path.module}/policies/gha-policy.json")
}

resource "aws_iam_role" "cd" {
name = "${var.cd_iam_role_policy_name}-dsst-${var.environment}"
assume_role_policy = templatefile("${path.module}/policies/assume-role.json.tftpl",
{
AWS_ACCOUNT_ID = var.AWS_ACCOUNT_ID
},
)
}

resource "aws_iam_role_policy_attachment" "cd" {
role = aws_iam_role.cd.name
policy_arn = aws_iam_policy.cd.arn
}

data "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
}
3 changes: 3 additions & 0 deletions terraform/modules/iam/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "instance_profile_name" {
value = aws_iam_instance_profile.profile.name
}
23 changes: 23 additions & 0 deletions terraform/modules/iam/policies/assume-role.json.tftpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": [
"repo:nimh-dsst/dsst-etl:*"
]
},
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
}
}
}
]
}

58 changes: 58 additions & 0 deletions terraform/modules/iam/policies/gha-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"rds:CreateDBInstance",
"rds:DeleteDBInstance",
"rds:ModifyDBInstance",
"rds:DescribeDBInstances",

"rds:CreateDBSnapshot",
"rds:DeleteDBSnapshot",
"rds:DescribeDBSnapshots",
"rds:RestoreDBInstanceFromDBSnapshot",
"rds:StartDBInstance",
"rds:StopDBInstance",

"rds:DescribeEvents",
"rds:DescribeDBLogFiles",
"rds:DownloadDBLogFilePortion",
"rds:DescribeDBInstanceAutomatedBackups",

"rds:AddRoleToDBInstance",
"rds:RemoveRoleFromDBInstance",
"rds:DescribeDBSecurityGroups",
"rds:AuthorizeDBSecurityGroupIngress",
"rds:RevokeDBSecurityGroupIngress",

"rds:DescribeDBParameterGroups",
"rds:ModifyDBParameterGroup",
"rds:DescribeDBClusterParameterGroups"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:PassRole",
"iam:GetRole",
"iam:CreateRole",
"iam:AttachRolePolicy",
"iam:DetachRolePolicy"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"rds:*",
"ec2:DescribeSecurityGroups",
"ec2:CreateSecurityGroup",
"ec2:DeleteSecurityGroup"
],
"Resource": "*"
}
]
}
40 changes: 40 additions & 0 deletions terraform/modules/iam/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
variable "environment" {
description = "The name of the environment. Usually `shared`, `stage`, or `prod`."
type = string
}

variable "region" {
description = "AWS region"
default = "us-east-1"
type = string
}

variable "instance_profile_name" {
description = "The name of the instance profile"
default = "dsst-etl-instance-profile"
type = string
}

variable "instance_profile_role_name" {
description = "The name of the instance profile"
default = "dsst-etl-instance-profile-role"
type = string
}

variable "cd_iam_policy_name" {
description = "The name of the IAM policy for continuous deployment to ECR"
default = "etl-github-actions-policy"
type = string
}

variable "cd_iam_role_policy_name" {
description = "The name of the IAM role policy for continuous deployment to ECR"
default = "etl-github-actions-role"
type = string
}

variable "AWS_ACCOUNT_ID" {
# All caps variable name because this is read in as an environment variable
description = "The ID of your AWS account. This should be set as an environment variable `TF_VAR_AWS_ACCOUNT_ID`."
type = string
}
35 changes: 35 additions & 0 deletions terraform/modules/networking/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
terraform {
required_version = ">= 1.0.0, < 2.0.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

provider "aws" {
region = var.region
}

# Use data source to reference existing VPC
data "aws_vpc" "selected" {
id = var.environment == "shared" ? "vpc-0da7e09c28aed91d4" : (
var.environment == "stage" ? "vpc-04e9bc794785725bd" : "vpc-08907c4cf973b8351"
)
}

# Get existing subnets in the VPC
data "aws_subnets" "existing" {
filter {
name = "vpc-id"
values = [data.aws_vpc.selected.id]
}
}

# Get existing security groups
data "aws_security_group" "default" {
vpc_id = data.aws_vpc.selected.id
name = "default"
}
14 changes: 14 additions & 0 deletions terraform/modules/networking/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
output "vpc_id" {
description = "ID of the VPC"
value = data.aws_vpc.selected.id
}

output "subnet_ids" {
description = "List of subnet IDs"
value = data.aws_subnets.existing.ids
}

output "default_security_group_id" {
description = "ID of the default security group"
value = data.aws_security_group.default.id
}
10 changes: 10 additions & 0 deletions terraform/modules/networking/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
variable "environment" {
description = "The name of the environment. Usually `shared`, `stage`, or `prod`."
type = string
}

variable "region" {
description = "AWS region"
default = "us-east-1"
type = string
}
72 changes: 72 additions & 0 deletions terraform/modules/state/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
terraform {
required_version = ">= 1.0.0, < 2.0.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

provider "aws" {
region = var.aws_region
}

resource "aws_s3_bucket" "tf_state" {
bucket = "${var.bucket_name}-${var.environment}"

tags = {
Name = "${var.bucket_name}-${var.environment}"
}
}

resource "aws_s3_bucket_lifecycle_configuration" "tf_state" {
bucket = aws_s3_bucket.tf_state.id
rule {
id = "tf_state_${var.environment}"
status = "Enabled"

transition {
days = 30
storage_class = "STANDARD_IA"
}

expiration {
days = 365
}
}
}

resource "aws_s3_bucket_versioning" "enabled" {
bucket = aws_s3_bucket.tf_state.id

versioning_configuration {
status = "Enabled"
}
}

resource "aws_s3_bucket_server_side_encryption_configuration" "default" {
bucket = aws_s3_bucket.tf_state.id

rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}

resource "aws_dynamodb_table" "tf_locks" {
name = "${var.table_name}-${var.environment}"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"

attribute {
name = "LockID"
type = "S"
}

tags = {
Name = "${var.bucket_name}-${var.environment}"
}
}
9 changes: 9 additions & 0 deletions terraform/modules/state/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
output "s3_bucket_arn" {
value = aws_s3_bucket.tf_state.arn
description = "The ARN of the S3 bucket"
}

output "dynamodb_table_name" {
value = aws_dynamodb_table.tf_locks.name
description = "The name of the DynamoDB table"
}
22 changes: 22 additions & 0 deletions terraform/modules/state/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
variable "bucket_name" {
description = "The name of the S3 bucket to store Terraform state. Must be globally unique."
type = string
default = "dsst-etl-terraform-state-storage"
}

variable "table_name" {
description = "The name of the DynamoDB table. Must be unique in this AWS account."
type = string
default = "dsst-etl-state-locks"
}

variable "aws_region" {
description = "The AWS region used by the deployment"
type = string
default = "us-east-1"
}

variable "environment" {
description = "The name of the development environment. Usually `stage` or `prod`."
type = string
}
Loading
Loading