Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
bb03c7e
CI OIDC Test and README for the REPO
OngeziweM5 Oct 26, 2025
c30f22f
Merge pull request #1 from OngeziweM5/oidc-gh-aws-test
OngeziweM5 Oct 26, 2025
1055245
Bootstrap Terraform backend (S3 + DynamoDB lock)
OngeziweM5 Oct 27, 2025
4e0b03c
Merge pull request #2 from OngeziweM5/tf-bootstrap
OngeziweM5 Oct 27, 2025
26fd090
feat(dev-setup): add Terraform setup for development environment with…
OngeziweM5 Oct 27, 2025
9ca9241
Merge pull request #3 from OngeziweM5/tf-dev-initial-setup
OngeziweM5 Oct 27, 2025
ca44b31
feat(ci-setup) Terraform validation and plan preview workflow"
OngeziweM5 Oct 27, 2025
a9dd4b9
style(terraform): format terraform files to pass ci fmt check
OngeziweM5 Oct 27, 2025
061ebbf
Configure AWS credentials in Terraform workflow
OngeziweM5 Oct 27, 2025
28c3e2a
Update permissions in terraform-validate workflow
OngeziweM5 Oct 27, 2025
08137d3
Add pull-requests permission(write) to workflow
OngeziweM5 Oct 27, 2025
afc66d7
Merge pull request #4 from OngeziweM5/tf-validation-ci
OngeziweM5 Oct 27, 2025
a081b0e
Configure Terraform environment directory based on branch
OngeziweM5 Oct 27, 2025
b1fa61d
Merge pull request #5 from OngeziweM5/tf-ci-environment-plan
OngeziweM5 Oct 27, 2025
fca54dd
Updated the tf deploy workflow
OngeziweM5 Oct 27, 2025
5716098
Merge pull request #6 from OngeziweM5/tf-ci-environment-plan
OngeziweM5 Oct 27, 2025
29e5ec7
feat(tf-networks-ec2-dev): update development environment configurati…
OngeziweM5 Oct 29, 2025
aeb0393
terraform fmt on modules
OngeziweM5 Oct 29, 2025
51a6137
Enable DEBUG logging for Terraform Plan
OngeziweM5 Oct 29, 2025
b368fa3
updated the terraform-plan job and backend.hcl
OngeziweM5 Oct 29, 2025
2be6207
updated the terraform-setup version to use default (latest)
OngeziweM5 Oct 29, 2025
ae2d993
Added tf vars for tf plan
OngeziweM5 Oct 29, 2025
056300d
Updated the ec2 module aws ami for cpt
OngeziweM5 Oct 29, 2025
700548a
Add environment variables for Terraform Plan
OngeziweM5 Oct 29, 2025
dfdaba0
Refactor secret access to use format function
OngeziweM5 Oct 29, 2025
7fe66f6
Refactor Terraform secrets handling for environments
OngeziweM5 Oct 29, 2025
45c98e5
Refactor Terraform workflow and add apply step
OngeziweM5 Oct 29, 2025
aa2f75a
Remove Terraform version specification in workflow
OngeziweM5 Oct 29, 2025
558e219
Merge pull request #7 from OngeziweM5/tf-network-ec2-setup
OngeziweM5 Oct 29, 2025
1e73cbf
feat(tf-ec2-setup) Adding ssh to ec2 and Elastic IP
OngeziweM5 Oct 30, 2025
b9bb85e
Patching the ssh issue onto the ec2 instance
OngeziweM5 Oct 30, 2025
6d3f50e
interminent ssh issues fix
OngeziweM5 Oct 30, 2025
d465898
Add SSH and API CIDR variables to Terraform workflow
OngeziweM5 Oct 30, 2025
7f0bf14
Add allowed SSH and API CIDRs to Terraform deploy
OngeziweM5 Oct 30, 2025
d9f22f7
Fix syntax error in terraform-validate.yml
OngeziweM5 Oct 30, 2025
d6e6cce
syntax issue update on ci ref of ALLOWEDSSH and PI CIDRS
OngeziweM5 Oct 30, 2025
5aa81b8
Syntax issue of CI for ref secrets
OngeziweM5 Oct 30, 2025
8cd406b
Update terraform-validate workflow triggers
OngeziweM5 Oct 30, 2025
a453789
Adding pub key for ec2 ssh setup
OngeziweM5 Oct 30, 2025
5148266
resolving reference to unknown resource error
OngeziweM5 Oct 30, 2025
3ad8280
set work dir on tf deploy workflow for plan output and added a depend…
OngeziweM5 Oct 30, 2025
431f9dd
resolving the 'file not found error' on tf deploy workflow
OngeziweM5 Oct 31, 2025
a37903c
Refactor README for clarity and structure
OngeziweM5 Oct 31, 2025
263c708
Fix formatting in README.md for repository structure
OngeziweM5 Oct 31, 2025
d86b41d
user management + SSH key-based access automation on the bash script
OngeziweM5 Oct 31, 2025
5e3b07a
Merge branch 'tf-ec2-ssh-elastic-ip-setup' of https://github.com/Onge…
OngeziweM5 Oct 31, 2025
d166f7b
Updated SSH key-based access automation on the bash script
OngeziweM5 Nov 1, 2025
ed95384
Updated SSH key-based access automation on the bash script
OngeziweM5 Nov 1, 2025
3c7f292
Updated SSH key-based access automation on the bash script. v.3
OngeziweM5 Nov 1, 2025
c5ee3a5
Updated secrets module and dev env secrets
OngeziweM5 Nov 2, 2025
e191ca9
Updated secrets module and dev env secrets v2
OngeziweM5 Nov 2, 2025
016652c
Update user-data.ssh to install docker compose on ec2 instance
OngeziweM5 Nov 2, 2025
bd481ae
Update user-data.ssh to install docker and docker compose on ec2 inst…
OngeziweM5 Nov 2, 2025
e18a1fd
Update user-data.ssh to install docker and docker compose on ec2 inst…
OngeziweM5 Nov 2, 2025
e8e19d4
Update user-data.ssh to install docker and docker compose on ec2 inst…
OngeziweM5 Nov 2, 2025
0e33100
Update user-data.ssh, prepping api dir
OngeziweM5 Nov 3, 2025
31f7c8b
Update user-data.ssh, prepping api dir v2
OngeziweM5 Nov 3, 2025
e2977da
Upping ec2 instance resource to run sql-server (require 2GB RAM and m…
OngeziweM5 Nov 4, 2025
6498c9e
Upping ec2 instance to t3.small
OngeziweM5 Nov 4, 2025
ab9180f
adding a swapfile for 1GB more on the t3.small instance
OngeziweM5 Nov 4, 2025
a67f656
Update the README, testing the worklfows
ongeziwe17 Nov 11, 2025
3c0afd8
Updated the infrastructure for adding frontend infra
ongeziwe17 Nov 12, 2025
7d599ee
Missed the dir setup to point to dev backend
ongeziwe17 Nov 12, 2025
726afef
Missed the dir setup to point to modules from dev backend
ongeziwe17 Nov 12, 2025
6ba7696
Adjust backend.hcl for dev
ongeziwe17 Nov 12, 2025
6bb1995
Update secrets and vars in secrest module
ongeziwe17 Nov 12, 2025
b20b369
Update secrets and vars in secrest module vv2
ongeziwe17 Nov 12, 2025
40dd144
Update deploy infra workflow to use matching state from aws
ongeziwe17 Nov 12, 2025
57106b9
Update deploy infra workflow env vars for s3 bucket name and path
ongeziwe17 Nov 12, 2025
b748906
Update deploy infra workflow env tf-vars for s3 bucket name and path
ongeziwe17 Nov 12, 2025
f65dcf9
Update deploy infra workflow env backend config vars for s3 bucket na…
ongeziwe17 Nov 12, 2025
b3e009b
Updated Import Pre-existing AWS Resources Step
ongeziwe17 Nov 12, 2025
22af1bd
Updated Import Pre-existing AWS Resources Step v2
ongeziwe17 Nov 12, 2025
8c283db
Update script to install git
ongeziwe17 Nov 12, 2025
7f02730
Deploy workflow condition to run import when needed
ongeziwe17 Nov 12, 2025
be62d01
Add infrastructure for frontend
ongeziwe17 Nov 12, 2025
c262dca
Fix Duplicate output definition for backend and frontend
ongeziwe17 Nov 12, 2025
8e4119e
Fix Duplicate output definition for backend and frontend
ongeziwe17 Nov 12, 2025
5219ed7
Fix Invalid function argument in the compute-ec2 module pointing to u…
ongeziwe17 Nov 12, 2025
fd5270f
Reference ws_ssm_parameter resources as a list
ongeziwe17 Nov 12, 2025
b64753c
Commented out declared vars but unused
ongeziwe17 Nov 12, 2025
a1a250e
sa_password, redis_password, and admin_key not used for frontend
ongeziwe17 Nov 12, 2025
dcd482d
backend provider random id and allowed_ssh_cidrs on network
ongeziwe17 Nov 12, 2025
852adf2
Add header for each dev backend and frontend for tf plan and work dir…
ongeziwe17 Nov 12, 2025
0d26df1
Update all env_dir and S3 key paths to use development
ongeziwe17 Nov 12, 2025
b7b9caa
Fix ssh key re-create same key issue for 2 envs, instead re-use
ongeziwe17 Nov 12, 2025
90664d4
Each environment (development, staging, production) runs only when it…
ongeziwe17 Nov 12, 2025
2c2948f
Terraform fmt modules\compute-ec2\main.tf
ongeziwe17 Nov 12, 2025
1f96af2
Use count directly on the EC2 resource
ongeziwe17 Nov 12, 2025
6879ad9
Use count directly on the EC2 resource
ongeziwe17 Nov 12, 2025
1f3e204
add 8081 to Terraform security group for cms
ongeziwe17 Nov 14, 2025
e3574ec
add 8081 to Terraform security group for cms V2
ongeziwe17 Nov 14, 2025
8111e52
add 8081 to Terraform security group for cms V3
ongeziwe17 Nov 14, 2025
ec02316
Updated the backend.hcl to include the lock file
ongeziwe17 Dec 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions .github/workflows/terraform-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
name: Terraform Deploy

on:
push:
branches: [main, staging, develop]

workflow_dispatch:
inputs:
import:
description: 'Import existing resources into Terraform state'
required: false
default: false
type: boolean

permissions:
id-token: write
contents: read
pull-requests: write

# ───────────────────────────────────────────────
# DEVELOPMENT JOB
# ───────────────────────────────────────────────
jobs:
deploy-development:
name: Deploy Infrastructure (development)
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/develop'
strategy:
fail-fast: false
matrix:
# env: [development, staging, production]
stack: [backend, frontend]
environment: development

steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.IAM_INFRA_ROLE_ID }}:role/flagging-infra-ci
aws-region: ${{ secrets.AWS_REGION }}

