CI/CD Pipeline for 876 Events AWS Infrastructure
Documentations

CI/CD Pipeline for 876 Events AWS Infrastructure

Building a Secure CI/CD Pipeline for ECS/Fargate

After migrating an application from managed hosting to AWS ECS/Fargate, the next step was removing manual deployments without sacrificing security, reliability, or control. This project focused on building a production-ready CI/CD pipeline that could ship changes safely, reduce deployment time, and improve operational consistency.

The result was a deployment workflow built around blue/green releases, least-privilege IAM, container image scanning, managed secrets, health validation, and fast rollback paths. The goal was not just automation, but automation that was secure, auditable, and practical for a live environment.


What I Built

  • Automated ECS/Fargate deployments through GitLab CI/CD
  • Blue/green deployment flow for zero-downtime releases
  • Secure image build and push workflow using Amazon ECR
  • Secrets Manager integration with no secrets stored in code
  • Health-based deployment validation through CloudWatch and ALB checks
  • Controlled database migration workflow with snapshot protection
  • Rollback procedures for failed or unhealthy deployments
  • Approval gates for production changes

The Problem

The AWS migration solved the infrastructure problem, but deployments were still manual. Shipping a release meant building images by hand, pushing them to ECR, updating ECS task definitions, forcing new deployments, monitoring service health, and rolling back manually if anything went wrong.

That created several issues:

  • Deployments were slower than they needed to be
  • Repeated manual steps increased the chance of mistakes
  • Rollback was possible, but too dependent on speed and context
  • There was no consistent, repeatable release process across environments

The requirement was clear: create a deployment pipeline that was fast, safe, and production-ready.


Architecture Overview

The final workflow followed a simple path:

Developer push
    ↓
GitLab CI/CD pipeline
    ↓
Test and build stages
    ↓
Container image pushed to ECR
    ↓
Deployment to staging
    ↓
Approval gate
    ↓
Deployment to production

The application itself ran on ECS/Fargate behind an Application Load Balancer, with Aurora as the database backend and RDS Proxy managing database connections. S3 handled object storage, and Secrets Manager supplied runtime credentials securely.


Security Design

A major part of this work was making sure the deployment process was secure by design rather than secure by policy alone.

  • Least-privilege IAM: deployment identities only had access to the AWS actions required for building, publishing, and updating services
  • Secrets isolation: credentials were stored in Secrets Manager and injected at runtime rather than committed into configuration files or CI variables unnecessarily
  • Separated responsibilities: task execution permissions were kept distinct from application runtime permissions
  • Image security: images were pushed to ECR with scanning enabled as part of the release process
  • No SSH-based operations: operational tasks such as migrations were handled through ECS Exec rather than opening shell access patterns that were harder to control and audit

This kept the deployment model aligned with security engineering principles while still being usable by the delivery process.


Pipeline Design

The CI/CD pipeline was structured around a few clear stages:

  1. Test - validate the application before any build or release work begins
  2. Build - create a production-ready Docker image and push it to ECR
  3. Deploy to staging - update the staging ECS service and validate application health
  4. Approve - require deliberate promotion before production release
  5. Deploy to production - update the production ECS service and monitor rollout health

This gave the release process a repeatable structure while still allowing controlled production promotion.


Docker Build Strategy

The container build used a multi-stage Dockerfile so the final runtime image stayed lean and production-focused.

  • Frontend assets were built separately
  • PHP dependencies were installed in a dedicated build stage
  • The final image only contained the runtime dependencies and built assets needed by the application

That reduced image size, lowered the runtime attack surface, and made deployments more efficient.


Deployment Strategy

For ECS, the deployment process was designed to avoid downtime during releases. New tasks were started and validated before old tasks were removed, allowing traffic to shift only after the new version passed health checks.

This approach improved release safety in several ways:

  • Users were not impacted during standard deployments
  • Bad deployments could fail health checks before taking traffic
  • The previous task definition remained available for rollback

The deployment process was built around health validation rather than simply assuming that a newly started container was ready.


Database Migration Approach

I treated database migrations as a separate operational concern rather than bundling them into every application deployment automatically.

That decision mattered because schema changes carry different risk than code releases. To reduce that risk:

  • database snapshots were taken before migration work
  • migration execution was controlled explicitly
  • migrations were run through ECS Exec rather than ad hoc server access

This gave the deployment workflow a safer boundary between application rollout and schema change management.


Monitoring and Rollback

A deployment pipeline is only as strong as its failure handling. I paired the rollout process with monitoring on service health, load balancer behavior, and database pressure so failures could be caught early.

Rollback was designed to be fast and operationally simple by reverting the ECS service to the previous task definition. That meant recovery did not depend on rebuilding or improvising under pressure.


Lessons Learned

A few practical lessons stood out during implementation:

  • Network paths matter as much as application health. A service can fail deployment even when the container itself is healthy if supporting dependencies are not reachable.
  • Operational access should be intentional. Using ECS Exec was a cleaner and more secure pattern than relying on SSH-style access.
  • Environment-specific image tags are essential. Release clarity matters, especially when promoting builds across environments.
  • Database connection behavior needs to be validated under scale. Application rollout and connection management must be considered together.
  • Automation must include failure paths. A fast rollback path is just as important as a fast deployment path.

Outcome

This project turned a manual deployment process into a secure, repeatable release pipeline for ECS/Fargate. It improved deployment speed, reduced operational risk, and created a cleaner separation between build, release, migration, and rollback workflows.

More importantly, it demonstrated the full lifecycle thinking required for production cloud delivery: infrastructure design, IAM boundaries, application packaging, deployment orchestration, operational safety, and recovery planning all need to work together.

Get In Touch

Get in touch with me about work opportunities


HIRE ME

Quick Links

Extras

Social Media Links

Copyright © Mark Clarke, 2026