11 KiB
DevOps Audit Report — GoodGo POS Platform
Auditor: DevOps Engineer (TechBi Company) Date: 2026-03-20 Scope: Docker configs, CI/CD pipelines, Kubernetes manifests, health checks, observability Branch: master
Executive Summary
Infrastructure cơ bản đã được triển khai tốt: multi-stage Docker builds, non-root container users, health probes trên tất cả K8s deployments, và CI/CD pipeline có environment approval cho production. Tuy nhiên có 2 vấn đề critical cần fix ngay trước khi go-live: production K8s manifests hardcode :latest image tag, và Alertmanager chưa được cấu hình dẫn đến toàn bộ alert rules không có đích nhận.
Critical Issues
CRIT-1: Production K8s manifests hardcode :latest image tag
File: deployments/production/kubernetes/iam-service.yaml:45
image: goodgo/iam-service-net:latest # WRONG
Impact: Nếu ai chạy kubectl apply -f trực tiếp (không qua pipeline), pod sẽ pull :latest — không reproducible, không rollback được. Mâu thuẫn hoàn toàn với nguyên tắc "NEVER use :latest tag in production" trong CLAUDE.md và logic pipeline deploy-production.yml:327.
Affected files: Cần kiểm tra tất cả files trong deployments/production/kubernetes/ — khả năng cao tất cả service manifests đều bị.
Fix: Dùng placeholder IMAGE_TAG và sed-replace trong pipeline, hoặc dùng Kustomize/Helm để inject SHA tag.
CRIT-2: Alertmanager không được cấu hình — toàn bộ alert rules im lặng
File: infra/observability/prometheus/prometheus.yml:29
alerting:
alertmanagers:
- static_configs:
- targets: [] # EMPTY — no alerts will fire
Impact: Toàn bộ alert-rules.yml và rules/service-alerts.yml định nghĩa đúng (ServiceDown, HighErrorRate, HighLatencyP95...) nhưng không có receiver nào. Production incident xảy ra sẽ không có ai được notify.
Fix: Deploy Alertmanager và uncomment targets: ['alertmanager:9093']. Configure receivers (Slack/PagerDuty/email) cho ít nhất kênh critical.
CRIT-3: docker-build.yml push :latest tag lên Docker Hub từ branch main
File: .github/workflows/docker-build.yml:99-103
if [ "$BRANCH" = "main" ]; then
echo "tags=${IMAGE}:latest,${IMAGE}:${SHA}" >> $GITHUB_OUTPUT
Impact: :latest tag bị overwrite mỗi lần push lên main. Mâu thuẫn với deploy-production.yml (dùng SHA). Tạo race condition nếu pipeline chạy song song. Tag :latest trên Docker Hub không ổn định.
Fix: Bỏ :latest khỏi production tags. Chỉ dùng ${SHA} + production mutable tag nếu cần.
Warnings
WARN-1: redis-exporter được Prometheus scrape nhưng không tồn tại trong docker-compose
File: infra/observability/prometheus/prometheus.yml:132
- job_name: 'redis'
static_configs:
- targets: ['redis-exporter:9121'] # service không tồn tại
deployments/local/docker-compose.yml không có service redis-exporter. Prometheus sẽ báo target missing liên tục. Cần thêm oliver006/redis_exporter vào compose hoặc xóa scrape job này.
WARN-2: Nhiều microservices trong docker-compose nhưng không có trong CI/CD pipeline
Missing từ deploy-staging.yml và deploy-production.yml:
chat-service-net,social-service-net,mining-service-net,mission-service-netpromotion-service-net,booking-service-net(staging),membership-service-net- Toàn bộ 5 ads services (
ads-manager,ads-serving,ads-billing,ads-tracking,ads-analytics) mkt-facebook,mkt-whatsapp,mkt-x,mkt-zalo
15+ services không có automated deployment. Phải deploy thủ công.
WARN-3: pr-checks.yml chỉ kiểm tra Node.js — không có .NET build/test
File: .github/workflows/pr-checks.yml
PR checks chỉ chạy pnpm lint, pnpm typecheck, pnpm build. Không có step nào build hoặc test .NET services. Broken .NET code có thể merge vào branch mà không bị phát hiện.
Fix: Thêm matrix build cho .NET services, hoặc ít nhất dotnet build cho các service thay đổi trong PR.
WARN-4: Redis deploy trong K8s là single instance — SPOF
File: deployments/staging/kubernetes/redis.yaml:14
replicas: 1
Redis là SignalR backplane cho chat-service, fnb-engine, mining-service. Redis down = toàn bộ real-time features down. Cần Redis Sentinel (HA) hoặc migrate sang Redis Cluster.
WARN-5: Không có Kubernetes NetworkPolicy
Không tìm thấy NetworkPolicy manifest nào trong deployments/staging/kubernetes/ hay deployments/production/kubernetes/. Theo principle least-privilege, mặc định tất cả pods có thể communicate với nhau (và ra internet nếu không có egress restriction).
Fix: Thêm default-deny NetworkPolicy + whitelist explicit inter-service communication.
WARN-6: MinIO dùng credentials mặc định trong local dev
File: deployments/local/docker-compose.yml:78-79
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin123
Credentials mặc định well-known. Dù là local dev, nên dùng .env file để tránh habit bad practice. Thêm vào .gitignore nếu chưa có.
WARN-7: Distributed tracing (Jaeger) bị comment out
File: deployments/local/docker-compose.yml:1230-1241
Jaeger config được comment out. Không có distributed tracing cho request correlation cross-service. Với 26+ microservices, đây là gap observability nghiêm trọng khi debug production issues.
Fix: Enable Jaeger hoặc dùng Grafana Tempo (đã có Loki/Grafana stack).
WARN-8: Traefik Dashboard exposed không có authentication
File: deployments/local/docker-compose.yml:121
- "--api.insecure=true"
Traefik dashboard (http://localhost:8080) accessible không cần auth. OK cho local dev nhưng cần đảm bảo api.insecure=false ở staging/production (K8s ingress không expose dashboard port nên staging OK, nhưng cần verify production Traefik config).
WARN-9: storage-service naming inconsistency
Trong docker-compose.yml service được gọi là storage-service (line 152) nhưng build context là ../../services/storage-service-net. Trong Traefik routes và K8s manifests cũng không nhất quán. Cần chuẩn hóa.
WARN-10: Jwt__RequireHttpsMetadata=false trong staging configmap
File: deployments/staging/kubernetes/configmap.yaml:21
Jwt__RequireHttpsMetadata: "false"
Staging đã có TLS (cert-manager + letsencrypt), nhưng JWT validation không require HTTPS. Nếu token bị intercept qua HTTP (misconfigured client), không bị phát hiện.
Improvements
IMP-1: Áp dụng GitOps với ArgoCD
Hiện tại CI/CD dùng kubectl apply trực tiếp từ GitHub Actions. Recommend deploy ArgoCD và dùng GitOps: Git là source of truth, ArgoCD tự sync K8s state. Lợi ích: drift detection, automatic rollback, audit trail, không cần expose KUBECONFIG trong GitHub Secrets.
IMP-2: Thêm PodDisruptionBudget cho production services
Hiện chưa có PDB. Khi node drain/upgrade, tất cả replicas của một service có thể bị terminate cùng lúc. Với maxUnavailable: 0 trong RollingUpdate — đây là bảo vệ khi rolling update, nhưng không bảo vệ khi voluntary disruption.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: iam-service-pdb
spec:
minAvailable: 1
selector:
matchLabels:
app: iam-service
IMP-3: Pin tất cả Docker image versions trong docker-compose
Hiện tại minio/minio:latest (line 74), grafana/grafana:10.3.1 (OK), prom/prometheus:v2.51.0 (OK).
Cần pin MinIO: minio/minio:RELEASE.2024-03-15T01-07-19Z hoặc version cụ thể.
IMP-4: Thêm health check endpoint /health/ready cho web-client-tpos-net
File: deployments/local/docker-compose.yml:1375
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1"]
Blazor WASM app chỉ có /health (basic), không có readiness probe riêng. K8s sẽ gửi traffic trước khi app thực sự ready.
IMP-5: Thêm image vulnerability scanning vào CI pipeline
Không có bước nào trong .github/workflows/ scan Docker images cho CVE. Recommend thêm aquasecurity/trivy-action sau build step.
IMP-6: Migrate Grafana credentials sang K8s Secret
File: deployments/local/docker-compose.yml:1278
GF_SECURITY_ADMIN_PASSWORD=admin
Password admin là default. Cần rotate và inject qua Secret, không hardcode trong compose file.
IMP-7: Bổ sung scrape targets còn thiếu trong Prometheus
prometheus.yml chỉ scrape 8 services trong khi docker-compose có 20+. Missing: promotion-service, booking-service, membership-service, social-service, mining-service, mission-service, fnb-engine, wallet-service, ads-*.
IMP-8: Thêm Kubernetes Secrets External Operator cho production
secrets.yaml.example note "Option 3: Use sealed-secrets or external-secrets operator (recommended for production)" nhưng chưa implement. Nên dùng External Secrets Operator với HashiCorp Vault hoặc AWS Secrets Manager.
Action Items (Prioritized)
| Priority | Issue | File | Effort |
|---|---|---|---|
| P0 | Fix production K8s :latest image tags |
deployments/production/kubernetes/*.yaml |
2h |
| P0 | Configure Alertmanager + receivers | infra/observability/prometheus/prometheus.yml |
4h |
| P0 | Remove :latest push từ docker-build.yml |
.github/workflows/docker-build.yml:100 |
30m |
| P1 | Thêm redis-exporter vào docker-compose | deployments/local/docker-compose.yml |
1h |
| P1 | Thêm .NET build/test vào pr-checks.yml | .github/workflows/pr-checks.yml |
2h |
| P1 | Thêm NetworkPolicy manifests | deployments/*/kubernetes/ |
4h |
| P1 | Mở rộng CI/CD pipelines cho missing services | .github/workflows/deploy-*.yml |
8h |
| P2 | Deploy Alertmanager + PagerDuty/Slack | infra/observability/ |
4h |
| P2 | Redis HA (Sentinel) cho staging/production | deployments/*/kubernetes/redis.yaml |
4h |
| P2 | Enable distributed tracing (Jaeger/Tempo) | deployments/local/docker-compose.yml |
2h |
| P2 | Thêm PodDisruptionBudget cho production | deployments/production/kubernetes/ |
2h |
| P2 | Image vulnerability scanning trong CI | .github/workflows/docker-build.yml |
1h |
| P3 | Pin MinIO image version | deployments/local/docker-compose.yml:74 |
15m |
| P3 | Rotate Grafana default password | deployments/local/docker-compose.yml:1278 |
30m |
| P3 | ArgoCD GitOps adoption | New infra | 2-3 days |
| P3 | External Secrets Operator | deployments/production/kubernetes/ |
1 day |
Report generated by DevOps Engineer agent (TEC-223) — 2026-03-20