Skip to content

Commit 5313ae5

Browse files
Merge pull request #1 from CloudNinjaDev/infra
Add Terraform CI/CD workflows and MongoDB infrastructure setup
2 parents 32760c6 + b01bb5b commit 5313ae5

6 files changed

Lines changed: 462 additions & 0 deletions

File tree

.github/workflows/cd.yml

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
name: Terraform CD
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'terraform/**'
9+
- '.github/workflows/cd.yml'
10+
11+
workflow_dispatch:
12+
inputs:
13+
plan_only:
14+
description: 'Run plan only (no apply)'
15+
required: false
16+
default: 'false'
17+
type: choice
18+
options:
19+
- 'true'
20+
- 'false'
21+
22+
destroy:
23+
description: 'Destroy all infrastructure (DANGEROUS)'
24+
required: false
25+
default: 'false'
26+
type: choice
27+
options:
28+
- 'true'
29+
- 'false'
30+
31+
permissions:
32+
contents: read
33+
id-token: write
34+
issues: write
35+
36+
env:
37+
AWS_REGION: us-west-2
38+
TF_WORKING_DIR: terraform
39+
TERRAFORM_VERSION: 1.6.0
40+
41+
jobs:
42+
terraform-plan:
43+
name: Plan Infrastructure Changes
44+
runs-on: ubuntu-latest
45+
46+
environment:
47+
name: production
48+
49+
defaults:
50+
run:
51+
working-directory: ${{ env.TF_WORKING_DIR }}
52+
53+
outputs:
54+
has_changes: ${{ steps.plan.outputs.exitcode == 2 }}
55+
56+
steps:
57+
- name: Checkout Code
58+
uses: actions/checkout@v4
59+
60+
- name: Configure AWS Credentials
61+
uses: aws-actions/configure-aws-credentials@v4
62+
with:
63+
aws-access-key-id: ${{ secrets.AWS_SECRET_ACCESS_ID }}
64+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
65+
aws-region: ${{ env.AWS_REGION }}
66+
67+
- name: Setup Terraform
68+
uses: hashicorp/setup-terraform@v3
69+
with:
70+
terraform_version: ${{ env.TERRAFORM_VERSION }}
71+
terraform_wrapper: false
72+
73+
- name: Terraform Format Check
74+
run: terraform fmt -check -recursive
75+
76+
- name: Terraform Init
77+
run: terraform init -upgrade
78+
79+
- name: Terraform Validate
80+
run: terraform validate
81+
82+
- name: Terraform Plan
83+
id: plan
84+
run: |
85+
terraform plan -detailed-exitcode -out=tfplan -input=false || exit_code=$?
86+
echo "exitcode=$exit_code" >> $GITHUB_OUTPUT
87+
terraform show tfplan -no-color
88+
continue-on-error: true
89+
90+
- name: Upload Plan Artifact
91+
if: steps.plan.outputs.exitcode == 2
92+
uses: actions/upload-artifact@v4
93+
with:
94+
name: terraform-plan-${{ github.sha }}
95+
path: ${{ env.TF_WORKING_DIR }}/tfplan
96+
retention-days: 1
97+
98+
- name: Create Deployment Summary
99+
if: always()
100+
run: |
101+
echo "## Terraform Plan Summary" >> $GITHUB_STEP_SUMMARY
102+
echo "" >> $GITHUB_STEP_SUMMARY
103+
echo "- **Workflow:** ${{ github.workflow }}" >> $GITHUB_STEP_SUMMARY
104+
echo "- **Triggered by:** ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
105+
echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
106+
echo "- **Plan Status:** ${{ steps.plan.outcome }}" >> $GITHUB_STEP_SUMMARY
107+
echo "- **Has Changes:** ${{ steps.plan.outputs.exitcode == 2 }}" >> $GITHUB_STEP_SUMMARY
108+
109+
terraform-apply:
110+
name: Apply Infrastructure Changes
111+
runs-on: ubuntu-latest
112+
113+
needs: terraform-plan
114+
if: |
115+
needs.terraform-plan.result == 'success' &&
116+
needs.terraform-plan.outputs.has_changes == 'true' &&
117+
github.event.inputs.plan_only != 'true'
118+
119+
defaults:
120+
run:
121+
working-directory: ${{ env.TF_WORKING_DIR }}
122+
123+
steps:
124+
- name: Checkout Code
125+
uses: actions/checkout@v4
126+
127+
- name: Configure AWS Credentials
128+
uses: aws-actions/configure-aws-credentials@v4
129+
with:
130+
aws-access-key-id: ${{ secrets.AWS_SECRET_ACCESS_ID }}
131+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
132+
aws-region: ${{ env.AWS_REGION }}
133+
134+
- name: Setup Terraform
135+
uses: hashicorp/setup-terraform@v3
136+
with:
137+
terraform_version: ${{ env.TERRAFORM_VERSION }}
138+
139+
- name: Terraform Init
140+
run: terraform init -upgrade
141+
142+
- name: Download Plan Artifact
143+
uses: actions/download-artifact@v4
144+
with:
145+
name: terraform-plan-${{ github.sha }}
146+
path: ${{ env.TF_WORKING_DIR }}
147+
148+
- name: Terraform Apply
149+
id: apply
150+
run: |
151+
echo "Applying Terraform changes..."
152+
terraform apply -auto-approve -input=false tfplan
153+
154+
- name: Get Terraform Outputs
155+
id: outputs
156+
if: steps.apply.outcome == 'success'
157+
run: |
158+
echo "instance_id=$(terraform output -raw instance_id)" >> $GITHUB_OUTPUT
159+
echo "instance_public_ip=$(terraform output -raw instance_public_ip)" >> $GITHUB_OUTPUT
160+
echo "instance_private_ip=$(terraform output -raw instance_private_ip)" >> $GITHUB_OUTPUT
161+
162+
- name: Create Deployment Summary
163+
if: always()
164+
run: |
165+
echo "## Terraform Apply Summary" >> $GITHUB_STEP_SUMMARY
166+
echo "" >> $GITHUB_STEP_SUMMARY
167+
echo "- **Workflow:** ${{ github.workflow }}" >> $GITHUB_STEP_SUMMARY
168+
echo "- **Triggered by:** ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
169+
echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
170+
echo "- **Apply Status:** ${{ steps.apply.outcome }}" >> $GITHUB_STEP_SUMMARY
171+
172+
if [ "${{ steps.apply.outcome }}" == "success" ]; then
173+
echo "" >> $GITHUB_STEP_SUMMARY
174+
echo "### EC2 Instance Information" >> $GITHUB_STEP_SUMMARY
175+
echo "- **Instance ID:** ${{ steps.outputs.outputs.instance_id }}" >> $GITHUB_STEP_SUMMARY
176+
echo "- **Public IP:** ${{ steps.outputs.outputs.instance_public_ip }}" >> $GITHUB_STEP_SUMMARY
177+
echo "- **Private IP:** ${{ steps.outputs.outputs.instance_private_ip }}" >> $GITHUB_STEP_SUMMARY
178+
echo "" >> $GITHUB_STEP_SUMMARY
179+
echo "### Connect to Instance" >> $GITHUB_STEP_SUMMARY
180+
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
181+
echo "ssh -i ~/.ssh/ashish-test-kp.pem ec2-user@${{ steps.outputs.outputs.instance_public_ip }}" >> $GITHUB_STEP_SUMMARY
182+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
183+
fi
184+
185+
- name: Notify on Failure
186+
if: failure()
187+
run: |
188+
echo "::error::Terraform apply failed. Please check the logs and fix the issues."
189+
190+
terraform-destroy:
191+
name: Destroy Infrastructure
192+
runs-on: ubuntu-latest
193+
194+
if: github.event_name == 'workflow_dispatch' && github.event.inputs.destroy == 'true'
195+
196+
environment:
197+
name: destroy-production
198+
199+
defaults:
200+
run:
201+
working-directory: ${{ env.TF_WORKING_DIR }}
202+
203+
steps:
204+
- name: Checkout Code
205+
uses: actions/checkout@v4
206+
207+
- name: Configure AWS Credentials
208+
uses: aws-actions/configure-aws-credentials@v4
209+
with:
210+
aws-access-key-id: ${{ secrets.AWS_SECRET_ACCESS_ID }}
211+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
212+
aws-region: ${{ env.AWS_REGION }}
213+
214+
- name: Setup Terraform
215+
uses: hashicorp/setup-terraform@v3
216+
with:
217+
terraform_version: ${{ env.TERRAFORM_VERSION }}
218+
219+
- name: Terraform Init
220+
run: terraform init -upgrade
221+
222+
- name: Terraform Destroy
223+
run: |
224+
echo "Destroying all infrastructure..."
225+
terraform destroy -auto-approve -input=false
226+
227+
- name: Confirm Destruction
228+
run: |
229+
echo "## Infrastructure Destroyed" >> $GITHUB_STEP_SUMMARY
230+
echo "" >> $GITHUB_STEP_SUMMARY
231+
echo "All resources have been destroyed." >> $GITHUB_STEP_SUMMARY
232+
echo "- **Triggered by:** ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
233+
echo "- **Timestamp:** $(date)" >> $GITHUB_STEP_SUMMARY

