diff --git a/README.md b/README.md index 96b8f3a..3916cf4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This repository is a production-inspired DevSecOps capstone for a small voting application. It combines application code, Terraform infrastructure, Kubernetes GitOps deployment, CI/CD security gates, image signing, admission policy, observability, runtime response, and disaster recovery. -The current implementation uses AWS as the active primary site and Azure as the warm standby site. AWS and Azure are connected by a route-based IPsec VPN with BGP. PostgreSQL data is replicated from AWS RDS to Azure PostgreSQL Flexible Server with native PostgreSQL logical replication. +The current implementation uses AWS as the active primary site and Azure as the warm standby site. AWS and Azure are connected by a route-based IPsec VPN with BGP. The codebase supports PostgreSQL logical replication from AWS RDS to Azure PostgreSQL Flexible Server; in the cost-capped demo, the Azure database standby can be enabled for a DR drill or left as a restore-required placeholder. ## Current Architecture @@ -31,13 +31,13 @@ AWS primary site Prometheus/Grafana, Loki/Promtail, Falco/Falcosidekick Azure warm standby site - VNet, AKS, ACR, Azure Key Vault, Azure PostgreSQL Flexible Server + VNet, AKS, ACR, Azure Key Vault, optional Azure PostgreSQL Flexible Server ArgoCD standby controller, External Secrets Operator Cross-cloud path AWS VPN Gateway <-> Azure Virtual Network Gateway BGP routes carry private traffic between the two networks - PostgreSQL logical replication sends WAL deltas from AWS to Azure + Optional PostgreSQL logical replication sends WAL deltas from AWS to Azure during a DB standby drill ``` Route53 DNS failover support is implemented in `scripts/configure-route53-failover.ps1`, but it requires a real Route53 hosted zone/domain. The current AWS account has no hosted zone, so public DNS failover is ready as code but not live-configured. @@ -59,7 +59,7 @@ On Azure, only the `vote` service is exposed with a public LoadBalancer by defau | Secrets | External Secrets Operator syncs AWS Secrets Manager and Azure Key Vault into Kubernetes. Secrets are not committed in Helm values. | | Runtime security | Falco detects suspicious runtime behavior and can open a GitHub incident workflow. Quarantine is a manual approval workflow. | | Observability | kube-prometheus-stack, Grafana SLI/SLO dashboard, Loki, Promtail, and PrometheusRule resources. | -| DR | Azure warm standby, ArgoCD sync, PostgreSQL logical replication, and Route53 failover script when a hosted zone exists. | +| DR | Azure warm standby, ArgoCD sync, optional PostgreSQL logical replication or restore-required DB placeholder, and Route53 failover script when a hosted zone exists. | ## Repository Structure @@ -181,6 +181,10 @@ Use the verified demo runbook: docs/teacher-aligned-demo-runbook.md docs/devsecops-phase-model.md docs/teacher-aligned-architecture.md +docs/architecture-conceptual.md +docs/devsecops-pipeline-diagram.md +docs/pipeline-frameworks.md +docs/demo-checklist.md ``` Useful scripts: @@ -215,6 +219,6 @@ az network vnet-gateway list -o table - Azure ACR uses Basic SKU. Premium-only controls such as private endpoints, geo-replication, image quarantine, and Defender integration are documented as production hardening items. - Azure image verification with Kyverno is disabled by default because Kyverno cannot verify private ACR manifests without extra registry credentials. AWS EKS remains the enforced signed-image admission path through Sigstore policy-controller. -- Azure warm standby uses an in-cluster Redis service to avoid extra managed Redis cost. PostgreSQL state is still replicated with native logical replication. +- Azure warm standby uses an in-cluster Redis service to avoid extra managed Redis cost. PostgreSQL standby is optional in the cost-capped demo; when disabled, Azure runtime secrets intentionally point at a restore-required database host. - Route53 failover requires a real hosted zone. The script exists, but no hosted zone is currently present in the AWS account. - GitHub branch protection is configured, but repository owners/admins can still bypass unless admin bypass is explicitly disabled in GitHub rulesets. diff --git a/docs/architecture-conceptual.md b/docs/architecture-conceptual.md new file mode 100644 index 0000000..05e6fd1 --- /dev/null +++ b/docs/architecture-conceptual.md @@ -0,0 +1,173 @@ +# Kien Truc Tong The Theo Ban Chat + +Tai lieu nay dung de trinh bay voi thay theo muc "em hieu he thong dang giai quyet van de gi", khong di vao ten tool truoc. Tool/framework nam o tai lieu pipeline rieng. + +## 1. Developer Dua Code Vao Repository + +Developer khong dua thang code len production. Developer tao branch rieng cho tung feature hoac bug fix, sau do tao pull request vao nhanh tich hop. + +Repository la nguon su that cua he thong: no luu source code, cau hinh, ha tang, lich su thay doi va la noi kich hoat cac buoc kiem soat. + +Y nghia: + +- Tach code dang lam voi code on dinh. +- Ghi lai ai sua, sua gi, vi sao sua. +- Tao noi de review truoc khi merge. +- Tao diem kich hoat cho kiem tra tu dong. + +Ghi chu ve tu "pool": trong boi canh nay cach goi dung thuong la `pull request`, `integration branch`, hoac `merge queue`. Neu y la noi gom nhieu feature de kiem tra chung thi do la nhanh tich hop, vi du `dev`. + +## 2. Quet So Bo Khi Co Pull Request + +Khi pull request duoc tao, he thong can quet so bo code truoc khi cho code vao nhanh tich hop. Muc tieu la bat loi som, khong doi den luc deploy moi phat hien. + +Vi du quan trong nhat la secret scanning. Neu developer hardcode token, password, private key hoac access key vao code, secret do co the nam trong lich su Git ke ca sau khi da xoa. Vi vay secret phai bi chan ngay tai pull request. + +Ngoai secret, buoc so bo co the kiem tra: + +- Mau code co dau hieu gay bug hoac lo hong. +- Thu vien phu thuoc co rui ro. +- Container build file, deployment manifest, infrastructure code co cau hinh nguy hiem. +- Format va loi cau hinh co ban. + +Y nghia: + +- Feedback nhanh cho developer. +- Giam chi phi sua loi. +- Ngan loi ro rang di vao nhanh tich hop. +- Bao ve repository khoi secret va cau hinh nhay cam. + +## 3. Nhanh Tich Hop Gom Nhieu Feature + +Sau khi pull request pass kiem tra so bo va duoc review, code duoc merge vao nhanh tich hop, vi du `dev`. + +Nhanh tich hop khong phai production. No la noi gom nhieu feature lai de kiem tra xem chung co hoat dong dung khi di cung nhau hay khong. + +Ly do can nhanh tich hop: + +- Tung feature rieng co the dung, nhung khi ghep voi feature khac co the xung dot. +- Cau hinh ung dung, ha tang va deployment can duoc kiem tra nhu mot bo. +- Can co mot noi tao release candidate truoc khi vao nhanh release. + +Y nghia: + +- Kiem tra chat luong o muc tong the. +- Phat hien loi do nhieu thay doi ket hop. +- Chuan bi mot ban release candidate sach hon. + +## 4. Ranh Gioi Release + +Khi nhanh tich hop da on dinh, he thong tao pull request tu `dev` sang `main`. Day la ranh gioi release. + +O buoc nay cau hoi khong con la "feature nay co dung khong", ma la "toan bo phien ban nay co du dieu kien de release khong". + +Can kiem tra nghiem hon: + +- Code co lo hong nghiem trong khong. +- Cau hinh ha tang co mo quyen qua rong khong. +- Manifest Kubernetes co vi pham policy khong. +- Dependency co rui ro cao khong. +- Ban release co the build thanh artifact nhat quan khong. + +Y nghia: + +- Tach moi truong tich hop voi moi truong release. +- Chi cho ban da qua gate vao `main`. +- Tao diem kiem soat truoc khi sinh artifact that. + +## 5. Build Artifact Bat Bien + +Sau khi code vao `main`, pipeline build source code thanh container image. Tu luc nay he thong deploy artifact, khong deploy source code truc tiep. + +Artifact can bat bien. Nghia la cung mot image digest thi noi dung ben trong khong thay doi. Neu chi dung tag nhu `latest`, ta khong biet production dang chay dung ban nao. Neu dung digest, ta truy vet duoc production dang chay image nao va image do sinh tu commit nao. + +Y nghia: + +- Bien source code thanh don vi trien khai. +- Dam bao staging va production dung cung artifact da kiem tra. +- Truy vet duoc tu production ve commit nguon. + +## 6. Kiem Soat Chuoi Cung Ung Phan Mem + +Sau khi build image, he thong can chung minh image do dung la image do pipeline tao ra va chua bi thay the. + +Can tra loi: + +- Image nay sinh tu commit nao? +- Image nay gom nhung package/dependency nao? +- Image nay co bi thay the tren registry khong? + +Vi vay artifact can co danh sach thanh phan va chu ky. Danh sach thanh phan giup biet trong image co gi. Chu ky giup cluster xac minh image den tu pipeline hop le. + +Y nghia: + +- Chong thay the image. +- Truy vet khi co CVE moi. +- Tao bang chung bao mat chuoi cung ung. + +## 7. Staging Truoc Production + +Truoc khi vao production, image phai duoc deploy len staging. Staging la moi truong gan production, dung de kiem tra app khi da chay that voi service, config, secret, network va database. + +Can kiem tra: + +- Pod co san sang khong. +- Endpoint co tra ve thanh cong khong. +- App co ket noi duoc thanh phan phu thuoc khong. +- Runtime co loi khong. +- Quet dong co phat hien loi web co ban khong. + +Y nghia: + +- Bat loi chi xuat hien khi app chay that. +- Kiem tra duong di tu user den service. +- Giam rui ro truoc khi cap nhat production. + +## 8. Promotion Bang GitOps + +Sau khi staging pass, pipeline khong day thang len production. Pipeline tao mot thay doi ve desired state cua production trong Git, goi la promotion PR. + +Production chi thay doi khi promotion PR duoc chap nhan. Cluster doc Git va tu dong dong bo trang thai production theo noi dung trong Git. + +Y nghia: + +- Git la nguon su that cua production. +- Moi thay doi production co review va lich su. +- De rollback vi co the quay lai desired state cu. +- Tach quyen build artifact voi quyen thay doi production. + +## 9. Kiem Soat Runtime + +Sau khi ung dung da chay, van can kiem soat runtime. Pipeline khong du de bao ve toan bo he thong, vi co the co nguoi apply tay, dung image sai, gan secret sai hoac workload co hanh vi bat thuong. + +Cluster can co cac lop: + +- Chi chap nhan image co nguon goc hop le. +- Khong de secret nam truc tiep trong manifest. +- Gioi han quyen cua workload. +- Kiem soat network giua service. +- Ghi log, metric va canh bao khi co bat thuong. + +Y nghia: + +- Bao ve he thong sau khi deploy. +- Chan cau hinh sai tai runtime. +- Tao bang chung van hanh khi co incident. + +## 10. Multi-Cloud Va Disaster Recovery + +He thong co AWS la site chinh va Azure la warm standby. Warm standby co nghia la moi truong du phong da ton tai va san sang nhan workload/traffic khi can, nhung traffic chinh van di vao AWS. + +DR khong chi la co them mot cluster. DR can co network path, data replication, cach chuyen traffic va quy trinh khoi phuc. + +Y nghia: + +- Giam phu thuoc vao mot cloud. +- Co duong failover khi primary site loi. +- Chung minh kha nang recover thay vi chi deploy thanh cong. + +## 11. Doan Noi 30 Giay + +```text +Kien truc cua em di theo dong chay DevSecOps. Developer khong day thang code len production ma tao pull request vao repository. PR duoc quet so bo de chan secret, loi code va cau hinh nguy hiem. Sau khi qua review, feature vao nhanh tich hop de kiem tra nhieu thay doi chung voi nhau. Khi san sang release, dev tao PR sang main va chay gate nghiem hon. Main moi build ra container image bat bien, co danh sach thanh phan va chu ky. Image duoc deploy len staging de test runtime va DAST. Neu staging pass, pipeline tao promotion PR de cap nhat desired state production. Production va Azure khong nhan lenh deploy truc tiep tu CI, ma duoc dong bo tu Git. Runtime tiep tuc co policy, secret management, monitoring va DR. +``` diff --git a/docs/demo-checklist.md b/docs/demo-checklist.md new file mode 100644 index 0000000..1ad97c4 --- /dev/null +++ b/docs/demo-checklist.md @@ -0,0 +1,226 @@ +# Demo Can Trinh Bay Nhung Gi + +Tai lieu nay la checklist de quay hoac trinh bay demo. Muc tieu la chung minh ban chat he thong, khong chi mo tung tool len cho thay xem. + +## 1. Mo Dau: Noi Kien Truc Trong 1 Phut + +Noi ngan gon: + +```text +Do an cua em la mot DevSecOps platform cho voting app. Developer khong deploy truc tiep len production. Moi thay doi di qua repository, pull request, security gate, build artifact, signing, staging test, promotion PR va GitOps deployment. AWS la primary site, Azure la warm standby site. Sau khi deploy, cluster van co runtime policy, secret management, monitoring va DR. +``` + +Can mo: + +- `docs/architecture-conceptual.md` +- `docs/devsecops-pipeline-diagram.md` +- So do tong the trong file do neu can. + +## 2. Demo Repository Va Branch Boundary + +Muc tieu: chung minh code di qua pull request va branch protection. + +Can demo: + +- Repository co source code, IaC, Helm, workflow, docs. +- Branch `dev` la integration branch. +- Branch `main` la release/production desired state. +- `dev` va `main` co required checks va review. + +Lenh: + +```powershell +gh api /repos/erotonin/devsecops-voting/branches/dev/protection --jq ".required_status_checks.contexts" +gh api /repos/erotonin/devsecops-voting/branches/main/protection --jq ".required_status_checks.contexts" +``` + +## 3. Demo PR Security Gate + +Muc tieu: chung minh code moi khong duoc merge neu chua qua kiem tra. + +Can demo: + +- Mo mot PR da pass gate gan day. +- Chi vao required check. +- Giai thich gate so bo gom secret scanning, SAST, dependency/config scan. + +Noi voi thay: + +```text +O buoc nay em muon bat loi som. Vi du secret hardcode phai bi chan ngay khi tao PR, khong doi den luc deploy. +``` + +## 4. Demo Release Pipeline + +Muc tieu: chung minh full pipeline tu `main` build ra artifact that. + +Can demo GitHub Actions run: + +- Main release run `26565822002`. +- Cac job build `vote`, `result`, `worker`. +- SBOM artifact. +- Cosign signing va verification. +- Trivy image scan. +- Deploy staging. +- DAST staging. +- Open promotion PR. + +Noi voi thay: + +```text +Sau khi vao main, pipeline moi tao artifact. Image duoc build, sinh SBOM, ky so, verify chu ky va scan CVE. Artifact nao khong qua cac buoc nay thi khong duoc dua vao staging. +``` + +## 5. Demo Staging Va DAST + +Muc tieu: chung minh ung dung da chay that truoc khi promotion. + +Can demo: + +- ArgoCD app `voting-staging` la `Synced Healthy`. +- Endpoint `/healthz` staging HTTP 200. +- OWASP ZAP baseline pass. + +Lenh: + +```powershell +kubectl --context arn:aws:eks:us-east-1:800557027783:cluster/voting-app-cluster ` + -n argocd get applications.argoproj.io voting-staging + +$h=(kubectl --context arn:aws:eks:us-east-1:800557027783:cluster/voting-app-cluster ` + -n voting-staging get svc vote -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') +Invoke-WebRequest -UseBasicParsing -Uri "http://$h/healthz" +``` + +## 6. Demo Promotion PR + +Muc tieu: chung minh production khong deploy truc tiep. + +Can demo: + +- Promotion PR `#74`. +- File thay doi: `k8s/values-prod.yaml`, `k8s/values-azure.yaml`. +- Noi dung thay doi la image digest production/Azure. + +Lenh: + +```powershell +gh pr view 74 --json url,state,mergedAt,mergeCommit +gh pr diff 74 --name-only +``` + +Noi voi thay: + +```text +CI khong day thang len production. CI chi tao PR thay doi desired state. Khi PR nay merge, ArgoCD moi dong bo production tu Git. +``` + +## 7. Demo Production Va Azure Warm Standby + +Muc tieu: chung minh release da vao hai moi truong. + +Can demo: + +- AWS production `Synced Healthy`. +- Azure warm standby `Synced Healthy`. +- Pod production/Azure running. +- `/healthz` cua production va Azure HTTP 200. + +Lenh: + +```powershell +kubectl --context arn:aws:eks:us-east-1:800557027783:cluster/voting-app-cluster ` + -n argocd get applications.argoproj.io voting-production + +kubectl --context devsecops-voting-aks ` + -n argocd get applications.argoproj.io voting-azure + +$prod=(kubectl --context arn:aws:eks:us-east-1:800557027783:cluster/voting-app-cluster ` + -n voting-production get svc vote -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') +Invoke-WebRequest -UseBasicParsing -Uri "http://$prod/healthz" + +$az=(kubectl --context devsecops-voting-aks ` + -n voting get svc vote -o jsonpath='{.status.loadBalancer.ingress[0].ip}') +Invoke-WebRequest -UseBasicParsing -Uri "http://$az/healthz" +``` + +## 8. Demo Runtime Security + +Muc tieu: chung minh bao mat khong dung lai o CI/CD. + +Can demo: + +- Policy admission trong cluster. +- External Secrets Operator. +- Monitoring/logging/runtime detection neu can. + +Lenh goi y: + +```powershell +kubectl --context arn:aws:eks:us-east-1:800557027783:cluster/voting-app-cluster get clusterimagepolicy +kubectl --context arn:aws:eks:us-east-1:800557027783:cluster/voting-app-cluster get constrainttemplates +kubectl --context arn:aws:eks:us-east-1:800557027783:cluster/voting-app-cluster get externalsecrets -A +kubectl --context arn:aws:eks:us-east-1:800557027783:cluster/voting-app-cluster -n monitoring get pods +kubectl --context arn:aws:eks:us-east-1:800557027783:cluster/voting-app-cluster -n logging get pods +kubectl --context arn:aws:eks:us-east-1:800557027783:cluster/voting-app-cluster -n falco get pods +.\scripts\test-policy-rejects.ps1 -Context arn:aws:eks:us-east-1:800557027783:cluster/voting-app-cluster -Namespace voting-staging +``` + +Ghi chu: trong namespace co Sigstore policy, mot so manifest xau co the bi policy-controller chan truoc Gatekeeper. Diem can noi la admission layer da reject workload khong hop policy. + +## 9. Demo DR Neu Co Thoi Gian + +Muc tieu: chung minh co ke hoach recover. + +Can demo: + +- So do AWS primary va Azure standby. +- VPN/BGP giua hai cloud. +- PostgreSQL logical replication. +- Script failover/Route53 neu co hosted zone. + +Lenh an toan de demo warm standby ma khong scale lai node pool: + +```powershell +.\scripts\dr-failover.ps1 -SkipScale +``` + +Noi voi thay: + +```text +DR khong chi la co them mot cluster. No can network path, data replication va cach chuyen traffic. Trong do an nay AWS la primary, Azure la warm standby. +``` + +## 10. Thu Tu Demo De Khong Bi Roi + +1. Mo `docs/architecture-conceptual.md` va noi ban chat kien truc. +2. Mo `docs/devsecops-pipeline-diagram.md` de nguoi xem nhin duoc toan bo pipeline. +3. Mo GitHub branch protection de chung minh boundary. +4. Mo PR/check de chung minh gate. +5. Mo Actions run `26565822002` de chung minh build/sign/scan/staging/DAST. +6. Mo promotion PR `#74` de chung minh production qua GitOps. +7. Mo terminal kiem tra ArgoCD AWS/Azure `Synced Healthy`. +8. Goi `/healthz` staging, production, Azure. +9. Neu con thoi gian, noi runtime security va DR. + +## 11. Cau Tra Loi Nhanh Khi Thay Hoi + +**Tai sao khong deploy thang tu CI vao production?** + +Vi production can audit va rollback ro rang. Neu deploy bang GitOps, moi thay doi production la mot commit/PR trong Git. + +**Tai sao can staging?** + +Vi nhieu loi chi xuat hien khi app chay that voi service, secret, network va database. + +**Tai sao can SBOM va signing?** + +SBOM cho biet image gom thanh phan nao. Signing chung minh image do do pipeline hop le tao ra va chua bi thay the. + +**Tai sao can Azure neu da co AWS?** + +AWS la primary. Azure la warm standby de co duong recover khi primary site gap su co. + +**Tool nao quan trong nhat?** + +Khong co mot tool quan trong nhat. Quan trong la cac lop kiem soat: source control, security gate, artifact integrity, GitOps deployment, runtime policy va recovery. diff --git a/docs/demo-recording-guide.md b/docs/demo-recording-guide.md index fb6e9ad..d7efd0f 100644 --- a/docs/demo-recording-guide.md +++ b/docs/demo-recording-guide.md @@ -470,7 +470,7 @@ Say: - "AWS is primary." - "Azure is warm standby." - "DR flow: scale/sync AKS, verify PostgreSQL logical replication, switch endpoint/DNS when a hosted zone exists, measure RTO/RPO." -- "The current build uses native PostgreSQL logical replication from AWS RDS to Azure PostgreSQL. Backup/seed remains a fallback path for cost-capped rebuilds." +- "The codebase supports native PostgreSQL logical replication from AWS RDS to Azure PostgreSQL. In the cost-capped live demo, Azure DB can stay as a restore-required placeholder unless the DR database drill is enabled." ## Part 15 - EKS upgrade readiness diff --git a/docs/devsecops-pipeline-diagram.md b/docs/devsecops-pipeline-diagram.md new file mode 100644 index 0000000..b323905 --- /dev/null +++ b/docs/devsecops-pipeline-diagram.md @@ -0,0 +1,167 @@ +# So Do Pipeline DevSecOps + +File nay dung de mo khi can giai thich pipeline bang hinh. Cach doc: di tu trai sang phai, moi khoi la mot diem kiem soat rui ro. Tool cu the nam trong ngoac de nguoi xem biet implementation, nhung y nghia chinh la muc tieu kiem soat. + +## 1. Pipeline Tong The + +```mermaid +flowchart LR + Dev["Developer
viet feature/fix"] --> Branch["Feature branch
tach thay doi rieng"] + Branch --> PRDev["Pull request vao dev
review + fast feedback"] + + PRDev --> Secret["Secret scan
chan token/password/key hardcode"] + PRDev --> SAST["Static code scan
bat bug va mau lo hong"] + PRDev --> SCA["Source dependency scan / SCA
bat CVE trong lockfile va third-party libraries"] + PRDev --> ConfigScan["Config/IaC scan
bat cau hinh nguy hiem"] + + Secret --> FeatureGate{"Feature gate pass?"} + SAST --> FeatureGate + SCA --> FeatureGate + ConfigScan --> FeatureGate + FeatureGate -- "Fail" --> FixFeature["Developer sua loi
push commit moi"] + FixFeature --> Branch + FeatureGate -- "Pass + review" --> DevBranch["dev
integration branch"] + + DevBranch --> Integration["Integration gate
kiem tra nhieu feature khi ghep chung"] + Integration --> ReleasePR["PR dev -> main
release boundary"] + ReleasePR --> ReleaseGate{"Release gate pass?"} + ReleaseGate -- "Fail" --> FixRelease["Sua release candidate"] + FixRelease --> DevBranch + ReleaseGate -- "Pass + review" --> Main["main
release source"] + + Main --> Build["Build container images
vote/result/worker"] + Build --> SBOM["Generate SBOM
biet image gom thanh phan nao"] + Build --> Sign["Sign image digest
chung minh image dung nguon"] + Build --> ImageScan["Image vulnerability scan
chan CVE nghiem trong"] + + SBOM --> ArtifactGate{"Artifact gate pass?"} + Sign --> ArtifactGate + ImageScan --> ArtifactGate + ArtifactGate -- "Fail" --> StopRelease["Dung release
khong deploy"] + ArtifactGate -- "Pass" --> StagingGit["Cap nhat desired state staging
GitOps branch staging"] + + StagingGit --> Staging["ArgoCD deploy staging
app chay that tren Kubernetes"] + Staging --> Smoke["Smoke test /healthz
kiem tra app song"] + Staging --> DAST["DAST baseline
quet web app dang chay"] + + Smoke --> StagingGate{"Staging gate pass?"} + DAST --> StagingGate + StagingGate -- "Fail" --> NoPromote["Khong promote
sua loi va build lai"] + StagingGate -- "Pass" --> PromotePR["Promotion PR
cap nhat values prod/Azure"] + + PromotePR --> ProdReview{"Review production change?"} + ProdReview -- "Reject" --> NoPromote + ProdReview -- "Approve + merge" --> ProdGit["main
desired state production"] + + ProdGit --> AWSProd["AWS production
ArgoCD sync"] + ProdGit --> AzureStandby["Azure warm standby
ArgoCD sync"] + + AWSProd --> Runtime["Runtime controls
policy, secret, monitor, log, alert"] + AzureStandby --> Runtime + Runtime --> DR["Recovery / DR
failover path khi primary loi"] + + classDef human fill:#f8fafc,stroke:#334155,stroke-width:1px,color:#0f172a; + classDef gate fill:#fef3c7,stroke:#b45309,stroke-width:2px,color:#78350f; + classDef security fill:#fee2e2,stroke:#b91c1c,stroke-width:1px,color:#7f1d1d; + classDef artifact fill:#dbeafe,stroke:#1d4ed8,stroke-width:1px,color:#1e3a8a; + classDef deploy fill:#dcfce7,stroke:#15803d,stroke-width:1px,color:#14532d; + classDef fail fill:#f3f4f6,stroke:#6b7280,stroke-dasharray: 4 3,color:#111827; + + class Dev,Branch human; + class FeatureGate,ReleaseGate,ArtifactGate,StagingGate,ProdReview gate; + class Secret,SAST,SCA,ConfigScan,Integration,ReleasePR security; + class Build,SBOM,Sign,ImageScan artifact; + class StagingGit,Staging,Smoke,DAST,PromotePR,ProdGit,AWSProd,AzureStandby,Runtime,DR deploy; + class FixFeature,FixRelease,StopRelease,NoPromote fail; +``` + +## 2. Pipeline Theo Lane + +So do nay dung khi muon giai thich ai lam gi va ranh gioi nam o dau. + +```mermaid +flowchart TB + subgraph L1["Developer / Git"] + A1["Feature branch"] + A2["Pull request vao dev"] + A3["dev integration branch"] + A4["Pull request dev -> main"] + A5["main release branch"] + end + + subgraph L2["Security Gates"] + B1["Fast PR gate
secret, SAST, SCA/dependency, config risk"] + B2["Integration gate
scan lai khi nhieu feature ghep chung"] + B3["Release gate
kiem tra release candidate truoc main"] + end + + subgraph L3["Artifact Supply Chain"] + C1["Build image
vote/result/worker"] + C2["SBOM
danh sach thanh phan"] + C3["Signature
ky image digest"] + C4["Image scan
CVE tren artifact that"] + end + + subgraph L4["Staging Validation"] + D1["GitOps staging desired state"] + D2["Deploy staging"] + D3["Smoke test"] + D4["DAST"] + end + + subgraph L5["Production GitOps"] + E1["Promotion PR"] + E2["Review production desired state"] + E3["AWS production sync"] + E4["Azure warm standby sync"] + end + + subgraph L6["Operate / Recover"] + F1["Admission policy"] + F2["Secret management"] + F3["Metrics/logs/runtime detection"] + F4["DR failover path"] + end + + A1 --> A2 --> B1 + B1 --> A3 + A3 --> B2 --> A4 --> B3 --> A5 + A5 --> C1 --> C2 --> C3 --> C4 + C4 --> D1 --> D2 --> D3 --> D4 + D4 --> E1 --> E2 + E2 --> E3 + E2 --> E4 + E3 --> F1 --> F2 --> F3 --> F4 + E4 --> F1 + + classDef lane fill:#f8fafc,stroke:#64748b,stroke-width:1px,color:#0f172a; + classDef security fill:#fee2e2,stroke:#b91c1c,color:#7f1d1d; + classDef artifact fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a; + classDef deploy fill:#dcfce7,stroke:#15803d,color:#14532d; + classDef git fill:#ede9fe,stroke:#6d28d9,color:#3b0764; + + class A1,A2,A3,A4,A5 git; + class B1,B2,B3 security; + class C1,C2,C3,C4 artifact; + class D1,D2,D3,D4,E1,E2,E3,E4,F1,F2,F3,F4 deploy; +``` + +## 3. Loi Thuyet Minh Ngan + +```text +Pipeline nay khong phai chi la build va deploy. No la chuoi kiem soat rui ro. Developer tao PR thi he thong quet loi som nhu secret, SAST, SCA/dependency va cau hinh nguy hiem. SCA o tang source giup bat CVE trong dependency manifest/lockfile som de developer sua ngay. Khi code vao dev, pipeline kiem tra lai vi nhieu feature ghep chung co the sinh loi moi. Truoc khi vao main co release gate de dam bao release candidate sach. Main moi build artifact that, tao SBOM, ky image va scan CVE tren image da build. Artifact da pass moi len staging. Staging phai smoke test va DAST pass thi moi mo promotion PR. Production khong deploy truc tiep tu CI, ma ArgoCD dong bo tu desired state trong Git. Sau deploy van co runtime policy, secret management, monitoring va DR. +``` + +## 4. Diem Can Nhan Manh Khi Giai Thich + +- `Pull request` la diem bat loi som va review thay doi. +- Neu PR fail gate, developer sua tren feature branch va push commit moi; PR hien tai tu cap nhat va gate chay lai. +- `SCA/dependency scan` nam o PR gate de bat CVE trong third-party libraries som; `image scan` nam o artifact gate de quet image that sau build. +- `dev` la noi gom feature de kiem tra tong hop, khong phai production. +- `main` la ranh gioi release, khong phai noi push code tuy tien. +- `Build artifact` tao image bat bien, co the truy vet bang digest. +- `SBOM + signing + image scan` bao ve chuoi cung ung phan mem. +- `Staging + smoke + DAST` kiem tra app dang chay that. +- `Promotion PR` la ranh gioi production. +- `GitOps` giup production co audit, rollback va desired state ro rang. +- `Runtime controls` bao ve sau khi deploy, vi pipeline khong phai lop bao ve duy nhat. diff --git a/docs/final-readiness.md b/docs/final-readiness.md index 7252820..4338434 100644 --- a/docs/final-readiness.md +++ b/docs/final-readiness.md @@ -43,9 +43,9 @@ This file summarizes the final project state for the capstone handoff. - ACR public access is kept for GitHub-hosted runners and AKS pulls; production should use private endpoints. - ACR Premium-only controls such as geo-replication, zone redundancy, retention policy, dedicated data endpoints, and Defender-integrated scanning are documented as production hardening items. - Checkov still runs in CI, but enterprise/cost-heavy controls are listed as accepted lab exceptions in `.github/workflows/ci-pipeline.yml`. The project continues to block high-signal failures through Gitleaks, Semgrep, tfsec, Trivy, Helm validation, Conftest, Gatekeeper, Kyverno, and Cosign verification. -- Cross-cloud database replication is enabled with native PostgreSQL logical replication from AWS RDS to Azure PostgreSQL Flexible Server. It creates extra paid database resources, so destroy the stack after recording. +- Cross-cloud database replication is implemented as an optional DR drill with native PostgreSQL logical replication from AWS RDS to Azure PostgreSQL Flexible Server. In the cost-capped live demo, Azure PostgreSQL may be disabled and represented by a restore-required runtime placeholder. - Canary/automated rollback is not enabled; current deployment uses rolling updates, readiness/liveness probes, and GitOps rollback by reverting Git. Production should add Argo Rollouts with Prometheus analysis. -- AWS EKS should be upgraded from `1.30` to `1.31` before the demo handoff window if time allows, then advanced one minor version at a time. See `docs/eks-upgrade-runbook.md`. +- AWS EKS has been brought to `1.31` in the current live environment. Future upgrades should continue one minor version at a time. See `docs/eks-upgrade-runbook.md`. ## Demo Commands diff --git a/docs/implementation-map.md b/docs/implementation-map.md index 6630341..7c3c4ec 100644 --- a/docs/implementation-map.md +++ b/docs/implementation-map.md @@ -78,6 +78,6 @@ This map links the project scope to the implementation files. ## Known Limits -- Cross-cloud live database replication is implemented with native PostgreSQL logical replication. The cost-capped fallback remains restore or seed data. +- Cross-cloud database replication is implemented as an optional native PostgreSQL logical replication drill. The cost-capped live demo can use a restore-required placeholder or seed data fallback. - Auto-quarantine is optional demo mode; default response is alert and human triage. - Full enterprise SSO is not implemented yet; ArgoCD RBAC groups are prepared as a baseline. diff --git a/docs/pipeline-frameworks.md b/docs/pipeline-frameworks.md new file mode 100644 index 0000000..32cd082 --- /dev/null +++ b/docs/pipeline-frameworks.md @@ -0,0 +1,176 @@ +# Full Pipeline Voi Framework Va Tool Cu The + +File nay trinh bay implementation cu the cua kien truc DevSecOps. Neu `docs/architecture-conceptual.md` noi ve ban chat, file nay noi ro framework, tool va moi truong dang dung. + +## 1. Source Control Va Branch Model + +| Thanh phan | Framework / tool | Vai tro | +| --- | --- | --- | +| Repository | GitHub | Luu source code, IaC, Helm chart, workflow, scripts va docs | +| Branch feature | Git branch | Noi developer lam tung thay doi rieng | +| Pull request | GitHub Pull Request | Review code va kich hoat security gate | +| Integration branch | `dev` | Gom feature da pass gate de kiem tra tong hop | +| Release branch | `main` | Nguon release va desired state production | +| Branch protection | GitHub branch protection | Bat required checks va approving review | + +Hien tai: + +- `dev` yeu cau check `Feature PR light security gates` va 1 review. +- `main` yeu cau check `Release PR full security gates` va 1 review. + +## 2. Feature PR Gate + +Khi developer tao PR vao `dev`, GitHub Actions chay fast gate. + +| Muc kiem tra | Tool / framework | Muc dich | +| --- | --- | --- | +| Secret scanning | Gitleaks | Chan token, password, private key bi hardcode | +| Static application security | Semgrep | Bat bug va mau code co lo hong | +| SCA / dependency scan | Trivy FS, npm audit | Quet CVE trong dependency manifest/lockfile va third-party libraries | +| Code quality | SonarCloud | Phat hien bug, smell, duplication | +| Local hygiene | pre-commit | Chuan hoa format, newline, whitespace, secret check | + +Ket qua dung: PR feature chi duoc merge vao `dev` khi gate nhanh pass va co review. + +## 3. Integration Gate Tren `dev` + +Sau khi merge vao `dev`, pipeline chay bo kiem tra rong hon. + +| Muc kiem tra | Tool / framework | Muc dich | +| --- | --- | --- | +| Secret scanning | Gitleaks | Dam bao `dev` khong chua secret | +| SAST | Semgrep | Quet loi code theo rule bao mat | +| IaC security | Checkov, tfsec | Kiem tra Terraform AWS/Azure | +| SCA / filesystem scan | Trivy FS | Kiem tra dependency manifest, lockfile, filesystem va config | +| Kubernetes manifest | Helm lint, Helm template | Dam bao chart render hop le | +| Policy as code | Conftest/OPA | Chan manifest vi pham policy | + +Ket qua dung: `dev` tro thanh release candidate sach hon, co the tao PR sang `main`. + +## 4. Release PR Gate Vao `main` + +Khi tao PR `dev -> main`, GitHub Actions chay `Release PR full security gates`. + +| Muc kiem tra | Tool / framework | Muc dich | +| --- | --- | --- | +| Secret | Gitleaks | Khong cho secret vao release branch | +| SAST | Semgrep | Chan loi bao mat trong code | +| IaC | Checkov, tfsec | Chan cau hinh cloud nguy hiem | +| K8s/Helm | Helm lint/template | Dam bao manifest render duoc cho staging/prod/Azure | +| Policy | Conftest | Dam bao manifest hop policy | + +Ket qua dung: PR vao `main` chi merge khi full gate pass va co review. + +Ghi chu: Trivy FS va `npm audit` la source-level SCA. Chung bat CVE trong dependency manifest/lockfile som o PR/integration/release gate. Trivy image scan o buoc artifact la lop khac, dung de quet image that sau khi build, bao gom base image va package da cai trong container. + +## 5. Build, SBOM, Signing Va Scan Image + +Khi code vao `main`, GitHub Actions build ba service: + +- `vote`: Python/Flask. +- `result`: Node.js/Express. +- `worker`: .NET/C#. + +Pipeline build container image bang Docker va day len: + +- AWS ECR cho AWS EKS. +- Azure ACR cho Azure AKS. + +| Buoc | Tool / framework | Ket qua | +| --- | --- | --- | +| Build image | Docker | Tao image cho `vote`, `result`, `worker` | +| Generate SBOM | Syft | Tao SBOM SPDX cho image | +| Sign image | Cosign keyless | Ky image digest bang GitHub OIDC/Fulcio/Rekor | +| Verify signature | Cosign + policy script | Xac minh identity, issuer, Rekor bundle/certificate | +| Image CVE scan | Trivy image | Chan image co CVE nghiem trong | + +Ket qua dung: chi image da co SBOM, da ky, da verify va scan pass moi duoc dung cho staging. + +## 6. Staging Deployment Va DAST + +| Thanh phan | Framework / tool | Gia tri hien tai | +| --- | --- | --- | +| GitOps branch | Git branch `staging` | Luu desired state staging | +| Deployment engine | ArgoCD | Sync tu Git vao EKS | +| Cluster | AWS EKS | Primary Kubernetes cluster | +| Namespace | `voting-staging` | Moi truong staging | +| Helm values | `k8s/values-staging.yaml` | Cau hinh staging | +| Smoke test | HTTP `/healthz` | Xac nhan app song | +| DAST | OWASP ZAP baseline | Quet web app khi dang chay | + +Ket qua dung: + +- ArgoCD app `voting-staging` `Synced Healthy`. +- `/healthz` staging HTTP 200. +- OWASP ZAP baseline pass. + +## 7. Production Promotion + +Neu staging va DAST pass, pipeline tao promotion PR cap nhat: + +- `k8s/values-prod.yaml` +- `k8s/values-azure.yaml` + +Promotion PR thay doi image digest cua production/Azure sang digest da duoc build, sign, verify va test o staging. + +| Thanh phan | Framework / tool | Vai tro | +| --- | --- | --- | +| Promotion PR | GitHub Pull Request | Review thay doi desired state production | +| GitOps desired state | Helm values | Ghi image digest production/Azure | +| Required gate | Release PR full security gates | Kiem tra promotion PR truoc merge | + +## 8. Production Va Azure Deployment + +| Moi truong | Cloud | Cluster | ArgoCD app | Namespace | Helm values | +| --- | --- | --- | --- | --- | --- | +| AWS staging | AWS | EKS | `voting-staging` | `voting-staging` | `k8s/values-staging.yaml` | +| AWS production | AWS | EKS | `voting-production` | `voting-production` | `k8s/values-prod.yaml` | +| Azure warm standby | Azure | AKS | `voting-azure` | `voting` | `k8s/values-azure.yaml` | + +Ket qua dung: + +- `voting-production` `Synced Healthy`. +- `voting-azure` `Synced Healthy`. +- `/healthz` production va Azure HTTP 200. + +## 9. Runtime Security + +| Lop bao ve | Framework / tool | Muc dich | +| --- | --- | --- | +| Image admission | Sigstore policy-controller | Chi chap nhan image co chu ky hop le | +| Policy as code | Gatekeeper/OPA | Chan workload/cau hinh vi pham policy | +| Secret sync | External Secrets Operator | Lay secret tu secret manager, khong hardcode trong manifest | +| AWS secrets | AWS Secrets Manager | Luu secret phia AWS | +| Azure secrets | Azure Key Vault | Luu secret phia Azure | +| Monitoring | Prometheus, Grafana | Metric va dashboard | +| Logging | Loki, Promtail | Tap trung log | +| Runtime detection | Falco | Phat hien hanh vi bat thuong trong cluster | + +## 10. Infrastructure Va Multi-Cloud + +| Thanh phan | Framework / tool | Vai tro | +| --- | --- | --- | +| IaC | Terraform | Tao va quan ly AWS/Azure infrastructure | +| AWS compute | EKS | Kubernetes primary | +| Azure compute | AKS | Kubernetes warm standby | +| AWS database | RDS PostgreSQL | Primary database | +| Azure database | Azure PostgreSQL | Logical subscriber | +| AWS cache | ElastiCache Redis | Cache/queue primary | +| Azure standby cache | In-cluster Redis | Standby cost-aware | +| Network DR | AWS VPN Gateway, Azure VNet Gateway, BGP | Ket noi hai cloud | +| Failover | Route53 failover script | Chuyen traffic khi primary loi | + +## 11. Evidence Gan Nhat + +| Evidence | Trang thai | +| --- | --- | +| Main release run `26565822002` | Success | +| Promotion GitOps run `26566117530` | Success | +| PR tai lieu `#73` | Merged | +| Promotion PR `#74` | Merged | +| AWS `voting-staging` | Synced Healthy | +| AWS `voting-production` | Synced Healthy | +| Azure `voting-azure` | Synced Healthy | +| Staging `/healthz` | HTTP 200 | +| Production `/healthz` | HTTP 200 | +| Azure `/healthz` | HTTP 200 | diff --git a/docs/teacher-aligned-architecture.md b/docs/teacher-aligned-architecture.md index 68761d8..aa022f4 100644 --- a/docs/teacher-aligned-architecture.md +++ b/docs/teacher-aligned-architecture.md @@ -195,7 +195,7 @@ ArgoCD la deployment controller, nen audit deploy gom Git commit, PR, ArgoCD rev ```mermaid flowchart LR AWSApp["AWS production app"] --> RDS["AWS RDS PostgreSQL"] - RDS -->|"logical replication"| AzurePG["Azure PostgreSQL"] + RDS -->|"optional logical replication / restore drill"| AzurePG["Azure PostgreSQL"] AWSNet["AWS VPC"] <-->|"IPsec VPN + BGP"| AzureNet["Azure VNet"] MainGit["main GitOps state"] --> AWSArgo["AWS ArgoCD"] MainGit --> AzureArgo["Azure ArgoCD"] @@ -207,7 +207,7 @@ DR story: - AWS la active primary. - Azure AKS sync cung desired state production nhu standby. -- Data path dung PostgreSQL logical replication tu AWS RDS sang Azure PostgreSQL. +- Data path co san runbook PostgreSQL logical replication tu AWS RDS sang Azure PostgreSQL. Trong live demo cost-capped, Azure DB co the de placeholder `restore-required` va trinh bay nhu buoc DR restore/replication drill. - Route53 failover script da co, nhung can hosted zone/domain that de kich hoat public DNS failover. - Azure student subscription co cost/quota constraint: result service de `ClusterIP`, Redis dung in-cluster Redis, ACR dung Basic SKU. diff --git a/k8s/templates/externalsecret.yaml b/k8s/templates/externalsecret.yaml index b5b65d5..c75bbca 100644 --- a/k8s/templates/externalsecret.yaml +++ b/k8s/templates/externalsecret.yaml @@ -29,6 +29,7 @@ stringData: DB_USER: postgres DB_PASSWORD: postgres DB_NAME: postgres + DB_SSL: "false" DB_SSL_MODE: Disable DATABASE_URL: postgres://postgres:postgres@db:5432/postgres COOKIE_SECURE: "false" diff --git a/result/server.js b/result/server.js index 7882b3d..d25ba0a 100644 --- a/result/server.js +++ b/result/server.js @@ -10,6 +10,26 @@ var express = require('express'), io = require('socket.io')(server); var port = process.env.PORT || 4000; +var dbConnected = false; + +function dbSslConfig() { + var explicitSsl = (process.env.DB_SSL || '').toLowerCase(); + var sslMode = (process.env.DB_SSL_MODE || '').toLowerCase(); + var databaseUrl = process.env.DATABASE_URL || ''; + var urlRequiresSsl = /[?&]sslmode=(require|verify-ca|verify-full)/i.test(databaseUrl); + + if (explicitSsl === 'false' || sslMode === 'disable') { + return false; + } + + if (explicitSsl === 'true' || sslMode === 'require' || sslMode === 'verify-ca' || sslMode === 'verify-full' || urlRequiresSsl) { + return { + rejectUnauthorized: process.env.DB_SSL_REJECT_UNAUTHORIZED === 'true' || sslMode === 'verify-full' + }; + } + + return false; +} client.collectDefaultMetrics({ prefix: 'result_' }); const httpRequestDuration = new client.Histogram({ @@ -35,7 +55,7 @@ io.on('connection', function (socket) { var pool = new Pool({ connectionString: process.env.DATABASE_URL || `postgres://${process.env.DB_USER || 'postgres'}:${process.env.DB_PASSWORD || 'postgres'}@${process.env.DB_HOST || 'db'}:${process.env.DB_PORT || '5432'}/${process.env.DB_NAME || 'postgres'}`, - ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: process.env.DB_SSL_REJECT_UNAUTHORIZED !== 'false' } : false + ssl: dbSslConfig() }); async.retry( @@ -43,7 +63,8 @@ async.retry( function(callback) { pool.connect(function(err, client, done) { if (err) { - console.error("Waiting for db"); + dbConnected = false; + console.error("Waiting for db: " + err.message); } callback(err, client); }); @@ -53,6 +74,7 @@ async.retry( return console.error("Giving up"); } console.log("Connected to db"); + dbConnected = true; getVotes(client); } ); @@ -60,8 +82,10 @@ async.retry( function getVotes(client) { client.query('SELECT vote, COUNT(id) AS count FROM votes GROUP BY vote', [], function(err, result) { if (err) { + dbConnected = false; console.error("Error performing query: " + err); } else { + dbConnected = true; var votes = collectVotesFromResult(result); io.sockets.emit("scores", JSON.stringify(votes)); } @@ -126,6 +150,10 @@ app.use(function (err, _req, res, next) { }); app.get('/healthz', function (req, res) { + if (!dbConnected) { + return res.status(503).json({ status: 'error', service: 'result', dependency: 'db' }); + } + res.status(200).json({ status: 'ok', service: 'result' }); }); diff --git a/scripts/dr-failover.ps1 b/scripts/dr-failover.ps1 index ef0c114..9b191fa 100644 --- a/scripts/dr-failover.ps1 +++ b/scripts/dr-failover.ps1 @@ -1,7 +1,7 @@ param( [string]$AzureEnv = "terraform/environments/azure", [int]$UserNodeCount = 1, - [string]$Namespace = "voting-production", + [string]$Namespace = "voting", [switch]$SkipScale, [switch]$OpenPortForward ) @@ -67,7 +67,7 @@ kubectl -n argocd rollout status deploy/argocd-server --timeout=5m | Out-Host kubectl -n argocd rollout status statefulset/argocd-application-controller --timeout=5m | Out-Host Write-Step "Refreshing Azure standby application" -kubectl -n argocd annotate application voting-azure-production argocd.argoproj.io/refresh=hard --overwrite | Out-Host +kubectl -n argocd annotate application voting-azure argocd.argoproj.io/refresh=hard --overwrite | Out-Host Write-Step "Waiting for voting workloads" kubectl -n $Namespace rollout status deploy/vote --timeout=10m | Out-Host @@ -84,7 +84,7 @@ Write-Host "RTO: $Rto minutes" Write-Step "Useful verification commands" Write-Host "kubectl -n $Namespace get pods,svc" -Write-Host "kubectl -n argocd get application voting-azure-production" +Write-Host "kubectl -n argocd get application voting-azure" if ($OpenPortForward) { Write-Step "Opening local port-forward to Azure vote service" diff --git a/scripts/dr-update-azure-runtime-secret.ps1 b/scripts/dr-update-azure-runtime-secret.ps1 index 1809e55..658a88e 100644 --- a/scripts/dr-update-azure-runtime-secret.ps1 +++ b/scripts/dr-update-azure-runtime-secret.ps1 @@ -44,9 +44,12 @@ $RuntimeConfig = [ordered]@{ DB_USER = $DbUser DB_PASSWORD = $DbPassword DB_NAME = $DbName + DB_SSL = "true" DB_SSL_MODE = "Require" + DB_SSL_REJECT_UNAUTHORIZED = "false" DATABASE_URL = "postgres://${DbUser}:${DbPassword}@${DbHost}:5432/${DbName}?sslmode=require" - COOKIE_SECURE = "true" + COOKIE_SECURE = "false" + COOKIE_SAMESITE = "Lax" } $SecretValue = $RuntimeConfig | ConvertTo-Json -Compress diff --git a/scripts/test-policy-rejects.ps1 b/scripts/test-policy-rejects.ps1 index b78659a..65f6959 100644 --- a/scripts/test-policy-rejects.ps1 +++ b/scripts/test-policy-rejects.ps1 @@ -26,16 +26,32 @@ $files = @( foreach ($file in $files) { $path = Join-Path $PolicyDir $file + $tempPath = Join-Path ([System.IO.Path]::GetTempPath()) "voting-$file" + (Get-Content -LiteralPath $path -Raw).Replace("namespace: voting", "namespace: $Namespace") | + Set-Content -LiteralPath $tempPath -NoNewline + Write-Host "" Write-Host "Applying $file. This should be denied." -ForegroundColor Yellow - $kubectlArgs = @("apply", "-f", $path, "-n", $Namespace, "--dry-run=server") + $kubectlArgs = @("apply", "-f", $tempPath, "--dry-run=server") if ($Context) { $kubectlArgs += @("--context", $Context) } - & kubectl @kubectlArgs - if ($LASTEXITCODE -eq 0) { + $previousErrorActionPreference = $ErrorActionPreference + $ErrorActionPreference = "Continue" + $output = (& kubectl @kubectlArgs 2>&1) -join "`n" + $kubectlExitCode = $LASTEXITCODE + $ErrorActionPreference = $previousErrorActionPreference + if ($kubectlExitCode -eq 0) { + Remove-Item -LiteralPath $tempPath -Force -ErrorAction SilentlyContinue throw "$file was accepted, but it should have been denied by admission policy." } + + Remove-Item -LiteralPath $tempPath -Force -ErrorAction SilentlyContinue + if ($output -notmatch "denied|admission webhook|violat|Image signature verification failed") { + throw "$file failed before admission policy could evaluate it:`n$output" + } + + Write-Host $output Write-Host "$file denied as expected." -ForegroundColor Green } diff --git a/terraform/environments/aws/main.tf b/terraform/environments/aws/main.tf index b1b2a15..f9820ff 100644 --- a/terraform/environments/aws/main.tf +++ b/terraform/environments/aws/main.tf @@ -152,17 +152,21 @@ module "app_runtime_secret" { name = "${var.name_prefix}/app-runtime" generate_password = false secret_data = { - REDIS_HOST = module.elasticache.primary_endpoint_address - REDIS_PORT = tostring(module.elasticache.port) - REDIS_PASSWORD = module.redis_secret.password - REDIS_SSL = "true" - DB_HOST = module.rds.address - DB_PORT = tostring(module.rds.port) - DB_USER = "postgres" - DB_PASSWORD = module.db_secret.password - DB_NAME = module.rds.db_name - DB_SSL_MODE = "Require" - DATABASE_URL = "postgres://postgres:${urlencode(module.db_secret.password)}@${module.rds.address}:${module.rds.port}/${module.rds.db_name}?sslmode=require" + REDIS_HOST = module.elasticache.primary_endpoint_address + REDIS_PORT = tostring(module.elasticache.port) + REDIS_PASSWORD = module.redis_secret.password + REDIS_SSL = "true" + DB_HOST = module.rds.address + DB_PORT = tostring(module.rds.port) + DB_USER = "postgres" + DB_PASSWORD = module.db_secret.password + DB_NAME = module.rds.db_name + DB_SSL = "true" + DB_SSL_MODE = "Require" + DB_SSL_REJECT_UNAUTHORIZED = "false" + DATABASE_URL = "postgres://postgres:${urlencode(module.db_secret.password)}@${module.rds.address}:${module.rds.port}/${module.rds.db_name}?sslmode=require" + COOKIE_SECURE = "false" + COOKIE_SAMESITE = "Lax" } tags = local.common_tags } diff --git a/terraform/environments/azure/secrets.tf b/terraform/environments/azure/secrets.tf index 9b7e7c8..d199bfa 100644 --- a/terraform/environments/azure/secrets.tf +++ b/terraform/environments/azure/secrets.tf @@ -35,17 +35,21 @@ resource "azurerm_key_vault_secret" "app_runtime" { content_type = "application/json" expiration_date = "2099-12-31T23:59:59Z" value = jsonencode({ - REDIS_HOST = var.azure_redis_host - REDIS_PORT = "6379" - REDIS_PASSWORD = var.azure_redis_password - REDIS_SSL = tostring(var.azure_redis_ssl) - DB_HOST = local.azure_db_host_effective - DB_PORT = "5432" - DB_USER = local.azure_db_user_effective - DB_PASSWORD = local.azure_db_password_effective - DB_NAME = local.azure_db_database_effective - DB_SSL_MODE = local.azure_db_ssl_mode_effective - DATABASE_URL = "postgres://${local.azure_db_user_effective}:${urlencode(local.azure_db_password_effective)}@${local.azure_db_host_effective}:5432/${local.azure_db_database_effective}?sslmode=require" + REDIS_HOST = var.azure_redis_host + REDIS_PORT = "6379" + REDIS_PASSWORD = var.azure_redis_password + REDIS_SSL = tostring(var.azure_redis_ssl) + DB_HOST = local.azure_db_host_effective + DB_PORT = "5432" + DB_USER = local.azure_db_user_effective + DB_PASSWORD = local.azure_db_password_effective + DB_NAME = local.azure_db_database_effective + DB_SSL = "true" + DB_SSL_MODE = local.azure_db_ssl_mode_effective + DB_SSL_REJECT_UNAUTHORIZED = "false" + DATABASE_URL = "postgres://${local.azure_db_user_effective}:${urlencode(local.azure_db_password_effective)}@${local.azure_db_host_effective}:5432/${local.azure_db_database_effective}?sslmode=require" + COOKIE_SECURE = "false" + COOKIE_SAMESITE = "Lax" }) depends_on = [azurerm_role_assignment.current_key_vault_admin]