Automated deployment of Gatus health monitoring to AWS ECS Fargate with security scanning and CI/CD.
Deploys Gatus, a health monitoring application, to AWS using containers. When I push code to GitHub, it automatically:
- Builds a secure container image
- Scans it for vulnerabilities
- Deploys it to AWS
- Makes it accessible at a custom domain
I wanted to learn platform engineering by building something real, not following tutorials. This project combines:
- Infrastructure as Code
- CI/CD pipelines
- Container security
- AWS networking
Without this automation, deploying would require manual steps every time — error-prone and slow.
- Push code to GitHub — triggers the pipeline automatically
- Build and scan — creates a container image, checks for security vulnerabilities
- Deploy infrastructure — Terraform creates the AWS resources needed
- Gatus goes live — accessible at tm.elsagatus.com behind a load balancer
- Two-layer architecture: Persistent resources (identity, registry) separated from ephemeral compute — can destroy and recreate without breaking CI/CD
- Security scanning: Trivy scans containers for CVEs, Checkov scans infrastructure code for misconfigurations
- No static credentials: Uses OIDC for GitHub Actions to assume AWS roles — no access keys to leak
- Immutable image tags: Container images can't be overwritten — prevents supply chain attacks
- Automated dependency updates: Dependabot watches Terraform, Docker, and GitHub Actions versions
- Manual approval gates: Production deployments require explicit approval via GitHub Environments — prevents accidental infrastructure changes
- WAF protection: Rate limiting and AWS managed rules for common attacks and SQL injection
- CloudWatch monitoring: Alarms for ECS CPU/memory, ALB latency (p99), unhealthy hosts, with email alerts via SNS
- Disaster recovery: Documented recovery procedure for persistent layer rebuild
- Terraform: Infrastructure as code — reproducible, version-controlled AWS resources
- GitHub Actions: CI/CD that integrates with my repo — no separate CI server needed
- AWS ECS Fargate: Serverless containers — no EC2 instances to manage
- OIDC authentication: Industry standard for secure CI/CD — recommended by AWS and GitHub
- Trivy + Checkov: Open source security scanners — catches vulnerabilities before deployment
Modular Terraform structure: VPC with public/private subnets, ALB in public, ECS Fargate in private, security groups restricting traffic flow. Remote state links to persistent layer (OIDC, ECR, ACM, Route 53 zone)
- AWS account with appropriate permissions
- Terraform >= 1.0
- GitHub repository
- Domain name with Route 53 hosted zone
# Clone the repository
git clone https://github.com/ElsaDevOps/Gatus-ECS.git
cd Gatus-ECS
# Apply persistent layer first (one-time setup)
cd infrastructure/persistent
terraform init
terraform apply
# Ephemeral layer is applied via CI/CD on push to main
### Running the Project
Push to `main` branch triggers automatic deployment.
To manually destroy ephemeral infrastructure:
- Go to Actions → "Destroy Gatus" → Run workflow → type `destroy`Current state: Working / Portfolio project
What's working:
- Full CI/CD pipeline (build, scan, push, deploy)
- Security scanning gates (Trivy, Checkov)
- Automated dependency updates
- Manual destroy workflow
- Live Gatus at tm.elsagatus.com
What's planned:
- Scope IAM resources for ECS/ELB Delete* and Modify* actions to gatus-*
-
Challenge: Destroyed my OIDC role during cost-saving teardown, broke CI/CD completely → Solution: Designed two-layer architecture to separate persistent identity from ephemeral compute
-
Challenge: Pipeline re-runs failed on immutable ECR tags → Solution: Added image existence check to skip build if image already exists
-
Challenge: Terraform state lock conflicts from cancelled pipelines → Solution: Added concurrency control to queue runs instead of running in parallel
-
Learning: Trivy found 2 HIGH severity CVEs in my Go base image — updated from Go 1.24.4 to 1.24.11 to remediate
-
Learning: AWS console organisation doesn't match IAM service namespaces — ALB is under
elasticloadbalancing, notec2
| Metric | Value |
|---|---|
| Container image size | 24 MB |
| Checkov checks passing | 31+ |
| CVEs remediated | 2 |
| Security gates | 2 |
Open an issue on GitHub or connect with me on LinkedIn.