- name: Verify AWS access
run: aws sts get-caller-identity

- name: Set up Terraform
uses: hashicorp/setup-terraform@v3

- name: Set paths
id: paths
run: |
echo "env_dir=environments/development/${{ matrix.stack }}" >> $GITHUB_OUTPUT
echo "s3_key=environments/development/${{ matrix.stack }}/terraform.tfstate" >> $GITHUB_OUTPUT

- name: Terraform Init
run: |
terraform -chdir=${{ steps.paths.outputs.env_dir }} init -reconfigure \
-backend-config="bucket=${{ secrets.S3_BUCKET_NAME }}" \
-backend-config="key=${{ steps.paths.outputs.s3_key }}" \
-backend-config="region=${{ secrets.AWS_REGION }}" \
-backend-config="encrypt=true"

- name: Terraform Plan & Apply
run: |
terraform -chdir=${{ steps.paths.outputs.env_dir }} plan -out=tfplan
terraform -chdir=${{ steps.paths.outputs.env_dir }} apply -auto-approve tfplan
env:
TF_VAR_allowed_ssh_cidrs: ${{ secrets.ALLOWED_SSH_CIDRS }}
TF_VAR_allowed_api_cidrs: ${{ secrets.ALLOWED_API_CIDRS }}
TF_VAR_allowed_cms_cidrs: ${{ secrets.ALLOWED_CMS_CIDRS }}
TF_VAR_ghcr_token: ${{ secrets.GHCR_PAT }}
TF_VAR_admin_key: ${{ matrix.stack == 'backend' && secrets.ADMIN_KEY_DEV || '' }}
TF_VAR_sa_password: ${{ matrix.stack == 'backend' && secrets.SA_PASSWORD_DEV || '' }}
TF_VAR_redis_password: ${{ matrix.stack == 'backend' && secrets.REDIS_PASSWORD_DEV || '' }}

