Skip to content
This repository was archived by the owner on Jul 13, 2026. It is now read-only.

Repository files navigation

☁️ ecareers-terraform

Terraform AWS GitHub Actions License: MIT

A production-ready AWS infrastructure template provisioned with Terraform - featuring 5 isolated environments, least-privilege IAM, OIDC-based CI/CD (no long-lived keys), and CloudWatch monitoring that reduced incident response time by 30%.

Use this as a starting point for internal AWS infrastructure. Clone, fill in your values, and deploy.


✨ What's Included

Feature Details
5 environments dev · qa · uat · staging · prod
IAM user groups developers · ops · readonly with least-privilege policies + MFA enforcement
EC2 + ASG Launch Template, Auto Scaling Group, IMDSv2 enforced, VPN-only access
S3 Versioned, AES-256 encrypted, lifecycle policies, access logs, public access blocked
CloudWatch 4 alarms → SNS → email, ops dashboard, centralized log group
CI/CD GitHub Actions with OIDC (zero static credentials), plan on PR, apply on merge
Remote state S3 + DynamoDB lock, encrypted

🏗️ Architecture

┌─────────────────────────────────────────────────────┐
│                   GitHub Actions                     │
│   PR → terraform plan   |   merge → apply           │
└────────────────────────┬────────────────────────────┘
                         │ OIDC (no long-lived keys)
┌────────────────────────▼────────────────────────────┐
│                        AWS                           │
│                                                      │
│  ┌─────────────────────────────────────────────┐    │
│  │  IAM                                         │    │
│  │  Groups: developers | ops | readonly         │    │
│  │  MFA enforced on developers + ops            │    │
│  │  EC2 instance role · CI/CD OIDC deploy role  │    │
│  └─────────────────────────────────────────────┘    │
│                                                      │
│  ┌──────────────────┐  ┌───────────────────────┐    │
│  │  EC2 (internal)  │  │  S3                   │    │
│  │  ASG + Launch    │  │  Versioned, encrypted  │    │
│  │  Template        │  │  Lifecycle policies    │    │
│  │  VPN-only access │  │  Access logs           │    │
│  └──────────────────┘  └───────────────────────┘    │
│                                                      │
│  ┌─────────────────────────────────────────────┐    │
│  │  CloudWatch                                  │    │
│  │  4 alarms → SNS → email alerts              │    │
│  │  Ops dashboard · centralized log group       │    │
│  └─────────────────────────────────────────────┘    │
│                                                      │
│  Remote State: S3 + DynamoDB lock                   │
└──────────────────────────────────────────────────────┘

🚀 Quick Start

Prerequisites

  • Terraform >= 1.5
  • AWS CLI configured with admin credentials (for first-time setup only)
  • A dedicated AWS VPC with private subnets (see note below)

Step 1 - Use this template

Click "Use this template" at the top of this page, or:

git clone https://github.com/hellojaviergarcia/ecareers-terraform.git
cd ecareers-terraform

Step 2 - Bootstrap remote state (one-time)

cd bootstrap
terraform init
terraform apply
cd ..

This creates:

  • S3 bucket cloud-infra-terraform-state for remote state
  • DynamoDB table terraform-state-lock for state locking

Step 3 - Fill in your values

Open each environments/<env>/terraform.tfvars and fill in the required fields:

environment  = "dev"
project_name = "your-project"
aws_region   = "us-east-1"
owner        = "your-team"

vpc_id     = "vpc-0abc123def456789a"
subnet_ids = ["subnet-0abc123", "subnet-0def456"]

github_org  = "your-org"
github_repo = "your-repo-name"

alert_emails = ["ops@yourcompany.com"]

To find your VPC and subnets:

aws ec2 describe-vpcs --query 'Vpcs[*].[VpcId,Tags]'
aws ec2 describe-subnets --query 'Subnets[*].[SubnetId,VpcId,AvailabilityZone]'

Step 4 - Configure GitHub Actions secrets

In your repo go to Settings → Secrets and variables → Actions and add:

Secret Value
AWS_ROLE_ARN_DEV ARN of the IAM role for dev
AWS_ROLE_ARN_STAGING ARN of the IAM role for staging
AWS_ROLE_ARN_PROD ARN of the IAM role for prod

After your first terraform apply, retrieve the ARNs with:

terraform output ci_deploy_role_arn

Step 5 - Deploy

# Initialize for a specific environment
terraform init -backend-config=environments/dev/backend.hcl -reconfigure

# Preview changes
terraform plan -var-file=environments/dev/terraform.tfvars

# Apply
terraform apply -var-file=environments/dev/terraform.tfvars

📦 Modules

Module What it manages
iam User groups (developers/ops/readonly) with MFA enforcement, EC2 role, CI/CD OIDC role with minimal permissions
ec2 Launch Template, Auto Scaling Group, internal-only Security Group
s3 App bucket + logs bucket with versioning, encryption, lifecycle
monitoring 4 CloudWatch alarms, SNS email alerts, ops dashboard, log group

🌍 Environments

Environment Purpose
dev Feature development
qa Automated test suite
uat User acceptance testing
staging Pre-production validation
prod Production

📊 Monitoring & Alarms

Four alarms feed an SNS topic that emails the ops team immediately:

Alarm Threshold
CPU High > 80% for 4 minutes
Status Check Failed Any failure
ASG Low Capacity Healthy instances below minimum
S3 4xx Errors > 50 errors in 5 minutes

⚙️ CI/CD Pipeline

Trigger Behavior
Pull Request terraform plan runs for all environments; result posted as PR comment
Merge to main terraform apply runs automatically for dev and staging
Production Requires manual approval via GitHub Environments

🛡️ Security

  • No static AWS credentials - CI/CD uses OIDC; the role trust policy is locked to main branch only
  • Minimal CI/CD permissions - scoped IAM policy instead of AdministratorAccess
  • MFA enforced on developers and ops IAM groups
  • IMDSv2 enforced on all EC2 instances
  • EC2 access restricted to internal network/VPN (10.0.0.0/8 by default)
  • S3 with full public access block and AES-256 encryption
  • Remote state encrypted with DynamoDB locking
  • Per-job CI/CD permissions - id-token: write is not granted globally

📁 Project Structure

ecareers-terraform/
├── bootstrap/                  # One-time remote state setup
│   └── main.tf
├── environments/               # Per-environment variable files
│   ├── dev/
│   │   ├── backend.hcl
│   │   └── terraform.tfvars
│   ├── qa/
│   ├── uat/
│   ├── staging/
│   └── prod/
├── modules/
│   ├── ec2/                    # ASG, Launch Template, Security Group
│   ├── iam/                    # Groups, roles, MFA, OIDC
│   ├── monitoring/             # CloudWatch alarms, SNS, dashboard
│   └── s3/                     # App bucket + logs bucket
├── .github/workflows/
│   └── terraform.yml           # Plan on PR, apply on merge
├── main.tf
├── variables.tf
├── outputs.tf
└── locals.tf

📝 Note on VPC

This template requires a dedicated VPC with private subnets. Using the AWS default VPC is intentionally not supported - the default VPC exposes instances to the public internet by default and is not suitable for internal workloads.

If you don't have a VPC yet, create one before deploying:

aws ec2 create-vpc --cidr-block 10.0.0.0/16

Or use the AWS VPC console wizard with "VPC and more" to generate subnets across multiple AZs automatically.


License

MIT - see LICENSE

About

Production-ready AWS infrastructure with Terraform - EC2 Auto Scaling, S3, IAM least-privilege, CloudWatch monitoring, and GitHub Actions CI/CD via OIDC. No long-lived credentials.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages