Skip to content

RĂ©sumĂ© Infra EKS — fastapi-eks-project

Contexte projet

Portfolio DevOps — FastAPI + PostgreSQL sur AWS EKS. GitLab : gitlab.com/yk-devops/fastapi-eks-project Dev Container : VS Code avec AWS CLI, Terraform, kubectl, Helm.


Stack technique

App         : FastAPI + PostgreSQL + Alembic + PyJWT + bcrypt
Cloud       : AWS eu-west-3 (Paris)
IaC         : Terraform 1.15
Container   : Docker → ECR → EKS
CI/CD       : GitLab CI/CD (runner self-hosted Ubuntu 22.04 ESXi)
Routing     : Envoy Gateway (Gateway API)
TLS         : cert-manager + Let's Encrypt (DNS-01 via Cloudflare)
Domaine     : devopsyouss.com (Cloudflare)

Architecture AWS

Internet (HTTPS — api.devopsyouss.com)
    ↓
ELB (créé par Envoy Gateway — ports 80 + 443)
    ↓
Envoy Proxy Pod (TLS terminĂ© ici — cert rempli par cert-manager + Let's Encrypt)
    ↓
Service ClusterIP (fastapi)
    ↓
FastAPI Pod (namespace: fastapi)
    ↓
RDS PostgreSQL (subnet privé)

Terraform — 2 workspaces sĂ©parĂ©s

persistent/ (jamais détruit)

ECR : fastapi-eks/fastapi
IAM : gitlab_ci (ECR push) + gitlab_ci_infra (terraform)
Secrets Manager : fastapi-eks/app (DB_PASSWORD + SECRET_KEY) → consommĂ© par ESO (#33)
State S3 : yk-devops-terraform-state/fastapi-eks/persistent/

ephemeral/ (apply matin, destroy soir)

VPC : 10.0.0.0/16, 2 subnets publics + 2 privés
NAT Gateway : obligatoire pour nodes EKS
EKS : fastapi-eks-cluster, version 1.32, node t3.medium
RDS : PostgreSQL 16, db.t3.micro, subnet privé
IRSA ESO (#33) : provider OIDC du cluster + rĂŽle fastapi-eks-eso-irsa (lecture du secret fastapi-eks/app)
State S3 : yk-devops-terraform-state/fastapi-eks/ephemeral/

Scripts quotidiens

./aws-start.sh   # matin → terraform apply + kubectl config
./aws-stop.sh    # soir  → kubectl delete gateway + terraform destroy

Pipeline CI/CD GitLab

.gitlab-ci.yml (app pipeline)

Stages : test → security → build → scan-image → promote → deploy

test          : pytest + PostgreSQL service
security      : SAST, Secret Detection, Trivy fs, tfsec, kube-linter
build         : Kaniko → ECR (tag: SHA-candidate)
scan-image    : Trivy image scan depuis ECR
promote       : Kaniko → ECR (tag: SHA + latest)
deploy        : kustomize edit set image + kubectl apply -k k8s/base/ (manual, si input deploy=true). Secret géré par ESO, plus de kubectl create secret

Déclenché sur : push, MR, develop, main
Deploy        : Run Pipeline (web) + input deploy=true (dropdown), infra EKS up requise
Inputs        : deploy = false | true (mappé sur la variable DEPLOY)

.gitlab-ci-infra.yml (infra pipeline)

Stages : infra → bootstrap → teardown → destroy

infra-status  : aws eks list-clusters, rds, ecr...
infra-start   : terraform apply + kubectl get nodes
bootstrap     : Ansible — Envoy Gateway + metrics-server + cert-manager + ClusterIssuers + External Secrets Operator + exposition (GatewayClass + Gateway + Certificate) + RBAC user CI (ESO + HTTPRoute) (action=start)
infra-stop    : aws-stop.sh (cleanup K8s + terraform destroy)

Déclenché sur : Run Pipeline (web) + Schedule 20h
Inputs        : action = status | start | stop

Variables GitLab CI/CD

APP PIPELINE :
AWS_ACCESS_KEY_ID      → gitlab_ci (ECR push)
AWS_SECRET_ACCESS_KEY  → gitlab_ci (ECR push)
AWS_DEFAULT_REGION     → eu-west-3
ECR_REGISTRY           → 199167114788.dkr.ecr.eu-west-3.amazonaws.com
ECR_REPOSITORY         → fastapi-eks/fastapi
SECRET_KEY             → JWT secret

INFRA PIPELINE :
AWS_INFRA_ACCESS_KEY_ID     → gitlab_ci_infra
AWS_INFRA_SECRET_ACCESS_KEY → gitlab_ci_infra
TF_VAR_db_password          → <REDACTED - stored in GitLab CI as Masked variable>
CLOUDFLARE_API_TOKEN        → token API Cloudflare (Masked + Protected, Zone > Zone Read + DNS Edit)

Note ESO (#33) : TF_VAR_db_password alimente aussi le secret Secrets Manager persistent (mĂȘme valeur que RDS). SECRET_KEY est gĂ©nĂ©rĂ© par Terraform (random_password) et stockĂ© dans Secrets Manager. Depuis MR-D, le job deploy ne crĂ©e plus le Secret (ESO le synchronise) : la variable CI SECRET_KEY est devenue inutile cĂŽtĂ© deploy et peut ĂȘtre supprimĂ©e des settings GitLab.


Kubernetes manifests (k8s/)

k8s/base/  (déployé en bloc via kustomize : kubectl apply -k k8s/base/)
├── serviceaccount.yaml             → SA dĂ©diĂ© fastapi, automountServiceAccountToken false
├── configmap.yaml                  → DB_HOSTNAME, DB_PORT, DB_NAME...
├── deployment.yaml                 → FastAPI pods, probes /healthz, resources, securityContext
├── service.yaml                    → ClusterIP port 80→8080
├── hpa.yaml                        → min:1, max:5, cpu:70%, mem:80%
├── pdb.yaml                        → PodDisruptionBudget minAvailable 1
├── networkpolicy-default-deny.yaml → deny-all ingress + egress
├── networkpolicy-fastapi.yaml      → ingress 8080 ; egress 5432 (RDS), 443 (AWS), 53 (DNS)
├── networkpolicy-postgres.yaml     → rĂšgles pour le pod postgres (prĂ©sent en local-kind)
├── secretstore.yaml                → ESO SecretStore (AWS Secrets Manager, auth IRSA contrîleur)
├── externalsecret.yaml             → ESO ExternalSecret → Secret fastapi-secrets (DB_PASSWORD, SECRET_KEY)
└── httproute.yaml                  → Gateway API HTTPRoute (app : route api.devopsyouss.com, ownĂ© par le deploy CI, #60)

Le namespace fastapi (+ labels PSA enforce restricted) n'est PAS dans k8s/base :
il est créé par le bootstrap Ansible (cluster-admin). Le user CI deploy en
least-privilege ne peut pas patcher un objet cluster-scoped (INC-045).

✅ Les NetworkPolicy sont enforced sur EKS depuis #55 : vpc-cni dĂ©clarĂ© en addon
EKS managé avec enableNetworkPolicy=true (résout INC-046). Validé par test négatif
(egress port 80 → timeout) + test positif (/healthz/ready → 200). Voir validation-runbook.md.

✅ L'exposition (GatewayClass + Gateway + Certificate) est posĂ©e par le bootstrap
Ansible, pas par le deploy CI (#60, ADR 010). Raison : GatewayClass cluster-scoped +
CRDs Gateway API / cert-manager non couverts par "edit" (mĂȘmes classes qu'INC-045/047/048).
Le HTTPRoute reste owné par l'app (k8s/base) avec son binding RBAC explicite
fastapi-deploy-httproute, pour faire évoluer les routes (canary, blueprints) sans re-bootstrap.

k8s/platform/  (exposition — appliquĂ©e par le bootstrap Ansible, cluster-admin, #60)
├── gateway.yaml                    → GatewayClass envoy + Gateway fastapi-gateway (listeners 80/443, TLS Terminate)
└── certificate.yaml                → Certificate fastapi-tls (cert-manager, ClusterIssuer letsencrypt-prod)

k8s/overlays/
├── ingress-alb/        → ALB Ingress Controller (option A, Ă©cartĂ©e #34)
└── local-kind/         → lab local (postgres en pod + ns baseline), dev only (#46)

IAM — Least Privilege

gitlab_ci :
→ ECR push uniquement (app pipeline)
→ ecr:GetAuthorizationToken, BatchCheck, InitiateUpload...

gitlab_ci_infra :
→ terraform_ci policy (ec2:*, eks:*, rds:*, iam:limited + OIDC provider + secretsmanager read pour IRSA #33)
→ infra_status policy (read-only EKS, EC2, RDS, ECR, ELB)

Coûts AWS (ephemeral 4h/jour)

NAT Gateway  : 0.045$/h × 4 = 0.18$/jour
EKS Control  : 0.10$/h  × 4 = 0.40$/jour
t3.medium    : 0.047$/h × 4 = 0.19$/jour
RDS micro    : 0.02$/h  × 4 = 0.08$/jour
Total        : ~0.85$/jour → ~17$/mois (20 jours)

Persistent (toujours) :
ECR          : ~0.01$/mois
IAM          : gratuit

État Sprint 3

✅ Terraform persistent/ephemeral
✅ Kubernetes manifests (base + overlays)
✅ Envoy Gateway opĂ©rationnel
✅ FastAPI + RDS validĂ© sur EKS
✅ Pipeline build/scan/promote
✅ Pipeline infra start/stop/status
✅ IAM Least Privilege (2 users)
✅ Schedule nightly destroy
✅ Stage deploy CI/CD validĂ© end-to-end via kustomize (#52)
✅ PSA enforce restricted effectif sur EKS (#48, INC-045)

✅ NetworkPolicy enforced via VPC CNI managĂ© (#55, INC-046)
❌ ALB Ingress Controller (#34) — Ă©cartĂ©, direction gateway-api actĂ©e pour portabilitĂ© multi-cloud
✅ HTTPS public api.devopsyouss.com — cert-manager + Let's Encrypt DNS-01 Cloudflare (#28)
🚧 Secrets Manager + ESO (#33) — MR-A→D livrĂ©es (secret persistent fastapi-eks/app, provider OIDC + rĂŽle IRSA ephemeral, install ESO via bootstrap, manifests SecretStore/ExternalSecret, deploy sans Secret impĂ©ratif). Sync ESO de fastapi-secrets validĂ©e live le 2026-05-29. Reste : valider le deploy app end-to-end via le pipeline develop, puis fermer #33

Commandes utiles

# AWS
awslogin                                    # ouvrir session aws-vault
aws sts get-caller-identity                 # vérifier l'identité
aws eks list-clusters                       # lister clusters EKS
aws ecr list-images --repository-name fastapi-eks/fastapi

# Kubernetes
kubectl get nodes
kubectl get all -n fastapi
kubectl logs -n fastapi -l app=fastapi -f
kubectl port-forward -n fastapi deployment/fastapi 8080:8080

# Terraform
cd terraform/ephemeral && terraform output  # voir outputs
cd terraform/persistent && terraform state list

# Pipeline infra
./aws-start.sh   # démarrer l'infra
./aws-stop.sh    # arrĂȘter l'infra