# ───────────────────────────────────────────────
# STAGING JOB
# ───────────────────────────────────────────────
deploy-staging:
name: Deploy Infrastructure (staging)
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/staging'
strategy:
fail-fast: false
matrix:
stack: [backend, frontend]
environment: staging

steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.IAM_INFRA_ROLE_ID }}:role/flagging-infra-ci
aws-region: ${{ secrets.AWS_REGION }}

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3

- name: Terraform Plan
run: |
terraform -chdir=environments/staging/${{ matrix.stack }} init -reconfigure \
-backend-config="bucket=${{ secrets.S3_BUCKET_NAME }}" \
-backend-config="key=environments/staging/${{ matrix.stack }}/terraform.tfstate" \
-backend-config="region=${{ secrets.AWS_REGION }}" \
-backend-config="encrypt=true"
terraform -chdir=environments/staging/${{ matrix.stack }} plan -no-color

# ───────────────────────────────────────────────
# PRODUCTION JOB
# ───────────────────────────────────────────────
deploy-production:
name: Deploy Infrastructure (production)
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
strategy:
fail-fast: false
matrix:
stack: [backend, frontend]
environment: production

steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.IAM_INFRA_ROLE_ID }}:role/flagging-infra-ci
aws-region: ${{ secrets.AWS_REGION }}

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3

