A FastAPI service that exposes an HTTPS REST + HTML interface for managing Amazon RDS database snapshots (create, status, delete) for both single instances and Aurora clusters. The same container ships with reference deployments for AWS (ECS, EKS), Azure (AKS), and Google Cloud (GKE), wired through a GitHub Actions DevSecOps pipeline.
- Architecture
- Features
- Repository Layout
- Quick Start
- API Reference
- Configuration
- Container Image
- Cloud Deployments
- CI/CD Pipeline
- Troubleshooting
- Reading
- License
The service is a small async FastAPI app fronted by Uvicorn over TLS. Each
HTTP handler delegates to the rdsAdmin module,
which wraps the AWS SDK (boto3) and calls Amazon RDS. Snapshots are
created by RDS itself and stored in AWS-managed S3 (visible only through
the RDS API).
Legacy diagram preserved at images/dbAPIapp.png. The SVG above (images/architecture.svg) is the current source of truth and is updated alongside the code.
Mermaid source (renders on GitHub)
flowchart LR
subgraph Clients["Clients"]
U["User / Browser"]
C["CI / Cron / curl"]
end
subgraph Runtime["Container Runtime (EKS / ECS / AKS / GKE / Local)"]
direction TB
UV["Uvicorn + TLS<br/>:25443"]
API["FastAPI app<br/>dbWebAPI.py"]
TPL["Jinja2 templates<br/>(HTML UI)"]
LIB["lib/rdsAdmin.py<br/>RDSCreate / RDSDescribe / RDSDelete"]
UV --> API
API --> TPL
API --> LIB
end
subgraph AWS["AWS Account"]
RDS["Amazon RDS<br/>(Instance / Aurora Cluster)"]
SNAP["RDS Snapshots<br/>(AWS-managed S3)"]
end
U -->|HTTPS form post| UV
C -->|HTTPS / curl| UV
LIB -->|boto3 / AWS API| RDS
RDS --> SNAP
sequenceDiagram
autonumber
participant Client
participant FastAPI as FastAPI (dbWebAPI)
participant RDSAdmin as lib.rdsAdmin
participant RDS as AWS RDS
Client->>FastAPI: POST /backup/create (endpoint=<db-host>)
FastAPI->>FastAPI: derive snapshot_name<br/>{instance}-snapshot-{YYYY-MM-DD-HH-MM-SS}
alt endpoint contains "cluster"
FastAPI->>RDSAdmin: rds_create_db_cluster_snapshot(...)
RDSAdmin->>RDS: create_db_cluster_snapshot
else single instance
FastAPI->>RDSAdmin: rds_create_db_snapshot(...)
RDSAdmin->>RDS: create_db_snapshot
end
FastAPI->>RDSAdmin: snapshot_status(snapshot_name, endpoint)
RDSAdmin->>RDS: describe_db[_cluster]_snapshots
RDS-->>RDSAdmin: Status (creating | available | ...)
RDSAdmin-->>FastAPI: status
FastAPI-->>Client: { snapshot_name, status }
- Async FastAPI REST endpoints + light Jinja2 HTML UI.
- HTTPS only — TLS terminated by Uvicorn using a configured cert/key.
- RDS instance and Aurora cluster snapshot support (routed by endpoint hostname pattern).
- Stateless — safe to run multiple replicas behind a load balancer.
- Multi-cloud deploys — reference Kubernetes manifests + IaC for AWS EKS, AWS ECS, Azure AKS, GCP GKE.
- DevSecOps GitHub Actions — checkout → test → build → Trivy scan → deploy → OWASP ZAP baseline scan.
webapp-fastapi/
├── app1/ # FastAPI application (the service)
│ ├── dbWebAPI.py # FastAPI app, routes, TLS entrypoint
│ ├── dbWebAPI.sh # Container entrypoint shim
│ ├── lib/rdsAdmin.py # boto3 wrapper: RDSCreate/Describe/Delete
│ ├── templates/ # Jinja2 HTML templates for the UI
│ ├── config/appConfig.yaml # host, port, cert, key
│ ├── cert/ # Local-dev TLS material (do not ship real certs)
│ ├── requirements.txt # Python deps
│ ├── Dockerfile # Primary image (python:3.13)
│ ├── Dockerfile.lite # Slim variant (python:3.11-slim)
│ ├── Dockerfile.alpine # Alpine variant
│ ├── deployment.yaml # Sample K8s Deployment
│ ├── service.yaml # Sample K8s Service
│ └── aws-task-definition.json# ECS task definition
│
├── aws/ # AWS deployment assets
│ ├── ecr/deploy/ # Push image to ECR
│ ├── ecs/deploy/ # ECS cluster + service (bash + terraform)
│ ├── eks/deploy/ # EKS cluster (eksctl) + app manifests
│ ├── monitoring/grafana/ # Grafana / infracost samples
│ ├── web_infra/example/ # Reference 3-tier VPC infra
│ │ ├── bash/ # AWS CLI bootstrap scripts
│ │ └── terraform/ # main.tf for VPC/ALB/EC2
│ ├── PermissionBoundary.yaml # IAM permission boundary template
│ └── createPermBoundary.sh
│
├── azure/ # Azure deployment assets
│ ├── acr/deploy/ # ACR setup
│ └── aks/deploy/
│ ├── bash/ # AKS provisioning + nginx ingress
│ └── manifest/ # App + Postgres samples
│
├── gcp/gke/ # GCP deployment assets
│ ├── deploy/
│ │ ├── terraform/ # GKE module + examples (public/private cluster)
│ │ ├── manifests/ # K8s manifests + Dockerfile for GKE
│ │ ├── monitoring/prometheus/
│ │ └── serviceMesh/ # Istio / Linkerd / Anthos installers
│ └── upgrade/ # Cluster + node pool upgrade scripts
│
├── local/deploy/webapp/ # Local docker/desktop deploy helpers
├── lite/ # Slim build context (Dockerfile + requirements)
├── from_dockerhub/ # K8s manifests pulling pre-built Docker Hub image
├── manifests/ # Generic K8s manifests
├── actions/ # Reference GitHub Actions workflows
├── .github/workflows/ # Active workflows (AKS / EKS / GKE)
├── workflows/ # Additional workflow examples
├── images/ # Diagrams and screenshots
├── README.md
└── LICENSE
# 1. Install dependencies
cd app1
pip install -r requirements.txt --user
# 2. Generate a self-signed cert (one-time, for local TLS)
cd cert
openssl genrsa -out key.pem 2048
openssl req -new -x509 -key key.pem -out certificate.pem -days 365 \
-subj "/C=US/ST=GA/L=Atlanta/O=Local/OU=Dev/CN=localhost"
cd ..
# 3. Point appConfig.yaml at your local cert paths, then run:
uvicorn dbWebAPI:app \
--host 0.0.0.0 --port 25443 \
--ssl-keyfile cert/key.pem --ssl-certfile cert/certificate.pem --reloadOpen https://localhost:25443/ (accept the self-signed cert warning).
*/5 * * * * /usr/bin/flock -n /tmp/fullWebapp.lock python /data2/api/db/dbWebAPI.py >> /data2/api/db/log 2>&1The service exposes both HTML pages (for browser use) and JSON
endpoints (for curl / CI). All paths are served over HTTPS on the port
defined in app1/config/appConfig.yaml.
| Method | Path | Form Body | Returns |
|---|---|---|---|
| GET | / |
— | HTML home |
| GET | /backup |
— | HTML tool menu |
| GET | /backup/create |
— | HTML form |
| POST | /backup/create |
endpoint=<db-host> |
{ snapshot_name, status } |
| GET | /backup/status |
— | HTML form |
| POST | /backup/status |
snapshotname=<name>&endpoint=<db> |
{ snapshot_status } |
| GET | /backup/delete |
— | HTML form |
| POST | /backup/delete |
snapshotname=<name>&endpoint=<db> |
{ message } |
| GET | /data |
— | JSON sample |
Cluster vs. instance routing is determined by checking whether the
endpointvalue contains the substringcluster(seedbWebAPI.py).
# Create a snapshot for an Aurora cluster (RO endpoint)
curl -k https://<host>:25443/backup/create \
--data "endpoint=ecomm-integ-postgresdb-aurora.cluster-ro-xxxx.us-east-1.rds.amazonaws.com"
# Check status
curl -k https://<host>:25443/backup/status \
--data "snapshotname=ecomm-integ-postgresdb-aurora-snapshot-2025-06-23-22-21-57" \
--data "endpoint=ecomm-integ-postgresdb-aurora.cluster-ro-xxxx.us-east-1.rds.amazonaws.com"
# Delete
curl -k https://<host>:25443/backup/delete \
--data "snapshotname=ecomm-integ-postgresdb-aurora-snapshot-2025-06-23-22-21-57" \
--data "endpoint=ecomm-integ-postgresdb-aurora.cluster-ro-xxxx.us-east-1.rds.amazonaws.com"app1/config/appConfig.yaml controls
runtime bindings:
appConfig:
hostname: 0.0.0.0
port: 25443
certificate: /app/certs/certificate.pem
key: /app/certs/key.pemAWS credentials are picked up by boto3 via the standard chain (env
vars, shared credentials file, instance/role profile, IRSA, or Workload
Identity in GKE). Ensure the runtime identity has the minimum IAM
permissions required by rdsAdmin.py:
rds:CreateDBSnapshot,rds:CreateDBClusterSnapshotrds:DescribeDBSnapshots,rds:DescribeDBClusterSnapshotsrds:DescribeDBInstances,rds:DescribeDBClustersrds:DeleteDBSnapshot,rds:DeleteDBClusterSnapshotrds:AddTagsToResource(used implicitly when tagging snapshots)
Three Dockerfiles are provided in app1/:
| File | Base image | Purpose |
|---|---|---|
Dockerfile |
python:3.13.1 |
Default — full build |
Dockerfile.lite |
python:3.11-slim |
Slim image for production |
Dockerfile.alpine |
python:*-alpine |
Smallest footprint |
Build and run:
cd app1
docker build -t skondla/dbwebapi:latest .
docker run --rm -p 25443:25443 \
-e AWS_ACCESS_KEY_ID=... -e AWS_SECRET_ACCESS_KEY=... -e AWS_REGION=us-east-1 \
skondla/dbwebapi:latest| Cloud | Compute | Tooling | Path |
|---|---|---|---|
| AWS | EKS | eksctl + kubectl manifests |
aws/eks/deploy/ |
| AWS | ECS | bash + Terraform | aws/ecs/deploy/ |
| AWS | (image) | ECR push helpers | aws/ecr/deploy/ |
| Azure | AKS | bash + nginx-ingress + manifests | azure/aks/deploy/ |
| Azure | (image) | ACR setup | azure/acr/deploy/ |
| GCP | GKE | Terraform module + manifests | gcp/gke/deploy/ |
| Local | Docker | Compose / single-container helpers | local/deploy/webapp/ |
A reference 3-tier VPC (bastion + ALB + private app subnet) is provided under aws/web_infra/example/ for those who want a complete environment, not just the cluster.
The GitHub Actions workflows in .github/workflows/
follow a consistent DevSecOps shape:
Mermaid source
flowchart LR
A[Code Commit] --> B[Checkout]
B --> C[Test]
C --> D[Build & Push<br/>ECR / ACR / Artifact Registry]
D --> E[Trivy Scan<br/>CRITICAL,HIGH]
E --> F[Deploy<br/>EKS / AKS / GKE]
F --> G[Smoke test endpoints]
G --> H[OWASP ZAP baseline]
G --> I[Slack notify]
The original asset is preserved at images/DevSecOps_with_GutHub_Actions.png.
# Is the process running?
ps -ef | grep dbWebAPI.py
# Is the port bound?
netstat -an | grep 25443
lsof -i :25443
# Tail logs (when launched via the cron flock pattern)
tail -f /data2/api/db/log
# In Kubernetes
kubectl -n <ns> get pods -l app=dbwebapi
kubectl -n <ns> logs deploy/db-backup-tool -fMaintainer: Sudheer (Sam) Kondla — skondla@me.com
Released under the terms of the LICENSE file in this repository.