DevOps Guide

AWS DevOps Pipeline

Simple guide to deploy FastAPI + Vanilla JS + AWS Infrastructure with CI/CD

FastAPI Vanilla JS AWS Terraform CI/CD

Prerequisites

AWS Account
GitHub Account
Local Terminal

Estimated Cost: ~$8-12/month for running infrastructure

We need to install AWS CLI, Terraform, and Git. Choose your operating system:

Windows (PowerShell as Administrator)

Install Chocolatey first (if not already installed):

Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

Then install the required tools:

choco install awscli terraform git -y

Mac (Terminal)

Install Homebrew first (if not already installed):

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Then install the required tools:

brew install awscli terraform git

Linux (Ubuntu/Debian)

Install AWS CLI v2:

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

Install Terraform:

wget https://releases.hashicorp.com/terraform/1.7.0/terraform_1.7.0_linux_amd64.zip
unzip terraform_1.7.0_linux_amd64.zip
sudo mv terraform /usr/local/bin/

Install Git:

sudo apt update
sudo apt install git -y

Verify Installation

Run these commands to verify everything is installed correctly:

aws --version
terraform --version
git --version

What You'll See:

Installing AWS CLI

Installing AWS CLI

Confirming Installation

Installation Confirmation

Version Check

Version Verification

Need an AWS account? Create one at aws.amazon.com

Step 1: Create IAM User

  1. Log into the AWS Console
  2. Navigate to IAM service
  3. Click Users in the left sidebar
  4. Click Create User
  5. Enter username: devops-demo-user
  6. Check Provide user access to the AWS Management Console (optional)
  7. Click Next

Step 2: Attach Permissions

  1. Select Attach policies directly
  2. Search for and select AdministratorAccess
  3. Click Next
  4. Review and click Create User

Note: AdministratorAccess is used for simplicity in this demo. In production, use more restrictive policies.

Step 3: Create Access Keys

  1. Click on your newly created user
  2. Go to the Security credentials tab
  3. Scroll down to Access keys
  4. Click Create access key
  5. Select Command Line Interface (CLI)
  6. Check the confirmation checkbox
  7. Click Next
  8. Add description (optional): DevOps Demo CLI Access
  9. Click Create access key
  10. ⚠️ Important: Copy both the Access Key ID and Secret Access Key immediately!
Creating AWS Access Key

Configure the AWS CLI with your access keys from the previous step.

Configure AWS CLI

Run the following command and enter your credentials when prompted:

aws configure

Enter These Values

AWS Access Key ID: [Your Access Key from Step 2]
AWS Secret Access Key: [Your Secret Key from Step 2]
Default region name: us-east-1
Default output format: json

Verify Configuration

Test your configuration by checking your identity:

aws sts get-caller-identity

This should return your AWS account ID and user ARN.

What You'll See:

AWS Configure

AWS CLI Configuration

AWS Identity

Identity Verification

✅ Success! If you see your account details, AWS CLI is properly configured and ready to use.

We'll create 3 separate repositories to organize our DevOps pipeline components.

Why 3 Separate Repositories?

  • Infrastructure: Manages AWS resources with Terraform
  • Backend: FastAPI application with its own CI/CD pipeline
  • Frontend: Static website with separate deployment to S3

Create Each Repository

Follow these steps for each of the 3 repositories:

  1. Go to github.com/new
  2. Enter the repository name (see list below)
  3. Set visibility to Private (recommended for AWS keys)
  4. Check Add a README file
  5. Click Create repository

Infrastructure Repository

1st
devops-demo-infrastructure

Contains Terraform files for AWS resources

Backend Repository

2nd
devops-demo-backend

FastAPI application, Dockerfile, and CI/CD

Frontend Repository

3rd
devops-demo-frontend

HTML/JS files and S3 deployment workflow

What You'll See:

Create Infrastructure Repo

Infrastructure Repository

Create Backend Repo

Backend Repository

Create Frontend Repo

Frontend Repository

Clone Repositories Locally

Replace [username] with your GitHub username:

# Create a folder for all projects
mkdir devops-demo
cd devops-demo

# Clone all repositories
git clone https://github.com/[username]/devops-demo-infrastructure.git
git clone https://github.com/[username]/devops-demo-backend.git
git clone https://github.com/[username]/devops-demo-frontend.git

# Verify all folders exist
ls -la

Verify Success

You should now have 3 folders on your local machine:

  • 📁 devops-demo-infrastructure/
  • 📁 devops-demo-backend/
  • 📁 devops-demo-frontend/

This Terraform configuration creates a complete AWS infrastructure for our DevOps demo application.

AWS Services Created

VPC & Networking

Purpose: Network foundation

Uses default VPC with security groups for app (port 8000) and database (port 5432)

RDS PostgreSQL

Purpose: Database

db.t3.micro instance with 20GB storage, accessible only from app security group

ECS Cluster

Purpose: Container orchestration

Fargate-based cluster running containerized FastAPI application

ECS Task Definition

Purpose: Container configuration

256 CPU, 512MB memory, with database URL from SSM Parameter Store

ECS Service

Purpose: Application deployment

Maintains 1 running task with public IP assignment

ECR Repository

Purpose: Container registry

Stores Docker images for the backend application

S3 Bucket

Purpose: Static website hosting

Hosts frontend files with public read access and website configuration

IAM Roles

Purpose: Security & permissions

ECS execution and task roles with minimal required permissions

SSM Parameter

Purpose: Secrets management

Securely stores database connection string

CloudWatch

Purpose: Logging

Centralized logging for ECS containers

Total estimated cost: ~$8-12/month

Create devops-demo-infrastructure/main.tf

provider "aws" {
  region = "us-east-1"
}

data "aws_vpc" "default" {
  default = true
}

data "aws_subnets" "default" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.default.id]
  }
}

