One of the most common ways developers deploy to AWS looks like this: Create an IAM User. Generate an Access Key and Secret Key. Store them in GitHub Secrets. Hope they never leak. This approach has a major flaw: Long-lived credentials are a leading cause of cloud security incidents. They can be leaked, exposed in logs, or simply forgotten. In this guide, I’ll show you how I built a production-grade, zero-secret CI/CD pipeline for a Dockerized Node.js app using AWS ECS Fargate and OIDC authentication. The Architecture The goal: A fully automated "Push-to-Production" flow in under 3 minutes. The Workflow: Git Push ➔ GitHub Actions ➔ OIDC Auth ➔ Docker Build ➔ Amazon ECR ➔ ECS Fargate Deployment Understanding OIDC in 60 Seconds
The Old Way: GitHub Secrets ➔ Static AWS Keys ➔ AWS API. Risk: Keys last forever. Manual rotation is a pain.
The OIDC Way: GitHub Workflow ➔ OIDC Token ➔ AWS STS ➔ Temporary Credentials. Win: AWS verifies the request came from your specific repo. It issues credentials valid for 1 hour only. No secrets stored anywhere!
Phase 1: The Application & Docker We’re using a lightweight Node.js server. javascript
const http = require('http'); const server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ message: 'Hello from ECS!', version: '1.0.0' })); }); server.listen(3000); Use code with caution.
The Dockerfile (Alpine Linux for speed): dockerfile
FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm install --production COPY . . EXPOSE 3000 CMD ["node", "app.js"]
Phase 2: Amazon ECR (The Image Registry) We create a private repository with two critical security features: scanOnPush: Automatically checks for vulnerabilities. IMMUTABLE tags: Prevents overwriting existing versions.
aws ecr create-repository --repository-name my-app --image-scanning-configuration scanOnPush=true --image-tag-mutability IMMUTABLE
Phase 3: ECS Fargate (Serverless Containers) No EC2 instances to manage. We define a Task (the blueprint) and a Service (the manager). Cluster: Pool of resources. Task Definition: How much CPU/RAM does the container need? Service: Ensures our container stays running 24/7.
aws ecs create-cluster --cluster-name my-app-cluster --capacity-providers FARGATE
Phase 4: The GitHub Actions Magic This is where the OIDC magic happens. Note the permissions block—it's required to request the JWT from GitHub.
yaml permissions: id-token: write contents: read
steps:
name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::ACCOUNT_ID:role/github-actions-deploy aws-region: us-east-1
name: Build and Push Image run: | docker build -t my-app . docker push $IMAGE_URI
Reliability: Self-Healing & Logs One of the best parts of ECS? Self-healing. If you manually stop a task:
aws ecs stop-task --cluster my-app-cluster --task TASK_ID
ECS notices the "desired count" dropped and instantly launches a new container. Zero human intervention. The Bottom Line: Cost Fargate: ~$9.00/mo ECR/Logs: ~$0.55/mo Security: Priceless.
Key Takeaways:
Have you made the switch to OIDC yet? Let's discuss in the comments! 👇
No responses yet.