From 7ad7182b5a99c16faa5533b98c50a9a887afcc6e Mon Sep 17 00:00:00 2001 From: Isaac T Date: Tue, 21 Oct 2025 22:29:20 -0400 Subject: [PATCH 1/7] feat(s3): configure private s3 bucket - add random provider for stable UUID - with encryption, lifecycle, and access block --- s3.tf | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 s3.tf diff --git a/s3.tf b/s3.tf new file mode 100644 index 0000000..4020f40 --- /dev/null +++ b/s3.tf @@ -0,0 +1,43 @@ +resource "aws_s3_bucket" "images" { + bucket = random_uuid() + force_destroy = true + bucket_prefix = var.name_prefix + + tags = { + Name = "${var.name_prefix}-s3" + Environment = var.profile + } +} + +resource "aws_s3_bucket_public_access_block" "images" { + bucket = aws_s3_bucket.images.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "images" { + bucket = aws_s3_bucket.images.id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_s3_bucket_lifecycle_configuration" "images" { + bucket = aws_s3_bucket.images.id + + rule { + id = "transition-standard-to-ia" + status = "Enabled" + + transition { + days = 30 + storage_class = "STANDARD_IA" + } + } +} From 87c4278b07bd69a3d2207ab6e72bdaa08960bde5 Mon Sep 17 00:00:00 2001 From: Isaac T Date: Wed, 22 Oct 2025 09:59:29 -0400 Subject: [PATCH 2/7] feat(terraform): provision PostgreSQL RDS instance - Create custom DB parameter group - Create DB subnet group from private subnets - Allow ingress from app_sg on 5432 - Outputs: endpoint and port" --- outputs.tf | 9 ++++++++ rds.tf | 53 +++++++++++++++++++++++++++++++++++++++++++++++ security-group.tf | 35 +++++++++++++++++++++++++++++-- variables.tf | 49 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 rds.tf diff --git a/outputs.tf b/outputs.tf index 9f0ee5f..d9133da 100644 --- a/outputs.tf +++ b/outputs.tf @@ -40,3 +40,12 @@ output "application_sg_id" { output "instance_id" { value = aws_instance.app.public_ip } + +output "rds_endpoint" { + description = "RDS endpoint hostname" + value = aws_db_instance.db.address +} + +output "rds_port" { + value = aws_db_instance.db.port +} diff --git a/rds.tf b/rds.tf new file mode 100644 index 0000000..5049f2a --- /dev/null +++ b/rds.tf @@ -0,0 +1,53 @@ +resource "aws_db_parameter_group" "postgres" { + name = "${var.name_prefix}-pg-param" + family = var.db_engine_family + description = "Custom parameter group for PostgreSQL ${var.db_engine_version}" + + parameter { + name = "log_min_duration_statement" + value = "500" + } +} + +resource "aws_db_subnet_group" "db_private" { + name = "${var.name_prefix}-db-subnet-group" + subnet_ids = [for s in aws_subnet.private : s.id] # multiple subnet (at least 2) + tags = { + Name = "${var.name_prefix}-db-subnet-group" + } +} + +# RDS Instance +resource "aws_db_instance" "db" { + identifier = "${var.name_prefix}-rds" + engine = "postgres" + engine_version = var.db_engine_version # e.g., "16.3" + instance_class = var.db_instance_class # e.g., "db.t3.micro" + allocated_storage = var.db_allocated_storage # e.g., 20 + storage_type = "gp3" + + db_name = var.db_name + username = var.db_username + password = var.db_password + + port = var.db_port # 5432 + multi_az = false + publicly_accessible = false + + vpc_security_group_ids = [aws_security_group.db_sg.id] + db_subnet_group_name = aws_db_subnet_group.db_private.name + parameter_group_name = aws_db_parameter_group.postgres.name + + skip_final_snapshot = true + + tags = { + Name = "${var.name_prefix}-rds-postgres" + Environment = var.profile + } + + depends_on = [ + aws_db_subnet_group.db_private, + aws_db_parameter_group.postgres, + aws_security_group.db_sg + ] +} diff --git a/security-group.tf b/security-group.tf index 1b52961..1ec2553 100644 --- a/security-group.tf +++ b/security-group.tf @@ -1,9 +1,12 @@ +#---------------------- +# Web App Security Group +#---------------------- resource "aws_security_group" "app_sg" { - name = "${var.name_prefix}-sg" + name = "${var.name_prefix}-app-sg" description = "Web App SG: 22,80,443,app open to world" vpc_id = aws_vpc.csye6225.id - tags = { Name = "${var.name_prefix}-sg" } + tags = { Name = "${var.name_prefix}-app-sg" } } locals { @@ -42,3 +45,31 @@ resource "aws_vpc_security_group_egress_rule" "all_out_ipv6" { cidr_ipv6 = "::/0" ip_protocol = "-1" } + +#---------------------- +# DB Security Group +#---------------------- +resource "aws_security_group" "db_sg" { + name = "${var.name_prefix}-db-sg" + description = "Database Security Group: only allow access from EC2 app_sg" + vpc_id = aws_vpc.csye6225.id + + tags = { Name = "${var.name_prefix}-db-sg" } +} + +# Allow inbound DB access from app_sg +resource "aws_vpc_security_group_ingress_rule" "db_ingress_app_sg" { + security_group_id = aws_security_group.db_sg.id # apply to what sg + referenced_security_group_id = aws_security_group.app_sg.id + from_port = var.db_port + to_port = var.db_port + ip_protocol = "tcp" + description = "Allow TCP ${each.value} from anywhere (IPv4)" +} + +# Allow outbound (for updates / AWS services) +resource "aws_vpc_security_group_egress_rule" "db_all_out_ipv4" { + security_group_id = aws_security_group.db_sg.id + cidr_ipv4 = "0.0.0.0/0" + ip_protocol = "-1" +} diff --git a/variables.tf b/variables.tf index e820903..6d46b42 100644 --- a/variables.tf +++ b/variables.tf @@ -74,6 +74,55 @@ variable "name_prefix" { default = "app" } +variable "db_port" { + description = "Database port number" + type = number + default = 5432 +} + +variable "db_name" { + description = "Initial database name to create inside RDS" + type = string + default = "csye6225_db" +} + +variable "db_username" { + description = "Master DB username" + type = string + default = "6225_user" +} + +variable "db_password" { + description = "Master password for RDS" + type = string + sensitive = true +} + +variable "db_instance_class" { + description = "RDS instance class" + type = string + default = "db.t3.micro" # or "db.t4g.micro" (ARM/Graviton) +} + +variable "db_allocated_storage" { + description = "Allocated storage in GB" + type = number + default = 20 +} + +# Control PG version & family +variable "db_engine_version" { + description = "PostgreSQL engine version" + type = string + default = "16.3" +} + +variable "db_engine_family" { + description = "Parameter group family for PostgreSQL" + type = string + default = "postgres16" +} + variable "tags" { description = "Common tags applied to all resources" type = map(string) From c5c49bf2e6b6e9f9b048865636f22de89b4bf3a6 Mon Sep 17 00:00:00 2001 From: Isaac T Date: Wed, 22 Oct 2025 21:04:52 -0400 Subject: [PATCH 3/7] feat(ec2): add user data script to inject RDS config - Write DB connection variables into .env on boot - Restart webapp service with updated RDS settings --- ec2.tf | 13 +++++++++++++ scripts/user_data.sh | 34 ++++++++++++++++++++++++++++++++++ variables.tf | 20 ++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 scripts/user_data.sh diff --git a/ec2.tf b/ec2.tf index 1207d2a..d34cc67 100644 --- a/ec2.tf +++ b/ec2.tf @@ -40,6 +40,19 @@ resource "aws_instance" "app" { # ensure a public IP if your subnet doesn't auto-assign associate_public_ip_address = var.subnet_tier == "public" ? true : false + user_data = templatefile("${path.module}/scripts/user_data.sh", { + app_user = var.app_user + app_group = var.app_group + app_dir = var.app_dir + service_name = var.service_name + + db_host = aws_db_instance.db.address + db_port = aws_db_instance.db.port + db_name = var.db_name + db_username = var.db_username + db_password = var.db_password + }) + tags = { Name = "${var.name_prefix}-ec2" Role = "webapp" diff --git a/scripts/user_data.sh b/scripts/user_data.sh new file mode 100644 index 0000000..14a4b55 --- /dev/null +++ b/scripts/user_data.sh @@ -0,0 +1,34 @@ +#!/bin/bash +set -euo pipefail + +APP_USER="${app_user}" +APP_GROUP="${app_group}" +APP_DIR="${app_dir}" +SERVICE_NAME="${service_name}" +ENV_FILE="$APP_DIR/.env" + +### ====== Configure log color ====== +log() { echo -e "\033[1;32m[OK]\033[0m $*"; } +info() { echo -e "\033[1;34m[INFO]\033[0m $*"; } +err() { echo -e "\033[1;31m[ERR]\033[0m $*" >&2; } + +info "=== Setting up environment for web app in $APP_DIR ===" + +mkdir -p "$APP_DIR" # make sure the directory exist + +cat >> "$ENV_FILE" < Date: Wed, 22 Oct 2025 21:08:16 -0400 Subject: [PATCH 4/7] feat(terraform): enable EC2 to securely access S3 via IAM role - Created IAM role and instance profile for EC2 - Defined trust policy allowing EC2 to assume the role - Added least-privilege S3 access policy (List/Get/Put/Delete on specific bucket) --- ec2.tf | 1 + iam_role.tf | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ variables.tf | 6 ++++ 3 files changed, 91 insertions(+) create mode 100644 iam_role.tf diff --git a/ec2.tf b/ec2.tf index d34cc67..83a67f5 100644 --- a/ec2.tf +++ b/ec2.tf @@ -23,6 +23,7 @@ resource "aws_instance" "app" { instance_type = var.instance_type subnet_id = local.chosen_subnet_id vpc_security_group_ids = [aws_security_group.app_sg.id] + iam_instance_profile = aws_iam_instance_profile.app_ec2_profile.name # assign ssh key key_name = var.key_name != "" ? var.key_name : null diff --git a/iam_role.tf b/iam_role.tf new file mode 100644 index 0000000..e2e9c61 --- /dev/null +++ b/iam_role.tf @@ -0,0 +1,84 @@ +resource "aws_iam_role" "app_ec2_role" { + name = "${var.name_prefix}-ec2-role" + + # Trust Policy + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = [{ + Effect = "Allow", + Principal = { Service = "ec2.amazonaws.com" }, # Who can assume this role. The 'Service' here represents the EC2 service itself. + Action = "sts:AssumeRole" + }] + }) +} +# Instance Profile is a container for the IAM Role. +# EC2 cannot directly attach an IAM Role — it must attach an Instance Profile instead. +# The profile allows EC2 to assume the role and get temporary credentials automatically. +resource "aws_iam_instance_profile" "app_ec2_profile" { + name = "${var.name_prefix}-ec2-profile" + role = aws_iam_role.app_ec2_role.name +} + +# ---------------------- +# Setup Least Privilage +# ---------------------- +locals { + # Retrieve the name and ARN of the S3 bucket created in Terraform. + bucket_name = aws_s3_bucket.images.bucket + bucket_arn = "arn:aws:s3:::${local.bucket_name}" + + # Define the object-level ARN (optionally scoped to a prefix). + objects_arn = "arn:aws:s3:::${local.bucket_name}/${var.s3_prefix}*" +} + +# Generate a least-privilege S3 access policy for the EC2 IAM Role. +data "aws_iam_policy_document" "s3_app_least" { + + # 1) Allow listing objects within the bucket. + statement { + sid = "ListBucket" + effect = "Allow" + actions = ["s3:ListBucket"] + resources = [local.bucket_arn] + + # If a prefix is specified, restrict the listing to that prefix only. + condition { + test = "StringLike" + variable = "s3:prefix" + values = [var.s3_prefix == "" ? "*" : "${var.s3_prefix}*"] + } + } + + # 2) Allow reading, uploading, and deleting objects. + statement { + sid = "ObjectRW" + effect = "Allow" + actions = ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"] + resources = [local.objects_arn] + } + + # 3) Optional: Allow multipart upload operations for large files. + statement { + sid = "Multipart" + effect = "Allow" + actions = [ + "s3:AbortMultipartUpload", + "s3:ListMultipartUploadParts", + "s3:ListBucketMultipartUploads" + ] + resources = [local.bucket_arn, local.objects_arn] + } +} + +# Create the custom least-privilege S3 policy. +resource "aws_iam_policy" "s3_app_policy" { + name = "${var.name_prefix}-s3-app-policy" + policy = data.aws_iam_policy_document.s3_app_least.json +} + +# This tells the IAM role what it is allowed to do. +# In this case, Attach the custom least-privilege S3 policy to the EC2 role. +resource "aws_iam_role_policy_attachment" "s3_access" { + role = aws_iam_role.app_ec2_role.name + policy_arn = aws_iam_policy.s3_app_policy.arn +} diff --git a/variables.tf b/variables.tf index b36e8d6..81a26a5 100644 --- a/variables.tf +++ b/variables.tf @@ -143,6 +143,12 @@ variable "service_name" { default = "csye6225_webapp" } +variable "s3_prefix" { + description = "Restrict access to a specific folder (prefix) inside the bucket. Leave empty (\"\") to allow access to the entire bucket." + type = string + default = "" +} + variable "tags" { description = "Common tags applied to all resources" type = map(string) From 28774bae60378d6a5259dbd348c3080710af1fd7 Mon Sep 17 00:00:00 2001 From: Isaac T Date: Wed, 22 Oct 2025 21:14:59 -0400 Subject: [PATCH 5/7] chore(terraform): format with terraform fmt --- ec2.tf | 12 ++++++------ iam_role.tf | 16 ++++++++-------- outputs.tf | 2 +- rds.tf | 48 +++++++++++++++++++++++------------------------ s3.tf | 4 ++-- security-group.tf | 10 +++++----- variables.tf | 26 ++++++++++++------------- 7 files changed, 59 insertions(+), 59 deletions(-) diff --git a/ec2.tf b/ec2.tf index 83a67f5..8999753 100644 --- a/ec2.tf +++ b/ec2.tf @@ -23,7 +23,7 @@ resource "aws_instance" "app" { instance_type = var.instance_type subnet_id = local.chosen_subnet_id vpc_security_group_ids = [aws_security_group.app_sg.id] - iam_instance_profile = aws_iam_instance_profile.app_ec2_profile.name + iam_instance_profile = aws_iam_instance_profile.app_ec2_profile.name # assign ssh key key_name = var.key_name != "" ? var.key_name : null @@ -47,11 +47,11 @@ resource "aws_instance" "app" { app_dir = var.app_dir service_name = var.service_name - db_host = aws_db_instance.db.address - db_port = aws_db_instance.db.port - db_name = var.db_name - db_username = var.db_username - db_password = var.db_password + db_host = aws_db_instance.db.address + db_port = aws_db_instance.db.port + db_name = var.db_name + db_username = var.db_username + db_password = var.db_password }) tags = { diff --git a/iam_role.tf b/iam_role.tf index e2e9c61..661f53e 100644 --- a/iam_role.tf +++ b/iam_role.tf @@ -5,9 +5,9 @@ resource "aws_iam_role" "app_ec2_role" { assume_role_policy = jsonencode({ Version = "2012-10-17", Statement = [{ - Effect = "Allow", + Effect = "Allow", Principal = { Service = "ec2.amazonaws.com" }, # Who can assume this role. The 'Service' here represents the EC2 service itself. - Action = "sts:AssumeRole" + Action = "sts:AssumeRole" }] }) } @@ -24,11 +24,11 @@ resource "aws_iam_instance_profile" "app_ec2_profile" { # ---------------------- locals { # Retrieve the name and ARN of the S3 bucket created in Terraform. - bucket_name = aws_s3_bucket.images.bucket - bucket_arn = "arn:aws:s3:::${local.bucket_name}" + bucket_name = aws_s3_bucket.images.bucket + bucket_arn = "arn:aws:s3:::${local.bucket_name}" # Define the object-level ARN (optionally scoped to a prefix). - objects_arn = "arn:aws:s3:::${local.bucket_name}/${var.s3_prefix}*" + objects_arn = "arn:aws:s3:::${local.bucket_name}/${var.s3_prefix}*" } # Generate a least-privilege S3 access policy for the EC2 IAM Role. @@ -59,9 +59,9 @@ data "aws_iam_policy_document" "s3_app_least" { # 3) Optional: Allow multipart upload operations for large files. statement { - sid = "Multipart" - effect = "Allow" - actions = [ + sid = "Multipart" + effect = "Allow" + actions = [ "s3:AbortMultipartUpload", "s3:ListMultipartUploadParts", "s3:ListBucketMultipartUploads" diff --git a/outputs.tf b/outputs.tf index d9133da..19f4d6a 100644 --- a/outputs.tf +++ b/outputs.tf @@ -43,7 +43,7 @@ output "instance_id" { output "rds_endpoint" { description = "RDS endpoint hostname" - value = aws_db_instance.db.address + value = aws_db_instance.db.address } output "rds_port" { diff --git a/rds.tf b/rds.tf index 5049f2a..7702c23 100644 --- a/rds.tf +++ b/rds.tf @@ -1,16 +1,16 @@ resource "aws_db_parameter_group" "postgres" { - name = "${var.name_prefix}-pg-param" - family = var.db_engine_family + name = "${var.name_prefix}-pg-param" + family = var.db_engine_family description = "Custom parameter group for PostgreSQL ${var.db_engine_version}" parameter { - name = "log_min_duration_statement" + name = "log_min_duration_statement" value = "500" } } resource "aws_db_subnet_group" "db_private" { - name = "${var.name_prefix}-db-subnet-group" + name = "${var.name_prefix}-db-subnet-group" subnet_ids = [for s in aws_subnet.private : s.id] # multiple subnet (at least 2) tags = { Name = "${var.name_prefix}-db-subnet-group" @@ -19,26 +19,26 @@ resource "aws_db_subnet_group" "db_private" { # RDS Instance resource "aws_db_instance" "db" { - identifier = "${var.name_prefix}-rds" - engine = "postgres" - engine_version = var.db_engine_version # e.g., "16.3" - instance_class = var.db_instance_class # e.g., "db.t3.micro" - allocated_storage = var.db_allocated_storage # e.g., 20 - storage_type = "gp3" - - db_name = var.db_name - username = var.db_username - password = var.db_password - - port = var.db_port # 5432 - multi_az = false - publicly_accessible = false - - vpc_security_group_ids = [aws_security_group.db_sg.id] - db_subnet_group_name = aws_db_subnet_group.db_private.name - parameter_group_name = aws_db_parameter_group.postgres.name - - skip_final_snapshot = true + identifier = "${var.name_prefix}-rds" + engine = "postgres" + engine_version = var.db_engine_version # e.g., "16.3" + instance_class = var.db_instance_class # e.g., "db.t3.micro" + allocated_storage = var.db_allocated_storage # e.g., 20 + storage_type = "gp3" + + db_name = var.db_name + username = var.db_username + password = var.db_password + + port = var.db_port # 5432 + multi_az = false + publicly_accessible = false + + vpc_security_group_ids = [aws_security_group.db_sg.id] + db_subnet_group_name = aws_db_subnet_group.db_private.name + parameter_group_name = aws_db_parameter_group.postgres.name + + skip_final_snapshot = true tags = { Name = "${var.name_prefix}-rds-postgres" diff --git a/s3.tf b/s3.tf index 4020f40..1cf0be8 100644 --- a/s3.tf +++ b/s3.tf @@ -4,8 +4,8 @@ resource "aws_s3_bucket" "images" { bucket_prefix = var.name_prefix tags = { - Name = "${var.name_prefix}-s3" - Environment = var.profile + Name = "${var.name_prefix}-s3" + Environment = var.profile } } diff --git a/security-group.tf b/security-group.tf index 1ec2553..f85cceb 100644 --- a/security-group.tf +++ b/security-group.tf @@ -59,12 +59,12 @@ resource "aws_security_group" "db_sg" { # Allow inbound DB access from app_sg resource "aws_vpc_security_group_ingress_rule" "db_ingress_app_sg" { - security_group_id = aws_security_group.db_sg.id # apply to what sg + security_group_id = aws_security_group.db_sg.id # apply to what sg referenced_security_group_id = aws_security_group.app_sg.id - from_port = var.db_port - to_port = var.db_port - ip_protocol = "tcp" - description = "Allow TCP ${each.value} from anywhere (IPv4)" + from_port = var.db_port + to_port = var.db_port + ip_protocol = "tcp" + description = "Allow TCP ${each.value} from anywhere (IPv4)" } # Allow outbound (for updates / AWS services) diff --git a/variables.tf b/variables.tf index 81a26a5..60fda24 100644 --- a/variables.tf +++ b/variables.tf @@ -123,30 +123,30 @@ variable "db_engine_family" { default = "postgres16" } -variable "app_user" { - type = string - default = "csyeapp" +variable "app_user" { + type = string + default = "csyeapp" } -variable "app_group" { - type = string - default = "csye6225" +variable "app_group" { + type = string + default = "csye6225" } -variable "app_dir" { - type = string - default = "/opt/csye6225" +variable "app_dir" { + type = string + default = "/opt/csye6225" } variable "service_name" { - type = string - default = "csye6225_webapp" + type = string + default = "csye6225_webapp" } variable "s3_prefix" { description = "Restrict access to a specific folder (prefix) inside the bucket. Leave empty (\"\") to allow access to the entire bucket." - type = string - default = "" + type = string + default = "" } variable "tags" { From 1615dbf4a05eec710404e56e4c0982d8ac3fe34c Mon Sep 17 00:00:00 2001 From: Isaac T Date: Thu, 23 Oct 2025 12:36:24 -0400 Subject: [PATCH 6/7] feat(s3): inject region and bucket info into EC2 user data - Added AWS_REGION and S3_BUCKET variables in user_data.sh - Passed new vars via templatefile in ec2.tf - Used random_uuid to keep S3 bucket name stable across applies --- .terraform.lock.hcl | 19 +++++++++++++++++++ ec2.tf | 3 +++ s3.tf | 4 +++- scripts/user_data.sh | 18 ++++++++---------- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl index 560e101..dac85a6 100644 --- a/.terraform.lock.hcl +++ b/.terraform.lock.hcl @@ -23,3 +23,22 @@ provider "registry.terraform.io/hashicorp/aws" { "zh:fb8c5ff7296d01bf60d983c64f45969ec664a40bdd768d90a35a6afe7df1aeb7", ] } + +provider "registry.terraform.io/hashicorp/random" { + version = "3.7.2" + hashes = [ + "h1:KG4NuIBl1mRWU0KD/BGfCi1YN/j3F7H4YgeeM7iSdNs=", + "zh:14829603a32e4bc4d05062f059e545a91e27ff033756b48afbae6b3c835f508f", + "zh:1527fb07d9fea400d70e9e6eb4a2b918d5060d604749b6f1c361518e7da546dc", + "zh:1e86bcd7ebec85ba336b423ba1db046aeaa3c0e5f921039b3f1a6fc2f978feab", + "zh:24536dec8bde66753f4b4030b8f3ef43c196d69cccbea1c382d01b222478c7a3", + "zh:29f1786486759fad9b0ce4fdfbbfece9343ad47cd50119045075e05afe49d212", + "zh:4d701e978c2dd8604ba1ce962b047607701e65c078cb22e97171513e9e57491f", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7b8434212eef0f8c83f5a90c6d76feaf850f6502b61b53c329e85b3b281cba34", + "zh:ac8a23c212258b7976e1621275e3af7099e7e4a3d4478cf8d5d2a27f3bc3e967", + "zh:b516ca74431f3df4c6cf90ddcdb4042c626e026317a33c53f0b445a3d93b720d", + "zh:dc76e4326aec2490c1600d6871a95e78f9050f9ce427c71707ea412a2f2f1a62", + "zh:eac7b63e86c749c7d48f527671c7aee5b4e26c10be6ad7232d6860167f99dbb0", + ] +} diff --git a/ec2.tf b/ec2.tf index 8999753..080d4e6 100644 --- a/ec2.tf +++ b/ec2.tf @@ -52,6 +52,9 @@ resource "aws_instance" "app" { db_name = var.db_name db_username = var.db_username db_password = var.db_password + + aws_region = var.region + s3_bucket = aws_s3_bucket.images.bucket }) tags = { diff --git a/s3.tf b/s3.tf index 1cf0be8..ca8a9b9 100644 --- a/s3.tf +++ b/s3.tf @@ -1,5 +1,5 @@ resource "aws_s3_bucket" "images" { - bucket = random_uuid() + bucket = "${var.name_prefix}-${random_uuid.s3_suffix.result}" force_destroy = true bucket_prefix = var.name_prefix @@ -9,6 +9,8 @@ resource "aws_s3_bucket" "images" { } } +resource "random_uuid" "s3_suffix" {} + resource "aws_s3_bucket_public_access_block" "images" { bucket = aws_s3_bucket.images.id diff --git a/scripts/user_data.sh b/scripts/user_data.sh index 14a4b55..4782830 100644 --- a/scripts/user_data.sh +++ b/scripts/user_data.sh @@ -1,11 +1,7 @@ #!/bin/bash set -euo pipefail -APP_USER="${app_user}" -APP_GROUP="${app_group}" -APP_DIR="${app_dir}" -SERVICE_NAME="${service_name}" -ENV_FILE="$APP_DIR/.env" +ENV_FILE="${app_dir}/.env" ### ====== Configure log color ====== log() { echo -e "\033[1;32m[OK]\033[0m $*"; } @@ -14,21 +10,23 @@ err() { echo -e "\033[1;31m[ERR]\033[0m $*" >&2; } info "=== Setting up environment for web app in $APP_DIR ===" -mkdir -p "$APP_DIR" # make sure the directory exist +mkdir -p "${app_dir}" # make sure the directory exist cat >> "$ENV_FILE" < Date: Thu, 23 Oct 2025 14:43:57 -0400 Subject: [PATCH 7/7] refactor(terraform): remove variable 'profile - resolve undefined variable issue and add logging to /var/log/user_data_setup.log in user_data.sh --- providers.tf | 3 +-- rds.tf | 3 +-- s3.tf | 4 +--- scripts/user_data.sh | 18 ++++++++++-------- security-group.tf | 2 +- variables.tf | 15 ++++++++------- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/providers.tf b/providers.tf index 060f4aa..d62e027 100644 --- a/providers.tf +++ b/providers.tf @@ -1,5 +1,4 @@ # Configure the AWS Provider provider "aws" { - region = var.region - profile = var.profile + region = var.region } diff --git a/rds.tf b/rds.tf index 7702c23..8123b3d 100644 --- a/rds.tf +++ b/rds.tf @@ -41,8 +41,7 @@ resource "aws_db_instance" "db" { skip_final_snapshot = true tags = { - Name = "${var.name_prefix}-rds-postgres" - Environment = var.profile + Name = "${var.name_prefix}-rds-postgres" } depends_on = [ diff --git a/s3.tf b/s3.tf index ca8a9b9..0fbd0de 100644 --- a/s3.tf +++ b/s3.tf @@ -1,11 +1,9 @@ resource "aws_s3_bucket" "images" { bucket = "${var.name_prefix}-${random_uuid.s3_suffix.result}" force_destroy = true - bucket_prefix = var.name_prefix tags = { - Name = "${var.name_prefix}-s3" - Environment = var.profile + Name = "${var.name_prefix}-s3" } } diff --git a/scripts/user_data.sh b/scripts/user_data.sh index 4782830..2012d99 100644 --- a/scripts/user_data.sh +++ b/scripts/user_data.sh @@ -2,24 +2,26 @@ set -euo pipefail ENV_FILE="${app_dir}/.env" +LOG_FILE="/var/log/user_data_setup.log" +exec > >(tee -a "$LOG_FILE") 2>&1 ### ====== Configure log color ====== log() { echo -e "\033[1;32m[OK]\033[0m $*"; } info() { echo -e "\033[1;34m[INFO]\033[0m $*"; } err() { echo -e "\033[1;31m[ERR]\033[0m $*" >&2; } -info "=== Setting up environment for web app in $APP_DIR ===" +info "=== Setting up environment for web app in ${app_dir} ===" mkdir -p "${app_dir}" # make sure the directory exist cat >> "$ENV_FILE" <