From 4fa7edaf926d7495ae8ddd23c1af1d613dfccdc0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 00:59:37 +0000 Subject: [PATCH 1/4] Initial plan From c1d314c1cc8f5954d0a9828bce2ec4cb7e91475f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 01:01:43 +0000 Subject: [PATCH 2/4] Create complete terraform-infra directory structure Co-authored-by: paseka10jaroslav-coder <252813980+paseka10jaroslav-coder@users.noreply.github.com> --- terraform-infra/.github/CODEOWNERS | 15 ++ .../.github/pull_request_template.md | 36 +++++ .../.github/workflows/terraform.yml | 53 +++++++ terraform-infra/.gitignore | 40 +++++ terraform-infra/README.md | 126 +++++++++++++++ terraform-infra/environments/dev/backend.tf | 9 ++ terraform-infra/environments/dev/main.tf | 33 ++++ terraform-infra/environments/dev/outputs.tf | 24 +++ terraform-infra/environments/dev/variables.tf | 29 ++++ terraform-infra/environments/prod/.gitkeep | 0 terraform-infra/environments/prod/README.md | 3 + terraform-infra/environments/staging/.gitkeep | 0 .../environments/staging/README.md | 2 + terraform-infra/modules/vpc/main.tf | 144 ++++++++++++++++++ terraform-infra/modules/vpc/outputs.tf | 29 ++++ terraform-infra/modules/vpc/variables.tf | 21 +++ 16 files changed, 564 insertions(+) create mode 100644 terraform-infra/.github/CODEOWNERS create mode 100644 terraform-infra/.github/pull_request_template.md create mode 100644 terraform-infra/.github/workflows/terraform.yml create mode 100644 terraform-infra/.gitignore create mode 100644 terraform-infra/README.md create mode 100644 terraform-infra/environments/dev/backend.tf create mode 100644 terraform-infra/environments/dev/main.tf create mode 100644 terraform-infra/environments/dev/outputs.tf create mode 100644 terraform-infra/environments/dev/variables.tf create mode 100644 terraform-infra/environments/prod/.gitkeep create mode 100644 terraform-infra/environments/prod/README.md create mode 100644 terraform-infra/environments/staging/.gitkeep create mode 100644 terraform-infra/environments/staging/README.md create mode 100644 terraform-infra/modules/vpc/main.tf create mode 100644 terraform-infra/modules/vpc/outputs.tf create mode 100644 terraform-infra/modules/vpc/variables.tf diff --git a/terraform-infra/.github/CODEOWNERS b/terraform-infra/.github/CODEOWNERS new file mode 100644 index 0000000..cf00c1c --- /dev/null +++ b/terraform-infra/.github/CODEOWNERS @@ -0,0 +1,15 @@ +# Terraform Infrastructure Code Owners +# These owners will be the default owners for everything in +# the terraform-infra directory + +# Global owners for all terraform files +*.tf @paseka10jaroslav-coder +*.tfvars @paseka10jaroslav-coder + +# Environment specific owners +/terraform-infra/environments/prod/ @paseka10jaroslav-coder +/terraform-infra/environments/staging/ @paseka10jaroslav-coder +/terraform-infra/environments/dev/ @paseka10jaroslav-coder + +# Modules +/terraform-infra/modules/ @paseka10jaroslav-coder diff --git a/terraform-infra/.github/pull_request_template.md b/terraform-infra/.github/pull_request_template.md new file mode 100644 index 0000000..8a747a8 --- /dev/null +++ b/terraform-infra/.github/pull_request_template.md @@ -0,0 +1,36 @@ +# Terraform Infrastructure Change Request + +## Description + + +## Environment + +- [ ] Dev +- [ ] Staging +- [ ] Production + +## Type of Change + +- [ ] New resource +- [ ] Resource modification +- [ ] Resource deletion +- [ ] Module update +- [ ] Configuration change +- [ ] Bug fix + +## Checklist +- [ ] I have run `terraform fmt` to format my code +- [ ] I have run `terraform validate` to validate my configuration +- [ ] I have run `terraform plan` and reviewed the changes +- [ ] I have tested my changes in a non-production environment +- [ ] I have updated documentation if necessary +- [ ] I have followed security best practices + +## Terraform Plan Output + +``` + +``` + +## Additional Notes + diff --git a/terraform-infra/.github/workflows/terraform.yml b/terraform-infra/.github/workflows/terraform.yml new file mode 100644 index 0000000..1c6d225 --- /dev/null +++ b/terraform-infra/.github/workflows/terraform.yml @@ -0,0 +1,53 @@ +name: Terraform CI/CD + +on: + pull_request: + branches: + - main + paths: + - 'terraform-infra/**' + push: + branches: + - main + paths: + - 'terraform-infra/**' + +jobs: + terraform: + name: Terraform Plan and Apply + runs-on: ubuntu-latest + strategy: + matrix: + environment: [dev, staging, prod] + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_version: 1.5.0 + + - name: Terraform Format Check + run: terraform fmt -check -recursive + working-directory: terraform-infra + + - name: Terraform Init + run: terraform init + working-directory: terraform-infra/environments/${{ matrix.environment }} + + - name: Terraform Validate + run: terraform validate + working-directory: terraform-infra/environments/${{ matrix.environment }} + + - name: Terraform Plan + run: terraform plan -out=tfplan + working-directory: terraform-infra/environments/${{ matrix.environment }} + env: + TF_VAR_environment: ${{ matrix.environment }} + + - name: Terraform Apply + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + run: terraform apply -auto-approve tfplan + working-directory: terraform-infra/environments/${{ matrix.environment }} diff --git a/terraform-infra/.gitignore b/terraform-infra/.gitignore new file mode 100644 index 0000000..1110ce0 --- /dev/null +++ b/terraform-infra/.gitignore @@ -0,0 +1,40 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data +*.tfvars +*.tfvars.json + +# Ignore override files as they are usually used to override resources locally +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +*tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +# Ignore Mac .DS_Store files +.DS_Store + +# Ignore IDE files +.idea/ +.vscode/ +*.swp +*.swo +*~ diff --git a/terraform-infra/README.md b/terraform-infra/README.md new file mode 100644 index 0000000..99d9de8 --- /dev/null +++ b/terraform-infra/README.md @@ -0,0 +1,126 @@ +# Terraform Infrastructure + +This directory contains the Terraform infrastructure code for the SolVoid project. + +## Directory Structure + +``` +terraform-infra/ +├── .github/ +│ ├── workflows/ +│ │ └── terraform.yml # CI/CD workflow for Terraform +│ ├── CODEOWNERS # Code ownership configuration +│ └── pull_request_template.md # PR template for infrastructure changes +├── environments/ +│ ├── dev/ # Development environment +│ │ ├── main.tf # Main Terraform configuration +│ │ ├── variables.tf # Variable definitions +│ │ ├── outputs.tf # Output definitions +│ │ └── backend.tf # Backend configuration +│ ├── staging/ # Staging environment (to be configured) +│ └── prod/ # Production environment (to be configured) +├── modules/ +│ └── vpc/ # VPC module +│ ├── main.tf # VPC resources +│ ├── variables.tf # VPC variables +│ └── outputs.tf # VPC outputs +├── .gitignore # Terraform-specific gitignore +└── README.md # This file +``` + +## Prerequisites + +- [Terraform](https://www.terraform.io/downloads.html) >= 1.5.0 +- AWS CLI configured with appropriate credentials +- S3 bucket for Terraform state (configured in backend.tf) +- DynamoDB table for state locking + +## Getting Started + +### 1. Initialize Terraform + +Navigate to the desired environment directory and initialize Terraform: + +```bash +cd terraform-infra/environments/dev +terraform init +``` + +### 2. Review the Plan + +Review the planned changes before applying: + +```bash +terraform plan +``` + +### 3. Apply Changes + +Apply the Terraform configuration: + +```bash +terraform apply +``` + +## Environments + +### Development (dev) +- **Region**: us-east-1 +- **VPC CIDR**: 10.0.0.0/16 +- **Purpose**: Development and testing + +### Staging +- To be configured +- Similar structure to dev environment + +### Production (prod) +- To be configured +- Enhanced security and compliance measures + +## Modules + +### VPC Module +Creates a VPC with: +- Public and private subnets across multiple availability zones +- Internet Gateway for public internet access +- NAT Gateways for private subnet internet access +- Route tables and associations + +## CI/CD + +The GitHub Actions workflow (`.github/workflows/terraform.yml`) automatically: +- Validates Terraform formatting +- Runs `terraform init` +- Runs `terraform validate` +- Runs `terraform plan` on pull requests +- Runs `terraform apply` on merges to main branch + +## Best Practices + +1. **State Management**: Always use remote state (S3 backend) with state locking (DynamoDB) +2. **Code Review**: All infrastructure changes must go through pull request review +3. **Testing**: Test changes in dev environment before applying to staging/prod +4. **Documentation**: Update documentation when adding new modules or resources +5. **Security**: Never commit sensitive data or credentials to version control +6. **Formatting**: Run `terraform fmt` before committing changes + +## Security Considerations + +- All resources are tagged with environment and managed-by metadata +- State files are encrypted at rest in S3 +- State locking prevents concurrent modifications +- CODEOWNERS ensures proper review of infrastructure changes + +## Contributing + +1. Create a new branch for your changes +2. Make changes in the appropriate environment or module +3. Run `terraform fmt` to format your code +4. Run `terraform validate` to validate your configuration +5. Create a pull request with a detailed description +6. Ensure CI/CD checks pass +7. Request review from code owners + +## Support + +For questions or issues, please open an issue in the repository or contact the infrastructure team. diff --git a/terraform-infra/environments/dev/backend.tf b/terraform-infra/environments/dev/backend.tf new file mode 100644 index 0000000..2d67d9a --- /dev/null +++ b/terraform-infra/environments/dev/backend.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "solvoid-terraform-state-dev" + key = "dev/terraform.tfstate" + region = "us-east-1" + encrypt = true + dynamodb_table = "solvoid-terraform-locks-dev" + } +} diff --git a/terraform-infra/environments/dev/main.tf b/terraform-infra/environments/dev/main.tf new file mode 100644 index 0000000..8cb21b2 --- /dev/null +++ b/terraform-infra/environments/dev/main.tf @@ -0,0 +1,33 @@ +terraform { + required_version = ">= 1.5.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +provider "aws" { + region = var.aws_region + + default_tags { + tags = { + Environment = var.environment + ManagedBy = "Terraform" + Project = "SolVoid" + } + } +} + +# VPC Module +module "vpc" { + source = "../../modules/vpc" + + environment = var.environment + vpc_cidr = var.vpc_cidr + availability_zones = var.availability_zones + + tags = var.tags +} diff --git a/terraform-infra/environments/dev/outputs.tf b/terraform-infra/environments/dev/outputs.tf new file mode 100644 index 0000000..2da24df --- /dev/null +++ b/terraform-infra/environments/dev/outputs.tf @@ -0,0 +1,24 @@ +output "vpc_id" { + description = "The ID of the VPC" + value = module.vpc.vpc_id +} + +output "vpc_cidr" { + description = "The CIDR block of the VPC" + value = module.vpc.vpc_cidr +} + +output "public_subnet_ids" { + description = "List of IDs of public subnets" + value = module.vpc.public_subnet_ids +} + +output "private_subnet_ids" { + description = "List of IDs of private subnets" + value = module.vpc.private_subnet_ids +} + +output "environment" { + description = "Environment name" + value = var.environment +} diff --git a/terraform-infra/environments/dev/variables.tf b/terraform-infra/environments/dev/variables.tf new file mode 100644 index 0000000..01b8105 --- /dev/null +++ b/terraform-infra/environments/dev/variables.tf @@ -0,0 +1,29 @@ +variable "aws_region" { + description = "AWS region to deploy resources" + type = string + default = "us-east-1" +} + +variable "environment" { + description = "Environment name" + type = string + default = "dev" +} + +variable "vpc_cidr" { + description = "CIDR block for VPC" + type = string + default = "10.0.0.0/16" +} + +variable "availability_zones" { + description = "List of availability zones" + type = list(string) + default = ["us-east-1a", "us-east-1b"] +} + +variable "tags" { + description = "Additional tags to apply to resources" + type = map(string) + default = {} +} diff --git a/terraform-infra/environments/prod/.gitkeep b/terraform-infra/environments/prod/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/terraform-infra/environments/prod/README.md b/terraform-infra/environments/prod/README.md new file mode 100644 index 0000000..f7fc0ec --- /dev/null +++ b/terraform-infra/environments/prod/README.md @@ -0,0 +1,3 @@ +# Production environment configuration will be added here +# Structure will be similar to dev environment +# Additional security and compliance measures should be applied diff --git a/terraform-infra/environments/staging/.gitkeep b/terraform-infra/environments/staging/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/terraform-infra/environments/staging/README.md b/terraform-infra/environments/staging/README.md new file mode 100644 index 0000000..721d5e0 --- /dev/null +++ b/terraform-infra/environments/staging/README.md @@ -0,0 +1,2 @@ +# Staging and Production environment configurations will be added here +# Structure will be similar to dev environment diff --git a/terraform-infra/modules/vpc/main.tf b/terraform-infra/modules/vpc/main.tf new file mode 100644 index 0000000..418cedb --- /dev/null +++ b/terraform-infra/modules/vpc/main.tf @@ -0,0 +1,144 @@ +resource "aws_vpc" "main" { + cidr_block = var.vpc_cidr + enable_dns_hostnames = true + enable_dns_support = true + + tags = merge( + var.tags, + { + Name = "${var.environment}-vpc" + Environment = var.environment + } + ) +} + +resource "aws_internet_gateway" "main" { + vpc_id = aws_vpc.main.id + + tags = merge( + var.tags, + { + Name = "${var.environment}-igw" + Environment = var.environment + } + ) +} + +# Public Subnets +resource "aws_subnet" "public" { + count = length(var.availability_zones) + vpc_id = aws_vpc.main.id + cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index) + availability_zone = var.availability_zones[count.index] + map_public_ip_on_launch = true + + tags = merge( + var.tags, + { + Name = "${var.environment}-public-subnet-${count.index + 1}" + Environment = var.environment + Type = "public" + } + ) +} + +# Private Subnets +resource "aws_subnet" "private" { + count = length(var.availability_zones) + vpc_id = aws_vpc.main.id + cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index + 100) + availability_zone = var.availability_zones[count.index] + + tags = merge( + var.tags, + { + Name = "${var.environment}-private-subnet-${count.index + 1}" + Environment = var.environment + Type = "private" + } + ) +} + +# Elastic IPs for NAT Gateways +resource "aws_eip" "nat" { + count = length(var.availability_zones) + domain = "vpc" + + tags = merge( + var.tags, + { + Name = "${var.environment}-nat-eip-${count.index + 1}" + Environment = var.environment + } + ) + + depends_on = [aws_internet_gateway.main] +} + +# NAT Gateways +resource "aws_nat_gateway" "main" { + count = length(var.availability_zones) + allocation_id = aws_eip.nat[count.index].id + subnet_id = aws_subnet.public[count.index].id + + tags = merge( + var.tags, + { + Name = "${var.environment}-nat-gateway-${count.index + 1}" + Environment = var.environment + } + ) + + depends_on = [aws_internet_gateway.main] +} + +# Route Table for Public Subnets +resource "aws_route_table" "public" { + vpc_id = aws_vpc.main.id + + route { + cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.main.id + } + + tags = merge( + var.tags, + { + Name = "${var.environment}-public-rt" + Environment = var.environment + } + ) +} + +# Route Table Associations for Public Subnets +resource "aws_route_table_association" "public" { + count = length(var.availability_zones) + subnet_id = aws_subnet.public[count.index].id + route_table_id = aws_route_table.public.id +} + +# Route Tables for Private Subnets +resource "aws_route_table" "private" { + count = length(var.availability_zones) + vpc_id = aws_vpc.main.id + + route { + cidr_block = "0.0.0.0/0" + nat_gateway_id = aws_nat_gateway.main[count.index].id + } + + tags = merge( + var.tags, + { + Name = "${var.environment}-private-rt-${count.index + 1}" + Environment = var.environment + } + ) +} + +# Route Table Associations for Private Subnets +resource "aws_route_table_association" "private" { + count = length(var.availability_zones) + subnet_id = aws_subnet.private[count.index].id + route_table_id = aws_route_table.private[count.index].id +} diff --git a/terraform-infra/modules/vpc/outputs.tf b/terraform-infra/modules/vpc/outputs.tf new file mode 100644 index 0000000..97f4c77 --- /dev/null +++ b/terraform-infra/modules/vpc/outputs.tf @@ -0,0 +1,29 @@ +output "vpc_id" { + description = "The ID of the VPC" + value = aws_vpc.main.id +} + +output "vpc_cidr" { + description = "The CIDR block of the VPC" + value = aws_vpc.main.cidr_block +} + +output "public_subnet_ids" { + description = "List of IDs of public subnets" + value = aws_subnet.public[*].id +} + +output "private_subnet_ids" { + description = "List of IDs of private subnets" + value = aws_subnet.private[*].id +} + +output "nat_gateway_ids" { + description = "List of NAT Gateway IDs" + value = aws_nat_gateway.main[*].id +} + +output "internet_gateway_id" { + description = "The ID of the Internet Gateway" + value = aws_internet_gateway.main.id +} diff --git a/terraform-infra/modules/vpc/variables.tf b/terraform-infra/modules/vpc/variables.tf new file mode 100644 index 0000000..dbb2f3f --- /dev/null +++ b/terraform-infra/modules/vpc/variables.tf @@ -0,0 +1,21 @@ +variable "environment" { + description = "Environment name (dev, staging, prod)" + type = string +} + +variable "vpc_cidr" { + description = "CIDR block for VPC" + type = string + default = "10.0.0.0/16" +} + +variable "availability_zones" { + description = "List of availability zones" + type = list(string) +} + +variable "tags" { + description = "Additional tags to apply to resources" + type = map(string) + default = {} +} From e86cc11c4681e98616b7e7d79d20f7c10f73ff0d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 01:02:27 +0000 Subject: [PATCH 3/4] Format terraform files with terraform fmt Co-authored-by: paseka10jaroslav-coder <252813980+paseka10jaroslav-coder@users.noreply.github.com> --- .../environments/dev/.terraform.lock.hcl | 25 +++++++++++++++++++ terraform-infra/environments/dev/main.tf | 10 ++++---- terraform-infra/modules/vpc/main.tf | 24 +++++++++--------- 3 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 terraform-infra/environments/dev/.terraform.lock.hcl diff --git a/terraform-infra/environments/dev/.terraform.lock.hcl b/terraform-infra/environments/dev/.terraform.lock.hcl new file mode 100644 index 0000000..39a6fbd --- /dev/null +++ b/terraform-infra/environments/dev/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.100.0" + constraints = "~> 5.0" + hashes = [ + "h1:edXOJWE4ORX8Fm+dpVpICzMZJat4AX0VRCAy/xkcOc0=", + "zh:054b8dd49f0549c9a7cc27d159e45327b7b65cf404da5e5a20da154b90b8a644", + "zh:0b97bf8d5e03d15d83cc40b0530a1f84b459354939ba6f135a0086c20ebbe6b2", + "zh:1589a2266af699cbd5d80737a0fe02e54ec9cf2ca54e7e00ac51c7359056f274", + "zh:6330766f1d85f01ae6ea90d1b214b8b74cc8c1badc4696b165b36ddd4cc15f7b", + "zh:7c8c2e30d8e55291b86fcb64bdf6c25489d538688545eb48fd74ad622e5d3862", + "zh:99b1003bd9bd32ee323544da897148f46a527f622dc3971af63ea3e251596342", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9f8b909d3ec50ade83c8062290378b1ec553edef6a447c56dadc01a99f4eaa93", + "zh:aaef921ff9aabaf8b1869a86d692ebd24fbd4e12c21205034bb679b9caf883a2", + "zh:ac882313207aba00dd5a76dbd572a0ddc818bb9cbf5c9d61b28fe30efaec951e", + "zh:bb64e8aff37becab373a1a0cc1080990785304141af42ed6aa3dd4913b000421", + "zh:dfe495f6621df5540d9c92ad40b8067376350b005c637ea6efac5dc15028add4", + "zh:f0ddf0eaf052766cfe09dea8200a946519f653c384ab4336e2a4a64fdd6310e9", + "zh:f1b7e684f4c7ae1eed272b6de7d2049bb87a0275cb04dbb7cda6636f600699c9", + "zh:ff461571e3f233699bf690db319dfe46aec75e58726636a0d97dd9ac6e32fb70", + ] +} diff --git a/terraform-infra/environments/dev/main.tf b/terraform-infra/environments/dev/main.tf index 8cb21b2..f2a3a2a 100644 --- a/terraform-infra/environments/dev/main.tf +++ b/terraform-infra/environments/dev/main.tf @@ -1,6 +1,6 @@ terraform { required_version = ">= 1.5.0" - + required_providers { aws = { source = "hashicorp/aws" @@ -11,7 +11,7 @@ terraform { provider "aws" { region = var.aws_region - + default_tags { tags = { Environment = var.environment @@ -24,10 +24,10 @@ provider "aws" { # VPC Module module "vpc" { source = "../../modules/vpc" - - environment = var.environment + + environment = var.environment vpc_cidr = var.vpc_cidr availability_zones = var.availability_zones - + tags = var.tags } diff --git a/terraform-infra/modules/vpc/main.tf b/terraform-infra/modules/vpc/main.tf index 418cedb..d0efbae 100644 --- a/terraform-infra/modules/vpc/main.tf +++ b/terraform-infra/modules/vpc/main.tf @@ -2,7 +2,7 @@ resource "aws_vpc" "main" { cidr_block = var.vpc_cidr enable_dns_hostnames = true enable_dns_support = true - + tags = merge( var.tags, { @@ -14,7 +14,7 @@ resource "aws_vpc" "main" { resource "aws_internet_gateway" "main" { vpc_id = aws_vpc.main.id - + tags = merge( var.tags, { @@ -31,7 +31,7 @@ resource "aws_subnet" "public" { cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index) availability_zone = var.availability_zones[count.index] map_public_ip_on_launch = true - + tags = merge( var.tags, { @@ -48,7 +48,7 @@ resource "aws_subnet" "private" { vpc_id = aws_vpc.main.id cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index + 100) availability_zone = var.availability_zones[count.index] - + tags = merge( var.tags, { @@ -63,7 +63,7 @@ resource "aws_subnet" "private" { resource "aws_eip" "nat" { count = length(var.availability_zones) domain = "vpc" - + tags = merge( var.tags, { @@ -71,7 +71,7 @@ resource "aws_eip" "nat" { Environment = var.environment } ) - + depends_on = [aws_internet_gateway.main] } @@ -80,7 +80,7 @@ resource "aws_nat_gateway" "main" { count = length(var.availability_zones) allocation_id = aws_eip.nat[count.index].id subnet_id = aws_subnet.public[count.index].id - + tags = merge( var.tags, { @@ -88,19 +88,19 @@ resource "aws_nat_gateway" "main" { Environment = var.environment } ) - + depends_on = [aws_internet_gateway.main] } # Route Table for Public Subnets resource "aws_route_table" "public" { vpc_id = aws_vpc.main.id - + route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.main.id } - + tags = merge( var.tags, { @@ -121,12 +121,12 @@ resource "aws_route_table_association" "public" { resource "aws_route_table" "private" { count = length(var.availability_zones) vpc_id = aws_vpc.main.id - + route { cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.main[count.index].id } - + tags = merge( var.tags, { From 6d88dc10fe5a32112c2464f162980b99c850f9ac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 01:03:58 +0000 Subject: [PATCH 4/4] Address code review feedback: update workflow, add prerequisites documentation Co-authored-by: paseka10jaroslav-coder <252813980+paseka10jaroslav-coder@users.noreply.github.com> --- .../.github/workflows/terraform.yml | 15 +++++-- terraform-infra/README.md | 42 +++++++++++++++++++ terraform-infra/environments/dev/backend.tf | 5 +++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/terraform-infra/.github/workflows/terraform.yml b/terraform-infra/.github/workflows/terraform.yml index 1c6d225..1ab1174 100644 --- a/terraform-infra/.github/workflows/terraform.yml +++ b/terraform-infra/.github/workflows/terraform.yml @@ -18,17 +18,26 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - environment: [dev, staging, prod] + # Only dev environment is configured currently + # Add staging and prod when those environments are ready + environment: [dev] steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Terraform - uses: hashicorp/setup-terraform@v2 + uses: hashicorp/setup-terraform@v3 with: terraform_version: 1.5.0 + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + - name: Terraform Format Check run: terraform fmt -check -recursive working-directory: terraform-infra diff --git a/terraform-infra/README.md b/terraform-infra/README.md index 99d9de8..e994b2f 100644 --- a/terraform-infra/README.md +++ b/terraform-infra/README.md @@ -35,6 +35,33 @@ terraform-infra/ - S3 bucket for Terraform state (configured in backend.tf) - DynamoDB table for state locking +### Backend Setup + +Before running `terraform init`, you need to create the backend resources manually: + +1. **Create S3 Bucket for State Storage:** + ```bash + aws s3api create-bucket --bucket solvoid-terraform-state-dev --region us-east-1 + aws s3api put-bucket-versioning --bucket solvoid-terraform-state-dev --versioning-configuration Status=Enabled + aws s3api put-bucket-encryption --bucket solvoid-terraform-state-dev --server-side-encryption-configuration '{ + "Rules": [{ + "ApplyServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + }] + }' + ``` + +2. **Create DynamoDB Table for State Locking:** + ```bash + aws dynamodb create-table \ + --table-name solvoid-terraform-locks-dev \ + --attribute-definitions AttributeName=LockID,AttributeType=S \ + --key-schema AttributeName=LockID,KeyType=HASH \ + --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 \ + --region us-east-1 + ``` + ## Getting Started ### 1. Initialize Terraform @@ -95,6 +122,21 @@ The GitHub Actions workflow (`.github/workflows/terraform.yml`) automatically: - Runs `terraform plan` on pull requests - Runs `terraform apply` on merges to main branch +### GitHub Actions Setup + +Before the workflow can run, you need to configure the following secrets in your GitHub repository: + +1. **AWS_ACCESS_KEY_ID**: AWS access key with permissions to manage infrastructure +2. **AWS_SECRET_ACCESS_KEY**: AWS secret access key + +To add these secrets: +1. Go to your repository on GitHub +2. Navigate to Settings > Secrets and variables > Actions +3. Click "New repository secret" +4. Add both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY + +Alternatively, you can configure OIDC authentication with AWS IAM for a more secure, keyless approach. + ## Best Practices 1. **State Management**: Always use remote state (S3 backend) with state locking (DynamoDB) diff --git a/terraform-infra/environments/dev/backend.tf b/terraform-infra/environments/dev/backend.tf index 2d67d9a..695b606 100644 --- a/terraform-infra/environments/dev/backend.tf +++ b/terraform-infra/environments/dev/backend.tf @@ -1,3 +1,8 @@ +# Backend configuration for storing Terraform state in S3 +# Prerequisites: +# 1. Create S3 bucket: solvoid-terraform-state-dev (with versioning enabled) +# 2. Create DynamoDB table: solvoid-terraform-locks-dev (with LockID as primary key) +# These resources should be created manually or through a separate bootstrap process terraform { backend "s3" { bucket = "solvoid-terraform-state-dev"