resource "aws_security_group" "app" {
  vpc_id = data.aws_vpc.default.id
  
  ingress {
    from_port   = 8000
    to_port     = 8000
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# ... (truncated for brevity, full code available in guide)

output "ecr_url" { value = aws_ecr_repository.app.repository_url }
output "bucket_name" { value = aws_s3_bucket.frontend.bucket }
output "website_url" { value = "http://${aws_s3_bucket_website_configuration.frontend.website_endpoint}" }
cd devops-demo-infrastructure
terraform init
terraform apply
# Save the outputs
Terraform Init Terraform Output

1. Create FastAPI app

File: devops-demo-backend/app/main.py

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
import os
import json
import psycopg2
from psycopg2.extras import RealDictCursor

app = FastAPI()
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"])

# ... (truncated for brevity)

2. Add dependencies

File: requirements.txt

fastapi==0.104.1
uvicorn==0.24.0
psycopg2-binary==2.9.9

3. Setup directories and secrets

cd devops-demo-backend
mkdir app .github .github/workflows

Add GitHub Secrets:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • ECR_REGISTRY (from terraform output)

GitHub Actions CI/CD Pipeline

The backend uses a fully automated CI/CD pipeline that builds, tests, and deploys your FastAPI application to AWS ECS.

What the GitHub Action Does:

1

Code Checkout & Setup

Checks out your code and configures Python environment

2

AWS Authentication

Configures AWS credentials using GitHub secrets

3

Docker Build & Push

Builds Docker image and pushes to AWS ECR registry

4

ECS Deployment

Updates ECS service to run the new container image

Automatic Triggers

  • Push to main branch: Automatically builds and deploys new version
  • Pull request: Runs build tests to verify code quality
  • Manual trigger: Can be run manually from GitHub Actions tab

4. Deploy

git add .
git commit -m "Add backend"
git push origin main
Backend Success Backend Secrets

1. Get backend IP

# Get task ARN
aws ecs list-tasks --cluster demo-cluster --service demo-app --desired-status RUNNING --query 'taskArns[0]' --output text --region us-east-1

# Get network interface ID (use task ARN from above)
aws ecs describe-tasks --cluster demo-cluster --tasks [TASK_ARN] --region us-east-1 --query 'tasks[0].attachments[0].details[?name==`networkInterfaceId`].value[0]' --output text

# Get public IP (use network interface ID from above)
aws ec2 describe-network-interfaces --network-interface-ids [NETWORK_INTERFACE_ID] --region us-east-1 --query 'NetworkInterfaces[0].Association.PublicIp' --output text

2. Setup and deploy

Add GitHub Secrets:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • S3_BUCKET (from terraform output)
  • API_URL: http://[BACKEND_IP]:8000
cd devops-demo-frontend
mkdir .github .github/workflows
git add .
git commit -m "Add frontend"
git push origin main

GitHub Actions Static Website Deployment

The frontend uses a streamlined deployment pipeline that builds and uploads your static website directly to AWS S3.

What the GitHub Action Does:

1

Code Checkout

Retrieves your HTML, CSS, and JavaScript files from the repository

2

Environment Variable Substitution

Replaces API_URL placeholder with actual backend endpoint URL

3

AWS S3 Upload

Syncs all static files to your S3 bucket with correct permissions

4

Website Availability

Files are immediately available via S3 website endpoint

Automatic Triggers

  • Push to main: Instantly deploys changes
  • Pull request: Validates file structure
  • Manual run: Deploy on-demand

Benefits

  • Fast deployment: ~30 seconds
  • Cost effective: No server required
  • Highly available: AWS S3 reliability
Frontend Success Working Website

Common Terraform Errors

Error: Invalid provider configuration

Usually means AWS credentials are not configured correctly.

Solution:

  • Verify aws configure was run
  • Check aws sts get-caller-identity works
  • Ensure your AWS keys have proper permissions

Error: Resource already exists

Some AWS resources with the same name already exist.

Solution:

  • Change the resource names in your Terraform file
  • Or delete existing resources manually in AWS console
  • Run terraform destroy if you have leftover resources

GitHub Actions Issues

AWS credentials not configured

Actions fail with authentication errors.

Solution:

  • Go to your repo → Settings → Secrets and variables → Actions
  • Add AWS_ACCESS_KEY_ID
  • Add AWS_SECRET_ACCESS_KEY
  • Add other required secrets (ECR_REGISTRY, S3_BUCKET, API_URL)

ECS IAM Permissions Debug

ECS tasks failing - runningCount stays at 0

Tasks keep stopping with no running containers.

Debug Commands:

# Check service status
aws ecs describe-services --cluster demo-cluster --services demo-app --region us-east-1

# Check stopped tasks for error details
aws ecs list-tasks --cluster demo-cluster --desired-status STOPPED --region us-east-1
aws ecs describe-tasks --cluster demo-cluster --tasks [TASK_ARN] --region us-east-1

Common Error Found:

"stoppedReason": "ResourceInitializationError: unable to pull secrets... AccessDeniedException: User is not authorized to perform: ssm:GetParameters because no identity-based policy allows the ssm:GetParameters action"

Root Cause:

IAM role had ssm:GetParameter (singular) but ECS needs ssm:GetParameters (plural).

Fix in Terraform:

resource "aws_iam_role_policy" "execution_ssm" {
  name = "ssm-access"
  role = aws_iam_role.execution.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Action = [
        "ssm:GetParameter",
        "ssm:GetParameters"  # Added this line
      ]
      Resource = [aws_ssm_parameter.db_url.arn]
    }]
  })
}

Key Learning: ECS requires both ssm:GetParameter and ssm:GetParameters permissions for secrets retrieval.

Connection Issues

Frontend can't connect to backend

CORS errors or connection refused.

Solution:

  • Verify backend is running: check ECS service status
  • Ensure security group allows port 8000 from anywhere
  • Check that API_URL in frontend secrets is correct
  • Verify backend has CORS enabled (should be in the code)

Error Examples:

Terraform Error

Terraform Error Example

Error Resolution

Error Resolution

You're Done!

Backend API

http://[BACKEND_IP]:8000

Frontend Website

From terraform website_url output

Cleanup: Run terraform destroy when done

Terraform Destroy Example

Terraform Destroy Output

Example output from terraform destroy command