Skip to main content

AWS Cloud Architecture

This section documents every AWS service and resource used to run the Bookstore platform in production. All infrastructure is defined as Terraform in the bookstore-infra repository. Application code and CI live in bookstore.

SettingValue
AWS accountXXXXXXXXXXXX
Primary regionus-west-2
Project slugbookstore
EKS clusterbookstore-eks
ECR registryXXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com
RDS endpointPrivate MySQL inside VPC
S3 (book covers)bookstore-book-images-XXXXXXXXXXXX
Terraform statebookstore-tfstate-XXXXXXXXXXXX

End-to-end architecture​


How the pieces connect​


AWS services reference​

Every service below is actually provisioned or used in this project.

Amazon VPC​

Purpose: Private network for all AWS resources.

Terraform module: bookstore-infra/vpc/

SettingValue
CIDR10.0.0.0/16 (~65,000 addresses)
Availability zones2
Private subnets10.0.1.0/24, 10.0.2.0/24 — EKS nodes, RDS
Public subnets10.0.101.0/24, 10.0.102.0/24 — load balancers, NAT
NAT gatewaySingle shared NAT (cost-optimized)
DNSHostnames and support enabled
ELB tagsPublic subnets tagged kubernetes.io/role/elb=1; private tagged kubernetes.io/role/internal-elb=1

Used by: EKS worker nodes, RDS, internet-facing load balancers, NAT for outbound pod traffic.


Amazon EC2​

Purpose: Compute for Kubernetes worker nodes (not used for standalone VMs).

How it appears: EKS managed node group launches EC2 instances.

SettingValue
Instance typem7i-flex.large (2 vCPU, 8 GiB RAM)
Node count1 desired, 1 min, 3 max (auto-scaling group)
Subnet placementPrivate subnets only
AMIEKS-optimized (managed by AWS)

Worker nodes run all application pods, Kafka, Argo CD workloads, and the monitoring stack.


Amazon EKS​

Purpose: Managed Kubernetes control plane and orchestration for all microservices.

Terraform module: bookstore-infra/eks/

SettingValue
Cluster namebookstore-eks
Kubernetes version1.33
API endpointPublic (for kubectl access)
Node groupgeneral — managed, in private subnets
AddonsCoreDNS, kube-proxy, VPC CNI
Namespacesbookstore (apps), monitoring (observability), argocd (GitOps)

Workloads running on EKS:

  • 8 microservices + api-gateway + frontend (Deployments)
  • Kafka (StatefulSet)
  • Prometheus, Grafana, Alertmanager (Deployments)
  • Argo CD (installed separately; Applications defined in infra repo)

Configure kubectl after cluster creation:

aws eks update-kubeconfig --region us-west-2 --name bookstore-eks

Amazon ECR​

Purpose: Private Docker image registry. GitHub Actions pushes here; EKS pulls at deploy time.

Terraform module: bookstore-infra/ecr/

SettingValue
Registry URLXXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com
Tag mutabilityIMMUTABLE
Scan on pushEnabled
LifecycleKeep last 10 images per repository

Repositories (Terraform):

api-gateway, auth-service, user-service, book-service, order-service, payment-service, notification-service, analytics-service

CI also pushes a frontend repository (created outside Terraform defaults).

Image tag format: 7-character git commit SHA (e.g. 6fa643b).


Amazon RDS (MySQL)​

Purpose: Managed relational database hosting all microservice schemas.

Terraform module: bookstore-infra/rds/

SettingValue
EngineMySQL 8.4
Instance classdb.t3.micro
Storage20 GiB gp3, encrypted
Identifierbookstore-postgres
Initial databasebookstore
Master usernamebookstore_admin
NetworkPrivate subnets only; publicly_accessible = false
Multi-AZNo (single-AZ, cost-optimized)
AccessSecurity group allows port 3306 from VPC CIDR only

Databases used by services (created by Hibernate ddl-auto: update or manual setup):

bookstore_auth_db, bookstore_user_db, bookstore_books_db, bookstore_order_db, bookstore_payment_db, bookstore_notification_db, bookstore_analytics_db

Pods read credentials from Kubernetes secret db-credentials (DB_USERNAME, DB_PASSWORD).