- name: Terraform Plan
run: |
terraform -chdir=environments/production/${{ matrix.stack }} init -reconfigure \
-backend-config="bucket=${{ secrets.S3_BUCKET_NAME }}" \
-backend-config="key=environments/production/${{ matrix.stack }}/terraform.tfstate" \
-backend-config="region=${{ secrets.AWS_REGION }}" \
-backend-config="encrypt=true"
terraform -chdir=environments/production/${{ matrix.stack }} plan -no-color
116 changes: 116 additions & 0 deletions .github/workflows/terraform-validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
name: Terraform Validation

on:
pull_request:
branches: [main, staging, develop]

workflow_dispatch: {}

permissions:
id-token: write
contents: read
pull-requests: write

jobs:
terraform-validation:
name: Validate Terraform configuration
runs-on: ubuntu-latest
strategy:
matrix:
stack: [backend, frontend]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3

- name: Terraform Format Check
run: terraform fmt -check -recursive

- name: Terraform Init (development env)
working-directory: environments/development/${{ matrix.stack }}
run: terraform init -backend=false

- name: Terraform Validate
working-directory: environments/development/${{ matrix.stack }}
run: terraform validate

- name: Terraform Lint
uses: terraform-linters/setup-tflint@v6
with:
tflint_version: v0.52.0

- name: Run TFLint in stack dir
working-directory: environments/development/${{ matrix.stack }}
run: |
tflint --init
tflint

- name: Summary
run: echo "Terraform syntax and lint checks completed successfully."

terraform-plan:
name: Terraform Plan (${{ matrix.stack }})
runs-on: ubuntu-latest
strategy:
matrix:
stack: [backend, frontend]
needs: terraform-validation
if: github.event_name == 'pull_request'

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: arn:aws:iam::${{ secrets.IAM_INFRA_ROLE_ID }}:role/flagging-infra-ci
aws-region: ${{ secrets.AWS_REGION }}

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3

- name: Terraform Init (with backend)
working-directory: environments/development/${{ matrix.stack }}
run: terraform init -backend-config=backend.hcl

- name: Terraform Plan (${{ matrix.stack }})
id: plan
working-directory: environments/development/${{ matrix.stack }}
env:
TF_VAR_admin_key: ${{ matrix.stack == 'backend' && secrets.ADMIN_KEY_DEV || '' }}
TF_VAR_sa_password: ${{ matrix.stack == 'backend' && secrets.SA_PASSWORD_DEV || '' }}
TF_VAR_redis_password: ${{ matrix.stack == 'backend' && secrets.REDIS_PASSWORD_DEV || '' }}
TF_VAR_ghcr_token: ${{ secrets.GHCR_PAT }}
TF_VAR_allowed_ssh_cidrs: ${{ secrets.ALLOWED_SSH_CIDRS }}
TF_VAR_allowed_api_cidrs: ${{ secrets.ALLOWED_API_CIDRS }}
TF_VAR_allowed_cms_cidrs: ${{ secrets.ALLOWED_CMS_CIDRS }}
TF_LOG: DEBUG
run: terraform plan -no-color -out=tfplan


- name: Save Plan Output
working-directory: environments/development/${{ matrix.stack }}
run: terraform show -no-color tfplan > plan-${{ matrix.stack }}.txt

