Provision a complete, minimal AWS environment with Terraform modules and deploy an application to EC2 using Jenkins.
- Architecture
- What gets created
- Project structure
- Prerequisites
- Backend and provider configuration
- Quick start (local Terraform)
- Module reference
- Jenkins CI/CD guide
- Security notes
- Recommended .gitignore
- Troubleshooting
flowchart LR
VPC[VPC\n10.0.0.0/16] --> SUBNET[Public Subnet\n10.0.1.0/24]
VPC --> IGW[Internet Gateway]
SUBNET --> RT[Route Table\n0.0.0.0/0 -> IGW]
VPC --> SG[Security Group\n22,80,9090]
SUBNET --> EC2[EC2 t2.micro]
SG --> EC2
KEY[Terraform-generated key pair] --> EC2
| Component | Details |
|---|---|
| VPC | 10.0.0.0/16 |
| Public Subnet | 10.0.1.0/24 in us-west-2a |
| Internet Gateway | Attached to the VPC |
| Route Table | Default route 0.0.0.0/0 to IGW |
| Route Association | Route table associated to public subnet |
| Security Group | Inbound 22, 80, 9090; outbound all |
| Key Pair | my-ec2-key + local PEM file |
| EC2 Instance | Ubuntu AMI ami-075686beab831bb7f, type t2.micro |
terraform/
backend.tf
provider.tf
main.tf
outputs.tf
Jenkinsfile
modules/
vpc/
subnet/
igw/
route-table/
security-group/
keypair/
ec2/
- Terraform
>= 1.3(recommended) - AWS account with permissions for VPC, EC2, Route Tables, Security Groups, Key Pairs, S3, and DynamoDB
- AWS credentials available locally (for local runs) or in Jenkins credentials store (for CI)
- Existing remote state resources in
us-west-2:- S3 bucket:
remote-backend - DynamoDB table:
terraform-locks
- S3 bucket:
Current config from this repo:
- Region:
us-west-2 - Backend bucket:
remote-backend - State key:
envs/dev/terraform.tfstate - Lock table:
terraform-locks - Encryption:
true
Run from the repository root (terraform/):
terraform init
terraform fmt -recursive
terraform validate
terraform plan -out=tfplan.binary
terraform apply tfplan.binaryGet EC2 public IP:
terraform output -raw instance_ipDestroy when done:
terraform destroy| Module | Purpose | Inputs | Outputs |
|---|---|---|---|
modules/vpc |
Creates VPC | None | vpc_id |
modules/subnet |
Creates subnet | vpc_id |
subnet_id |
modules/igw |
Creates internet gateway | vpc_id |
igw_id |
modules/route-table |
Route table + association | vpc_id, igw_id, subnet_id |
None |
modules/security-group |
Security group rules | vpc_id |
sg_id |
modules/keypair |
Generates key pair + PEM | None | key_name, private_key_path |
modules/ec2 |
Creates EC2 instance | subnet_id, sg_id, key_name |
instance_ip |
Top-level Terraform output:
instance_ip: EC2 public IP
- Jenkins agent/node with:
terraforminstalled and available inPATHssh,git, and basic Linux tools- Optional:
tflint,tfsec
- Recommended Jenkins plugins:
- Pipeline
- Credentials Binding
- ANSI Color
- Timestamper
- Git
The pipeline expects these credential IDs in Jenkins:
aws-access-keygithub-pat-token-id
Important:
- Verify the AWS credential mapping in
Jenkinsfileto ensureAWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEYare sourced correctly for your credential type. - If your Jenkins credential IDs differ, update the IDs in
Jenkinsfile.
- Create a Pipeline or Multibranch Pipeline job in Jenkins.
- Point SCM to this repository.
- Use
Jenkinsfileat repo root as pipeline script. - Save and run build.
- Checkout source
terraform fmt -check -recursiveterraform initandterraform validate- Optional lint/security checks (
tflint,tfsec) terraform plan -out=tfplan.binary- Archive plan as
tfplan.txt - Pause for manual approval
terraform apply -auto-approve tfplan.binary- Read
instance_ipoutput - SSH to EC2 using generated PEM and deploy app
After successful build:
- Open build artifacts and inspect
tfplan.txt. - Approve manual gate when ready.
- Confirm pipeline logs show fetched
INSTANCE_IP. - Validate app on
http://<INSTANCE_IP>:9090.
- Keep
my-ec2-key.pemout of source control. - Restrict who can approve the manual apply stage.
- Consider splitting deploy and infrastructure apply into separate jobs for production.
- Inbound
22,80, and9090are open to0.0.0.0/0; restrict to trusted CIDRs for real environments. - PEM file generated at
modules/keypair/my-ec2-key.pemis sensitive. - Use least-privilege IAM policies for Terraform/Jenkins.
- Rotate AWS and GitHub credentials regularly.
.terraform/
*.tfstate
*.tfstate.*
*.tfplan
tfplan.binary
modules/keypair/*.pem
crash.log- Confirm S3 bucket
remote-backendexists inus-west-2. - Confirm DynamoDB lock table
terraform-locksexists and is accessible.
- Confirm inbound port
22is allowed from your source IP. - Confirm PEM file permissions are
0400. - Confirm instance is in running state and has a public IP.
- Confirm security group allows inbound
9090. - Confirm Java process is running on EC2.
- Check app logs generated by deployment script (
app.log).