Amazon S3​

Two S3 buckets serve different purposes:

1. Book cover images (s3-images/ module)​

SettingValue
Bucketbookstore-book-images-XXXXXXXXXXXX
AccessPublic read on objects (for <img src> URLs)
Write accessbook-service only (via IRSA)
CORSGET/HEAD from any origin
VersioningDisabled

Used by book-service BookCoverStorageService for cover uploads.

2. Terraform remote state (bootstrap/ module)​

SettingValue
Bucketbookstore-tfstate-XXXXXXXXXXXX
AccessPrivate (all public access blocked)
EncryptionAES-256 (SSE-S3)
VersioningEnabled
LockingS3 native (use_lockfile = true, Terraform 1.11+)

State keys: vpc/, eks/, rds/, ecr/, s3-images/, github-oidc/


AWS IAM​

Purpose: Identity and access control for CI/CD pipelines and Kubernetes pods.

Terraform modules: github-oidc/, s3-images/ (IRSA role)

Roles​

RoleTrustPermissions
github-actions-ecr-pushGitHub OIDC (repo:ashishnamdeo16/bookstore:*)ECR push/pull (ecr:GetAuthorizationToken, layer upload, PutImage)
book-service-s3-accessEKS IRSA (system:serviceaccount:bookstore:book-service)S3 Put/Get/Delete on book images bucket

OIDC provider​

  • URL: https://token.actions.githubusercontent.com
  • Audience: sts.amazonaws.com
  • Defined in Terraform (github-oidc/) and referenced in this repo as trust-policy.json

GitHub Actions assumes github-actions-ecr-push via OIDC — no long-lived AWS access keys in GitHub secrets.

IRSA (IAM Roles for Service Accounts)​

book-service pod uses a ServiceAccount annotated with:

eks.amazonaws.com/role-arn: arn:aws:iam::XXXXXXXXXXXX:role/book-service-s3-access

This lets the pod call S3 without embedding credentials in the container.


AWS Secrets Manager​

Purpose: Stores the RDS master password automatically.

How it works: Terraform sets manage_master_user_password = true on the RDS instance. AWS generates and rotates the master password in Secrets Manager. The Kubernetes db-credentials secret is populated separately for pod use.


Elastic Load Balancing (ALB/NLB)​

Purpose: Exposes the application to the internet.

How it works (no standalone Terraform):

  • Kubernetes Service type LoadBalancer on frontend and api-gateway in the bookstore namespace
  • EKS cloud controller provisions an AWS load balancer in public subnets (tagged via VPC module)
  • Frontend LB serves the React SPA (nginx port 80)
  • API gateway LB serves backend API routes (port 80 → 8080)

Example hostname pattern: *.us-west-2.elb.amazonaws.com (used as default VITE_API_BASE_URL in CI).


Amazon EBS​

Purpose: Block storage for persistent Kubernetes volumes.

UsageStorage classSize
Prometheus metrics data (prometheus-data PVC)gp210 GiB
RDS storagegp3 (managed by RDS, not a K8s PVC)20 GiB

EBS volumes are created automatically when Kubernetes binds a PVC to a pod in the monitoring namespace.


AWS Budgets​

Purpose: Cost guardrails and billing alerts.

Terraform module: bookstore-infra/bootstrap/

SettingValue
Budget namebookstore-monthly
Limit$50 USD/month (default)
Alert at 80%Actual spend email notification
Alert at 100%Forecasted spend email notification

Configured during the bootstrap phase before any other infrastructure is provisioned.


NAT Gateway​

Purpose: Allows pods in private subnets to reach the internet (ECR image pulls, Stripe, Twilio, Mailtrap, external APIs).

Provisioned by: VPC Terraform module (enable_nat_gateway = true, single_nat_gateway = true)

Cost note: Single NAT gateway is used instead of one-per-AZ to reduce cost. Production HA deployments would use multiple NAT gateways.


Network topology​

Traffic flows​