.github/workflows/ci.yml

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
name: Terraform CI
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- '**'
7+
paths:
8+
- 'terraform/**'
9+
- '.github/workflows/ci.yml'
10+
11+
push:
12+
branches:
13+
- '**'
14+
- '!main'
15+
paths:
16+
- 'terraform/**'
17+
- '.github/workflows/ci.yml'
18+
19+
permissions:
20+
contents: read
21+
pull-requests: write
22+
issues: write
23+
24+
env:
25+
AWS_REGION: us-west-2
26+
TF_WORKING_DIR: terraform
27+
TERRAFORM_VERSION: 1.6.0
28+
29+
jobs:
30+
terraform-validate:
31+
name: Validate Terraform Configuration
32+
runs-on: ubuntu-latest
33+
34+
defaults:
35+
run:
36+
working-directory: ${{ env.TF_WORKING_DIR }}
37+
38+
steps:
39+
- name: Checkout Code
40+
uses: actions/checkout@v4
41+
42+
- name: Configure AWS Credentials
43+
uses: aws-actions/configure-aws-credentials@v4
44+
with:
45+
aws-access-key-id: ${{ secrets.AWS_SECRET_ACCESS_ID }}
46+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
47+
aws-region: ${{ env.AWS_REGION }}
48+
49+
- name: Setup Terraform
50+
uses: hashicorp/setup-terraform@v3
51+
with:
52+
terraform_version: ${{ env.TERRAFORM_VERSION }}
53+
54+
- name: Terraform Format Check
55+
id: fmt
56+
run: terraform fmt -check -recursive
57+
continue-on-error: true
58+
59+
- name: Terraform Init
60+
id: init
61+
run: terraform init -upgrade -backend=false
62+
63+
- name: Terraform Validate
64+
id: validate
65+
run: terraform validate -no-color
66+
67+
- name: Terraform Plan
68+
id: plan
69+
run: |
70+
terraform init -upgrade
71+
terraform plan -no-color -input=false -out=tfplan
72+
continue-on-error: true
73+
74+
- name: Post Plan to PR
75+
if: github.event_name == 'pull_request'
76+
uses: actions/github-script@v7
77+
env:
78+
PLAN_OUTPUT: ${{ steps.plan.outputs.stdout }}
79+
with:
80+
github-token: ${{ secrets.GITHUB_TOKEN }}
81+
script: |
82+
const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\`
83+
#### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
84+
#### Terraform Validation 🤖\`${{ steps.validate.outcome }}\`
85+
#### Terraform Plan 📖\`${{ steps.plan.outcome }}\`
86+
87+
<details><summary>Show Plan</summary>
88+
89+
\`\`\`terraform
90+
${{ steps.plan.outputs.stdout }}
91+
\`\`\`
92+
93+
</details>
94+
95+
*Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`, Workflow: \`${{ github.workflow }}\`*`;
96+
97+
github.rest.issues.createComment({
98+
issue_number: context.issue.number,
99+
owner: context.repo.owner,
100+
repo: context.repo.repo,
101+
body: output
102+
});
103+
104+
- name: Check Plan Status
105+
if: steps.plan.outcome == 'failure'
106+
run: exit 1
107+
108+
- name: Upload Plan Artifact
109+
if: steps.plan.outcome == 'success'
110+
uses: actions/upload-artifact@v4
111+
with:
112+
name: terraform-plan
113+
path: ${{ env.TF_WORKING_DIR }}/tfplan
114+
retention-days: 5
115+
116+
terraform-security-scan:
117+
name: Security Scan
118+
runs-on: ubuntu-latest
119+
120+
steps:
121+
- name: Checkout Code
122+
uses: actions/checkout@v4
123+
124+
- name: Run tfsec
125+
uses: aquasecurity/tfsec-action@v1.0.3
126+
with:
127+
working_directory: ${{ env.TF_WORKING_DIR }}
128+
soft_fail: true

0 commit comments

Comments
 (0)