- name: Upload Plan as Artifact
uses: actions/upload-artifact@v4
with:
name: terraform-plan ${{ matrix.stack }}
path: environments/development/${{ matrix.stack }}/plan-${{ matrix.stack }}.txt

- name: Comment Plan on PR
uses: marocchino/sticky-pull-request-comment@v2
with:
header: "Terraform Plan – ${{ matrix.stack }}"
path: environments/development/${{ matrix.stack }}/plan-${{ matrix.stack }}.txt

- name: Force unlock on failure
if: failure()
working-directory: environments/development/${{ matrix.stack }}
run: |
echo "Attempting to remove Terraform lock..."
terraform force-unlock -force $(terraform show -json | jq -r '.lock.id') || true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Local .terraform directories
.terraform/
.terraform.lock.hcl

# .tfstate files
*.tfstate
Expand Down
111 changes: 110 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,110 @@
# flagging-infrastructure
# Feature Flags Infrastructure

This repository manages the **cloud infrastructure** for the **Feature Flags Platform**, which includes:

- The **backend API** (built with .NET)
- The **frontend dashboard** (built with Vue.js)
- Supporting services such as **Redis** and **SQL Server**

All infrastructure is defined using **Terraform (Infrastructure as Code)** and deployed to **AWS**.

---

## Repository Structure
```
feature-flags-infra/
├── .github/workflows/ # CI/CD automation for Terraform and deployments
├── bootstrap/ # One-time setup for remote Terraform state (S3 + DynamoDB to keep infrastructure state consistent)
├── environments/ # Per-environment Terraform configurations
│ ├── development/ # Dev environment (testing, internal usage)
│ ├── staging/ # Staging environment (QA, integration)
│ └── production/ # Production environment (Production deployment)
├── modules/ # Reusable Terraform modules
│ ├── compose/ # Handles Docker Compose deployments on EC2
│ ├── compute-ec2/ # Provisions EC2 instances and security groups
│ ├── dns/ # Manages DNS records, SSL certs, and optional load balancer
│ ├── network/ # Creates VPCs, subnets, and networking resources
│ └── secrets/ # Manages sensitive data
├── scripts/ # Helper shell scripts for rendering, deployment, and SSM commands
└── templates/ # Template files (e.g., docker-compose.yaml) used for deployments
```
---

## Key Concepts

| **Component** | **Description** |
|--------------------|------------------------------------------------------------------------|
| **Terraform** | Used to define, provision, and manage AWS resources. |
| **AWS EC2** | Hosts Docker Compose deployments for API + Frontend containers. |
| **AWS SSM** | Enables secure, keyless remote commands and configuration. |
| **Docker Compose** | Orchestrates multi-container setup (API, Frontend, Redis, SQL Server). |
| **GitHub Actions** | Automates build, plan, and deploy workflows across environments. |

---

## ⚙️ How It Works

1. **API & Frontend Repositories**
- Build and push Docker images to **GitHub Container Registry (GHCR)**.
- Trigger a `repository_dispatch` event to this infrastructure repository.

2. **Infrastructure Repository**
- Terraform provisions AWS resources per environment (**Development**, **Staging**, **Production**).
- AWS **SSM** executes deployment commands on EC2 instances such as:

```text
docker compose pull && docker compose up -d
```

3. **Environment Isolation**
- Each environment has its own **Terraform state**, **variables**, and **resource set**.
- Promoting changes is done by merging `develop → staging → main`.

---

## Environments and branches

| **Environment** | **Branch** | **Purpose** | **Trigger** |
|------------------|------------|--------------|----------------------------------------|
| 🧪 Development | `develop` | Active feature testing | On merge to `develop` |
| 🚀 Staging | `staging` | QA and pre-production testing | On merge to `staging` |
| 🏆 Production | `main` | Live production deployment | On merge to `main` |

---

## Typical Workflow

### Bootstrap Terraform Remote State

Used to create the S3 bucket and DynamoDB table for Terraform state management.

```bash
cd bootstrap
terraform init
terraform apply -auto-approve

cd environments/development
terraform init -backend-config=backend.hcl
terraform apply -auto-approve
```

## Promote to Staging / Production

Merge develop → staging → main

GitHub Actions automatically runs terraform apply for each environment

## Notes for Contributors

Each environment is fully isolated and can be applied independently.

Never commit AWS credentials — use GitHub OIDC authentication for Terraform.

Keep module logic reusable; environment folders should only contain configuration.

Use tags (e.g., Project, Env) on all resources for cost tracking and organization.
Loading