DirectionPath
Inbound (users)Internet → IGW → ALB (public subnet) → EKS Service → Pod (private subnet)
Outbound (pods)Pod → NAT gateway (public subnet) → IGW → Internet
DatabasePod (private) → RDS (private), port 3306, VPC CIDR only
ECR pullkubelet on worker node → NAT → ECR API + registry
S3 uploadbook-service pod → S3 API (via VPC endpoint or internet via NAT)

Terraform provisioning order​

Infrastructure is built in phases. Each phase stores state in S3 and later phases read earlier outputs via terraform_remote_state.

PhaseModuleAWS resources created
0bootstrap/S3 state bucket, versioning, encryption, AWS Budget
1vpc/VPC, subnets, IGW, NAT, route tables, ELB tags
2eks/EKS cluster, managed node group, addons
3rds/RDS MySQL, subnet group, security group
4ecr/ECR repositories, lifecycle policies
5s3-images/S3 book images bucket, IRSA role for book-service
6github-oidc/OIDC provider, GitHub Actions IAM role

All modules use Terraform ≥ 1.11 with S3 native state locking.


CI/CD and AWS integration​

Detailed workflow documentation: CI/CD Pipeline

StepAWS involvement
1. Developer pushes codeNone
2. GitHub Actions startsAssumes github-actions-ecr-push via OIDC
3. Docker build + pushImage stored in Amazon ECR
4. Manifest updateCommits to bookstore-infra (no AWS API)
5. Argo CD syncEKS pulls new image from ECR
6. Rolling updateEC2 worker nodes run new pods

Repository secrets/vars used with AWS:

NamePurpose
INFRA_REPO_TOKENPush manifest updates (GitHub, not AWS)
ROLE_ARN (in workflow env)arn:aws:iam::XXXXXXXXXXXX:role/github-actions-ecr-push
ECR_REGISTRY (in workflow env)ECR registry URL

Kubernetes on AWS​

Detailed K8s documentation: Kubernetes Deployment

K8s resourceAWS backing
Service type: LoadBalancerAWS Elastic Load Balancer
PersistentVolumeClaim (Prometheus)Amazon EBS (gp2)
ServiceAccount + IRSA annotationAWS IAM role
EKS managed node groupAmazon EC2 instances
Pod → RDS connectionAmazon RDS in same VPC

Monitoring on AWS​

The observability stack runs inside EKS, not as separate AWS managed services (no Amazon Managed Prometheus, no CloudWatch Container Insights configured).

ComponentStorageNamespace
PrometheusEBS PVC (10 Gi gp2)monitoring
GrafanaEphemeral pod storagemonitoring
AlertmanagerEphemeral pod storagemonitoring

Prometheus scrapes Spring Boot /actuator/prometheus endpoints from services annotated in the bookstore namespace.

See Monitoring for scrape annotations and metric details.


Security summary​

LayerMechanism
NetworkPrivate subnets for compute and database; RDS not publicly accessible
CI/CD authGitHub OIDC → IAM role (no static AWS keys)
Pod → S3IRSA (short-lived credentials, scoped to one bucket)
DatabaseSecurity group restricts MySQL to VPC CIDR; credentials in K8s secret
Terraform stateS3 encrypted, versioned, public access blocked
ECRPrivate registry; images pulled by EKS nodes only
S3 book imagesPublic read on objects only; write requires IAM role

ResourceCost consideration
EKS control plane~$0.10/hour per cluster
EC2 worker nodesm7i-flex.large × desired count
NAT gatewayHourly charge + data processing (single NAT to save cost)
RDSdb.t3.micro single-AZ
EBS10 Gi Prometheus PVC + 20 Gi RDS gp3
ALBPer load balancer (frontend + api-gateway = 2 LBs)
AWS BudgetAlerts at $50/month default threshold

What is not used​

These AWS services are not part of the current architecture:

  • AWS Lambda
  • Amazon CloudFront
  • Amazon API Gateway (AWS) — routing uses Spring Cloud Gateway on EKS
  • Amazon MSK — Kafka runs as a pod on EKS
  • Amazon ElastiCache
  • AWS Fargate — EKS uses EC2 managed node groups
  • Amazon Cognito — auth is custom JWT in auth-service
  • AWS CloudFormation — infrastructure is Terraform

External repository: bookstore-infra on GitHub