AWS Fully Serverless Architecture with CI/CD

Pratiksha kadamPratiksha kadam
5 min read

Introduction to Serverless Architecture

Serverless computing has fundamentally changed how we build and deploy cloud-native applications. By abstracting away server management, serverless enables developers to focus exclusively on application logic and user experience. It began with the concept of Function-as-a-Service (FaaS), pioneered by AWS Lambda, and has grown into a powerful suite of managed services that can run complete applications—without provisioning a single server.

Understanding Serverless Doesn't Mean Server-Free

Despite the name, serverless doesn't eliminate servers—it simply means developers are no longer responsible for maintaining them. The underlying infrastructure is still very much alive, but it's fully managed by AWS. The benefit? Near-infinite scalability, granular cost control (pay-per-invocation), and reduced operational complexity.


Project Objective

This project demonstrates the deployment of a fully serverless Node.js API using Terraform for Infrastructure-as-Code (IaC) and GitHub Actions for CI/CD. The goal is to run a production-grade backend API on AWS public cloud services using only managed, scalable, and serverless components.

Source Code : https://github.com/lastoyster/serverless-api/


Serverless Components Overview

Here are the AWS services used to build this architecture:

  • API Gateway

  • AWS Lambda

  • Amazon Aurora Serverless (MySQL-compatible)

  • Amazon S3

  • AWS Secrets Manager

  • AWS Certificate Manager (ACM)

  • Amazon CloudWatch

  • Amazon Route 53


Core AWS Serverless Services

API Gateway

Amazon API Gateway provides a front-door to access data and services via RESTful APIs. It handles all the heavy lifting: authentication, rate-limiting, caching, and versioning.

Best Practice:

Always use usage plans with API keys for consumer throttling and JWT authorizers for security.

resource "aws_api_gateway_rest_api" "api" {
  name        = "serverless-api"
  description = "API Gateway for Lambda backend"
}

AWS Lambda

Lambda functions are stateless compute containers that scale automatically. They're perfect for REST APIs and background jobs.

Best Practice:

Keep function packages small and use layers for dependencies.

resource "aws_lambda_function" "api_function" {
  function_name = "serverless_api"
  handler       = "index.handler"
  runtime       = "nodejs18.x"
  role          = aws_iam_role.lambda_exec.arn
  filename      = "build/serverless_api.zip"
  vpc_config {
    subnet_ids         = var.private_subnets
    security_group_ids = [aws_security_group.lambda_sg.id]
  }
}

Amazon Aurora Serverless

Aurora Serverless provides automatic scaling and pauses when not in use—ideal for unpredictable workloads.

Best Practice:

Always enable auto-scaling and use Secrets Manager for credentials.

resource "aws_rds_cluster" "aurora_serverless" {
  engine         = "aurora-mysql"
  engine_mode    = "serverless"
  master_username = "admin"
  master_password = var.db_password
  backup_retention_period = 5
}

Amazon S3

Amazon S3 is used to store media files such as user-uploaded images. With high durability (11 9s), it’s a great fit for object storage.

Best Practice:

Use S3 bucket policies to limit access from Lambda only through VPC Gateway Endpoints.

resource "aws_s3_bucket" "api_bucket" {
  bucket = "serverless-api-bucket"
  acl    = "private"
}

AWS Secrets Manager

Secrets Manager automatically rotates database credentials securely using Lambda under the hood.

Best Practice: Set rotation policies and access secrets from Lambda using IAM roles.

resource "aws_secretsmanager_secret" "db_secret" {
  name = "aurora-db-credentials"
}

Networking and Security Considerations

VPC Design with Private Subnets

Lambda is deployed in private subnets to ensure that no public access is allowed directly. Only API Gateway exposes endpoints.


VPC Endpoints (Interface & Gateway)

  • Use Interface endpoints for private Secrets Manager access.

  • Use Gateway endpoints for S3 access.

resource "aws_vpc_endpoint" "s3" {
  vpc_id       = var.vpc_id
  service_name = "com.amazonaws.${var.region}.s3"
  route_table_ids = var.route_table_ids
}

Security Groups

Control access at the ENI level using security groups. Each Lambda ENI should only allow traffic to S3, Secrets Manager, and the database.


IAM Roles

Grant least privilege to Lambda functions. Assign execution roles that grant specific actions, e.g., rds:Connect, s3:GetObject, etc.

resource "aws_iam_role_policy" "lambda_policy" {
  role = aws_iam_role.lambda_exec.name
  policy = data.aws_iam_policy_document.lambda_policy.json
}

Monitoring and Observability

AWS CloudWatch Integration

Lambda automatically pushes logs to CloudWatch. Use log retention policies and custom metrics for enhanced observability.

Best Practice: Integrate structured logging using tools like Winston or Pino.

resource "aws_cloudwatch_log_group" "lambda_logs" {
  name              = "/aws/lambda/serverless_api"
  retention_in_days = 7
}

Domain and TLS Management

Route53 & AWS Certificate Manager

Use ACM to provision free SSL certificates and bind them to custom domains via API Gateway or CloudFront.


Infrastructure as Code with Terraform

Terraform Workflow

Use these core commands:

terraform init
terraform plan
terraform apply
terraform destroy

Best Practices for Terraform Modules

  • Organize by module: vpc, lambda, rds, api_gateway

  • Use remote state (e.g., S3 with DynamoDB locking)


CI/CD Pipeline with GitHub Actions

GitHub Actions for Automation

A typical .github/workflows/deploy.yml might look like:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      - name: Deploy to Lambda
        run: |
          npm install
          zip -r function.zip .
          aws lambda update-function-code --function-name serverless_api --zip-file fileb://function.zip

Managing AWS Credentials Securely

Use GitHub Secrets (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) for credentials injection. Rotate these keys regularly.


IAM User Strategy

Use a dedicated IAM user with minimal permissions for CI/CD. Avoid using root credentials in CI/CD environments.


Node.js Cloud Native API Overview

The Node.js API exposes standard REST routes for user and product operations and is tightly integrated with AWS Lambda for execution.

Routes and Endpoints

GET    /healthz
GET    /v1/user/{userId}
POST   /v1/user
PUT    /v1/user/{userId}

Sample Payloads

POST User:

{
  "username": "jane.doe@example.com",
  "password": "password",
  "first_name": "Jane",
  "last_name": "Doe"
}

GET Product:

{
  "id": 1,
  "name": "Sample",
  "quantity": 1
}

Best Practices for a Robust Serverless Stack

  • Always use environment variables to manage config.

  • Use dead-letter queues (DLQs) for Lambda error handling.

  • Enable tracing with AWS X-Ray.

  • Automate credential rotation with Secrets Manager.

  • Monitor cold starts and reduce package size to mitigate.


Conclusion

By combining Terraform, AWS serverless services, and CI/CD automation via GitHub Actions, we've created a scalable, secure, and cost-effective architecture. This stack enables rapid development, seamless deployment, and a reduced operational footprint—hallmarks of a modern cloud-native approach.


0
Subscribe to my newsletter

Read articles from Pratiksha kadam directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Pratiksha kadam
Pratiksha kadam