Lab 9 — 🔐 GitOps Secrets
🎯 Mục tiêu
Sau lab này, bạn sẽ:
- Hiểu tại sao Kubernetes Secret không nên được commit trực tiếp vào Git.
- Hiểu sự khác nhau giữa
Secret,SealedSecretvà secret thật trong Kubernetes. - Biết cách dùng Sealed Secrets để đưa secret vào GitOps một cách an toàn hơn.
- Deploy secret thông qua ArgoCD.
- Biết cách xử lý secret trong môi trường
dev / staging / production.
🤔 1. Vấn đề thực tế
Giả sử Todo App của chúng ta cần PostgreSQL:
POSTGRES_USER=todo
POSTGRES_PASSWORD=todo123
POSTGRES_DB=todo
Nếu deploy thủ công, bạn có thể làm:
kubectl create secret generic todo-db-secret \
-n todo-app \
--from-literal=username=todo \
--from-literal=password=todo123
Cách này chạy được.
Nhưng GitOps có một vấn đề:
ArgoCD cần biết toàn bộ desired state từ Git.
Bạn có thể nghĩ đến việc tạo file:
apiVersion: v1
kind: Secret
metadata:
name: todo-db-secret
stringData:
username: todo
password: todo123
Sau đó:
git add .
git commit -m "add database secret"
git push
💥 Đây là một lỗi rất nguy hiểm.
Git repository bây giờ chứa password.
Ngay cả khi bạn xóa file ở commit sau:
Commit 1
↓
password123
Commit 2
↓
xóa password
password vẫn có thể tồn tại trong Git history.
🧠 2. Hiểu nhanh
2.1. Kubernetes Secret có thực sự "secret"?
Đây là một hiểu lầm rất phổ biến.
Kubernetes Secret dùng để lưu password, token, key... nhưng giá trị trong data thường chỉ được Base64 encode, không phải encryption. Kubernetes cũng lưu Secret trong etcd theo dạng không mã hóa mặc định nếu cluster chưa cấu hình encryption at rest. (Kubernetes)
Ví dụ:
data:
password: dG9kbzEyMw==
Decode:
echo "dG9kbzEyMw==" | base64 -d
Kết quả:
todo123
Vì vậy:
❌ Base64 ≠ Encryption ❌ Base64 ≠ Security
🔐 3. Sealed Secrets giải quyết vấn đề gì?
Ý tưởng của Sealed Secrets rất đơn giản:
Secret thật
│
│ encrypt
▼
SealedSecret
│
│ Git
▼
GitHub
│
│ ArgoCD
▼
Kubernetes
│
│ decrypt
▼
Secret
Thay vì commit:
kind: Secret
chúng ta commit:
kind: SealedSecret
SealedSecret chứa dữ liệu đã được mã hóa.
ArgoCD có thể sync file này từ Git.
Sau đó controller của Sealed Secrets trong Kubernetes sẽ giải mã và tạo ra Kubernetes Secret.
🏗️ 4. Architecture
Luồng hoàn chỉnh của Lab:
GitOps Repository
┌─────────────────┐
│ │
│ SealedSecret │
│ encrypted data │
│ │
└────────┬────────┘
│
│ Git
▼
┌───────────┐
│ ArgoCD │
└─────┬─────┘
│
│ Sync
▼
┌───────────────────────┐
│ Kubernetes Cluster │
│ │
│ Sealed Secrets │
│ Controller │
│ │ │
│ │ decrypt │
│ ▼ │
│ Kubernetes Secret │
│ │ │
│ ▼ │
│ Todo Backend │
└───────────────────────┘
Điểm quan trọng:
Git
│
│ Không chứa password plaintext
▼
SealedSecret
│
│ ArgoCD
▼
Kubernetes
│
▼
Secret thật
🧪 5. Chuẩn bị Lab
Giả sử chúng ta đang sử dụng:
Namespace:
todo-app
Application:
todo-app
GitOps repository:
todo-gitops/
Kiểm tra cluster:
kubectl get nodes
Kiểm tra ArgoCD:
kubectl get pods -n argocd
Kiểm tra namespace:
kubectl get namespace todo-app
Nếu chưa có:
kubectl create namespace todo-app
🔧 6. Cài đặt Sealed Secrets Controller
6.1. Tại sao cần Controller?
SealedSecret không phải Kubernetes Secret thông thường.
Kubernetes API mặc định không biết cách xử lý:
kind: SealedSecret
Do đó chúng ta cần một controller.
Controller sẽ:
SealedSecret
│
▼
Sealed Secrets Controller
│
│ decrypt
▼
Secret
6.2. Cài bằng Helm
Thêm repository:
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
Update:
helm repo update
Cài controller:
helm install sealed-secrets \
sealed-secrets/sealed-secrets \
-n kube-system
Kiểm tra:
kubectl get pods -n kube-system | grep sealed
Bạn cần thấy controller đang Running.
Ví dụ:
sealed-secrets-xxxxx 1/1 Running
🔑 7. Cài kubeseal
kubeseal là CLI dùng để mã hóa Kubernetes Secret thành SealedSecret.
Kiểm tra:
kubeseal --version
Nếu chưa có, cài theo cách phù hợp với OS của bạn.
Trên macOS với Homebrew:
brew install kubeseal
Kiểm tra:
kubeseal --version
🧪 8. Tạo Kubernetes Secret
Bây giờ chúng ta tạo một Secret nhưng chưa commit nó vào Git.
Tạo:
kubectl create secret generic todo-db-secret \
-n todo-app \
--from-literal=username=todo \
--from-literal=password='todo123' \
--dry-run=client \
-o yaml > secret.yaml
Kiểm tra:
cat secret.yaml
Bạn sẽ thấy:
apiVersion: v1
kind: Secret
metadata:
name: todo-db-secret
namespace: todo-app
type: Opaque
data:
password: ...
username: ...
Đây chính là Secret thật.
⚠️ 9. Không commit secret.yaml
Đây là bước rất quan trọng.
File:
secret.yaml
chứa credential của chúng ta.
Không được:
git add secret.yaml
Thay vào đó:
echo "secret.yaml" >> .gitignore
Kiểm tra:
git status
Mục tiêu:
secret.yaml
không xuất hiện trong danh sách file chuẩn bị commit.
💡 Production tip: Nếu credential thật đã từng được commit vào Git, đừng chỉ xóa file. Hãy rotate credential — tức tạo credential mới và vô hiệu hóa credential cũ.
🔐 10. Encrypt Secret thành SealedSecret
Bây giờ chúng ta dùng:
kubeseal
để mã hóa Secret.
kubeseal \
--format yaml \
< secret.yaml \
> sealed-secret.yaml
Kiểm tra:
cat sealed-secret.yaml
Bạn sẽ thấy:
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: todo-db-secret
namespace: todo-app
spec:
encryptedData:
password: Ag...
username: Ag...
Điểm quan trọng:
password: todo123
đã biến thành:
password: Ag...
🧠 11. Điều gì vừa xảy ra?
Hãy nhìn vào flow:
secret.yaml
│
│ chứa
│ password = todo123
▼
kubeseal
│
│ encrypt
▼
sealed-secret.yaml
│
│ password = Ag...
▼
Git
Bây giờ file:
sealed-secret.yaml
có thể được commit vào Git.
Nhưng:
secret.yaml
thì không.
📦 12. Đưa SealedSecret vào GitOps Repository
Giả sử cấu trúc repository của bạn:
todo-gitops/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
│
└── overlays/
└── dev/
├── kustomization.yaml
└── sealed-secret.yaml
Copy file:
cp sealed-secret.yaml \
todo-gitops/overlays/dev/
Sau đó:
cd todo-gitops
Commit:
git add overlays/dev/sealed-secret.yaml
git commit -m "add sealed secret for todo database"
git push
👀 13. See Result — Kiểm tra Git
Mở GitHub repository.
Bạn có thể nhìn thấy:
kind: SealedSecret
spec:
encryptedData:
password: Ag...
username: Ag...
Nhưng bạn không thấy:
todo123
Đây chính là mục tiêu.
GitHub
│
│ encrypted
▼
SealedSecret
🚀 14. Deploy bằng ArgoCD
Bây giờ ArgoCD sẽ đọc:
Git
│
▼
SealedSecret
và apply nó vào Kubernetes.
Nếu Application đã cấu hình Auto Sync:
Git push
│
▼
ArgoCD detects change
│
▼
Sync
│
▼
SealedSecret created
Nếu chưa bật Auto Sync, có thể sync thủ công:
argocd app sync todo-app
Hoặc vào:
ArgoCD UI
↓
todo-app
↓
SYNC
🔎 15. Kiểm tra SealedSecret
Chạy:
kubectl get sealedsecret -n todo-app
Kết quả:
NAME STATUS
todo-db-secret True
Tiếp tục kiểm tra Secret:
kubectl get secret -n todo-app
Bạn sẽ thấy:
todo-db-secret
Điều này có nghĩa:
Git
│
▼
SealedSecret
│
▼
Sealed Secrets Controller
│
▼
Secret
🎉 GitOps Secrets đã hoạt động.
🧪 16. Kiểm tra Secret được tạo
Xem Secret:
kubectl describe secret todo-db-secret -n todo-app
Bạn sẽ thấy:
Name: todo-db-secret
Namespace: todo-app
Type: Opaque
Data
====
password: 7 bytes
username: 4 bytes
Kubernetes không hiển thị plaintext khi dùng describe.
Nếu thực sự cần kiểm tra:
kubectl get secret todo-db-secret \
-n todo-app \
-o jsonpath='{.data.password}' | base64 -d
Kết quả:
todo123
⚠️ Chỉ decode khi debug. Đừng đưa command kiểu này vào script/log production nếu không cần thiết.
🔌 17. Cho Application sử dụng Secret
Secret chỉ hữu ích khi Application sử dụng nó.
Ví dụ Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: todo-backend
namespace: todo-app
spec:
template:
spec:
containers:
- name: backend
image: todo-backend:1.0
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: todo-db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: todo-db-secret
key: password
Flow:
SealedSecret
│
▼
Secret
│
▼
Deployment
│
▼
Pod
│
▼
DB_PASSWORD
Kubernetes hỗ trợ sử dụng Secret thông qua environment variable hoặc volume mount. (Kubernetes)
🧪 18. See Result — Kiểm tra Pod
Kiểm tra:
kubectl get pods -n todo-app
Sau đó:
kubectl describe pod <pod-name> -n todo-app
Bạn sẽ thấy:
Environment:
DB_USERNAME: <set to the key 'username' in secret 'todo-db-secret'>
DB_PASSWORD: <set to the key 'password' in secret 'todo-db-secret'>
Điều đó chứng minh:
Git
↓
ArgoCD
↓
SealedSecret
↓
Secret
↓
Pod
↓
Application
🧠 19. Hiểu bản chất: Secret vs SealedSecret
Đây là phần quan trọng nhất của Lab.
| Secret | SealedSecret | |
|---|---|---|
| Kubernetes hiểu trực tiếp? | ✅ | ❌ |
| Có thể chứa plaintext? | ✅ | ❌ |
| Base64? | Có | Không phải cơ chế bảo mật chính |
| Commit vào Git? | ❌ | ✅ |
| Controller cần thiết? | ❌ | ✅ |
| Dùng cho Application? | ✅ | ❌ |
| Mục đích | Runtime Secret | GitOps representation |
Có thể hiểu đơn giản:
SealedSecret
│
│ "bản đã khóa"
▼
Secret
│
│ "bản đã mở khóa"
▼
Application
🔐 20. Public Key và Private Key
Sealed Secrets hoạt động dựa trên encryption key.
Có thể hình dung:
Public Key
│
▼
Secret ──────► Encrypt
│
▼
SealedSecret
│
│ Git
▼
GitHub
Kubernetes
│
▼
Private Key
│
▼
Decrypt
│
▼
Secret
Điểm quan trọng:
Developer có thể dùng public key để seal secret, nhưng private key dùng để giải mã phải được bảo vệ trong cluster.
Vì vậy, đừng đưa private key của Sealed Secrets controller vào Git.
⚠️ 21. Một vấn đề production rất quan trọng
Giả sử cluster bị mất.
Bạn dựng cluster mới:
Old Cluster
│
└── Sealed Secrets private key
Nếu private key cũng mất:
Git
│
▼
SealedSecret
│
X
Cannot decrypt
Do đó production cần có chiến lược:
Sealed Secrets private key
│
▼
Secure Backup
│
├── encrypted backup
├── restricted access
└── disaster recovery
Đừng nhầm:
Backup Git repository ≠ backup secret decryption key.
🌎 22. Secrets giữa Dev / Staging / Production
Một lỗi phổ biến là dùng chung secret:
dev
│
└── DB_PASSWORD=abc
staging
│
└── DB_PASSWORD=abc
production
│
└── DB_PASSWORD=abc
Không nên.
Nên có credential riêng:
GitOps
│
┌───────┼────────┐
▼ ▼ ▼
dev staging prod
│ │ │
Secret Secret Secret
│ │ │
DB DB DB
Ví dụ:
dev
todo-db-secret
staging
todo-db-secret
production
todo-db-secret
Tên có thể giống nhau, nhưng giá trị secret khác nhau.
🧩 23. GitOps Repository nên tổ chức thế nào?
Một cấu trúc đơn giản:
todo-gitops/
│
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
│
└── overlays/
│
├── dev/
│ ├── kustomization.yaml
│ └── sealed-secret.yaml
│
├── staging/
│ ├── kustomization.yaml
│ └── sealed-secret.yaml
│
└── production/
├── kustomization.yaml
└── sealed-secret.yaml
Điểm quan trọng:
base/
│
└── Application configuration
overlays/
│
├── dev/
│
├── staging/
│
└── production/
│
└── Environment-specific secrets
🆚 24. Sealed Secrets vs External Secrets
Sealed Secrets không phải giải pháp duy nhất.
Trong production, bạn sẽ thường gặp thêm External Secrets Operator (ESO).
ESO cho phép Kubernetes lấy secret từ external secret manager như AWS Secrets Manager, Google Secret Manager, Azure Key Vault, HashiCorp Vault... rồi tạo Kubernetes Secret. (External Secrets)
Sealed Secrets
Git
│
▼
Encrypted Secret
│
▼
ArgoCD
│
▼
Kubernetes
External Secrets
Git
│
▼
ExternalSecret
│
▼
ArgoCD
│
▼
External Secret Manager
│
▼
Kubernetes Secret
Có thể hiểu:
| Sealed Secrets | External Secrets | |
|---|---|---|
| Secret thật nằm ở đâu? | Kubernetes | Secret Manager |
| Git chứa gì? | Encrypted secret | Reference |
| Dễ setup Lab? | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| Phù hợp Local Lab | ✅ | ✅ |
| Production lớn | ✅ | ⭐⭐⭐⭐⭐ |
| Rotation | Hạn chế hơn | Tốt |
| Cloud Secret Manager | Không bắt buộc | Rất phù hợp |
👉 Với Lab 9, Sealed Secrets giúp bạn hiểu bản chất GitOps Secrets trước.
Trong hệ thống production lớn, đặc biệt khi đã sử dụng AWS/Azure/GCP, External Secrets + Secret Manager thường là hướng đáng cân nhắc hơn.
🧪 25. Exercise — Tự thực hành
Bây giờ hãy thử tự làm lại toàn bộ flow.
Exercise 1 — Tạo Secret
Tạo:
todo-api-secret
với:
API_KEY=dev-secret-key
Exercise 2 — Seal Secret
Tạo:
sealed-api-secret.yaml
và đảm bảo:
dev-secret-key
không xuất hiện trong file.
Exercise 3 — GitOps
Commit:
sealed-api-secret.yaml
vào GitOps repository.
Sau đó để ArgoCD tự sync.
Exercise 4 — Verify
Kiểm tra:
kubectl get sealedsecret -n todo-app
và:
kubectl get secret -n todo-app
Kết quả mong muốn:
SealedSecret
│
▼
Secret
│
▼
Pod
🧯 26. Troubleshooting
❌ SealedSecret không tạo Secret
Kiểm tra:
kubectl get sealedsecret -n todo-app
Sau đó:
kubectl describe sealedsecret todo-db-secret \
-n todo-app
Kiểm tra controller:
kubectl get pods -n kube-system | grep sealed
Xem log:
kubectl logs \
-n kube-system \
-l app.kubernetes.io/name=sealed-secrets
❌ ArgoCD báo OutOfSync
Kiểm tra:
argocd app get todo-app
Hoặc xem trực tiếp trên ArgoCD UI:
Application
↓
Sync Status
↓
Diff
Đặc biệt kiểm tra:
namespace
name
kind
apiVersion
❌ kubeseal không seal được Secret
Kiểm tra controller có hoạt động:
kubectl get pods -n kube-system | grep sealed
Sau đó kiểm tra certificate:
kubeseal --fetch-cert
Nếu cluster có vấn đề về connectivity, kubeseal có thể không lấy được certificate của controller.
🧠 27. Production Tips
🔥 Tip 1 — Đừng commit Secret plaintext
Sai:
secret.yaml
password: production123
Đúng hơn:
sealed-secret.yaml
encryptedData:
password: Ag...
🔥 Tip 2 — Base64 không bảo vệ secret
Đừng nghĩ:
data:
password: cHJvZHVjdGlvbjEyMw==
là an toàn.
Base64 chỉ là encoding. Kubernetes cũng cảnh báo rằng Base64 không cung cấp confidentiality. (Kubernetes)
🔥 Tip 3 — Không dùng chung credential giữa environment
Không nên:
dev password = prod password
Nếu dev bị compromise thì production cũng có nguy cơ.
🔥 Tip 4 — Rotate credential
Secret production nên có lifecycle:
Create
↓
Use
↓
Rotate
↓
Revoke old credential
Không nên để một password production tồn tại mãi mãi.
🔥 Tip 5 — GitOps không có nghĩa là "mọi thứ đều phải nằm trong Git"
GitOps nói rằng Git là source of truth cho desired state, nhưng không có nghĩa bạn phải đưa plaintext credentials vào Git.
ArgoCD được thiết kế để lấy desired application state từ Git và đồng bộ state đó vào Kubernetes. (Argo CD)
Với secret, ta có thể lưu:
Encrypted representation
hoặc:
Reference → External Secret Manager
thay vì:
Plaintext password
🎯 28. Tổng kết
Trước Lab:
Git
│
├── deployment.yaml
├── service.yaml
└── ❌ password
Sau Lab:
Git
│
├── deployment.yaml
├── service.yaml
└── sealed-secret.yaml
│
│ encrypted
▼
ArgoCD
│
▼
SealedSecret Controller
│
│ decrypt
▼
Secret
│
▼
Pod
Điều quan trọng nhất cần nhớ:
Không commit Kubernetes Secret plaintext vào Git.
Và cũng đừng học thuộc rằng:
"
SealedSecret= Secret an toàn tuyệt đối."
Hãy nhớ bản chất:
GitOps
+
Secret Management
=
Encrypted Secret / External Secret Reference
+
ArgoCD
+
Kubernetes Secret
Đó mới là cách tư duy khi xây dựng GitOps thực tế.
🏁 Sau Lab 9
Bạn đã có:
Lab 1 → GitOps Fundamentals
Lab 2 → GitOps Repository
Lab 3 → ArgoCD
Lab 4 → Deploy Application
Lab 5 → Sync & Self-Healing
Lab 6 → Kustomize
Lab 7 → Helm
Lab 8 → Multi-Environment
Lab 9 → 🔐 GitOps Secrets
Lab tiếp theo — Lab 10: ArgoCD Application & Project sẽ đi vào một vấn đề production quan trọng hơn: làm sao quản lý nhiều team, nhiều application và giới hạn quyền deploy của từng team bằng AppProject + RBAC.
All rights reserved