AWS Fully Serverless Architecture with CI/CD

Table of contents
- Introduction to Serverless Architecture
- Understanding Serverless Doesn't Mean Server-Free
- Project Objective
- Core AWS Serverless Services
- Networking and Security Considerations
- Monitoring and Observability
- Domain and TLS Management
- Infrastructure as Code with Terraform
- CI/CD Pipeline with GitHub Actions
- Node.js Cloud Native API Overview
- Best Practices for a Robust Serverless Stack
- Conclusion
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.
Subscribe to my newsletter
Read articles from Pratiksha kadam directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
