
SOPS Encryption กับ Post-mortem Analysis —
SOPS Encryption

SOPS Secrets OPerationS เข้ารหัสไฟล์ Secrets Mozilla YAML JSON ENV INI เข้ารหัสเฉพาะ Value ใช้ AWS KMS GCP KMS Azure Key Vault age PGP Git ปลอดภัย
Post-mortem Analysis วิเคราะห์หลัง Incident Root Cause Timeline Impact Action Items Blameless ไม่โทษบุคคล โฟกัสระบบกระบวนการ
อ่านเพิ่ม: LXC vs Docker เลือก Container Technology อะไรดี · อ่านเพิ่ม: Proxmox VE Cluster ทำ High Availability สำหรับ Home Lab · อ่านเพิ่ม: MinIO S3 Compatible Storage self-hosted ทดแทน AWS S3
SOPS Configuration
=== SOPS Setup และ Configuration ===
1. ติดตั้ง SOPS
macOS: brew install sops
Linux: wget https://github.com/getsops/sops/releases/download/v3.8.1/sops-v3.8.1.linux.amd64 -O /usr/local/bin/sops && chmod +x /usr/local/bin/sops
Windows: scoop install sops
2. ติดตั้ง age (Key Management)
brew install age
age-keygen -o ~/.sops/age/keys.txt
export SOPS_AGE_KEY_FILE=~/.sops/age/keys.txt
3. .sops.yaml — Configuration File
creation_rules:
- path_regex: \.enc\.yaml$
age: >-
age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
- path_regex: secrets/.*\.yaml$
kms: arn:aws:kms:us-east-1:123456789:key/abcd-1234-efgh
- path_regex: prod/.*\.yaml$
gcp_kms: projects/my-project/locations/global/keyRings/sops/cryptoKeys/sops-key
age: >-
age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
4. เข้ารหัสไฟล์
sops --encrypt secrets.yaml > secrets.enc.yaml
sops --encrypt --in-place secrets.yaml
5. แก้ไขไฟล์เข้ารหัส
sops secrets.enc.yaml # เปิด Editor decrypt อัตโนมัติ
6. ถอดรหัสไฟล์
sops --decrypt secrets.enc.yaml > secrets.yaml
sops --decrypt --output-type json secrets.enc.yaml
7. Rotate Keys
sops --rotate --in-place secrets.enc.yaml
8. ใช้กับ Kubernetes
sops --decrypt secrets.enc.yaml | kubectl apply -f -
9. ใช้กับ Terraform
data "sops_file" "secrets" {
source_file = "secrets.enc.yaml"
}
sops_commands = {
"sops --encrypt": "เข้ารหัสไฟล์",
"sops --decrypt": "ถอดรหัสไฟล์",
"sops <file>": "เปิด Editor แก้ไข (decrypt อัตโนมัติ)",
"sops --rotate": "หมุนเวียน Key",
"sops --set": "เปลี่ยนค่าเฉพาะ Key",
"sops updatekeys": "อัปเดต Key Recipients",
}
backends = {
"age": "ง่าย ไม่ต้องมี Cloud, ใช้ Local Key File",
"AWS KMS": "ใช้ IAM Roles, Envelope Encryption",
"GCP KMS": "ใช้ Service Account, Cloud KMS",
"Azure Key Vault": "ใช้ Azure AD, Managed Identity",
"PGP": "ใช้ GPG Keys, Legacy แต่ยังรองรับ",
}
print("SOPS Commands:")
for cmd, desc in sops_commands.items():
print(f" {cmd}")
print(f" -> {desc}")
print(f"\nEncryption Backends:")
for backend, desc in backends.items():
print(f" {backend}: {desc}")
Post-mortem Template
# post_mortem.py — Post-mortem Analysis Framework
from dataclasses import dataclass, field
from typing import List, Dict
from datetime import datetime
@dataclass
class TimelineEvent:
time: str
description: str
actor: str
@dataclass
class ActionItem:
description: str
owner: str
priority: str # P0, P1, P2
deadline: str
status: str = "Open"
@dataclass
class PostMortem:
title: str
incident_id: str
severity: str # SEV1, SEV2, SEV3
date: str
duration: str
impact: str
summary: str
root_cause: str
timeline: List[TimelineEvent] = field(default_factory=list)
action_items: List[ActionItem] = field(default_factory=list)
what_went_well: List[str] = field(default_factory=list)
what_went_wrong: List[str] = field(default_factory=list)
where_we_got_lucky: List[str] = field(default_factory=list)
def show(self):
print(f"\n{'='*60}")
print(f"POST-MORTEM: {self.title}")
print(f"{'='*60}")
print(f" Incident: {self.incident_id} | Severity: {self.severity}")
print(f" Date: {self.date} | Duration: {self.duration}")
print(f" Impact: {self.impact}")
print(f"\n Summary: {self.summary}")
print(f"\n Root Cause: {self.root_cause}")
print(f"\n Timeline:")
for event in self.timeline:
print(f" [{event.time}] {event.description} ({event.actor})")
print(f"\n What went well:")
for item in self.what_went_well:
print(f" + {item}")
print(f"\n What went wrong:")
for item in self.what_went_wrong:
print(f" - {item}")
print(f"\n Action Items:")
for item in self.action_items:
print(f" [{item.priority}] {item.description}")
print(f" Owner: {item.owner} | Deadline: {item.deadline}")
# ตัวอย่าง Post-mortem
pm = PostMortem(
title="Database Credentials Leaked in Git Repository",
incident_id="INC-2024-042",
severity="SEV1",
date="2024-01-15",
duration="4 ชั่วโมง 23 นาที",
impact="Production Database Exposed, 2,300 Users Potentially Affected",
summary="Database credentials ถูก Commit เข้า Public Git Repository โดยไม่ได้เข้ารหัส ทำให้ถูกเข้าถึงจากภายนอก",
root_cause="Developer commit .env file ที่มี credentials โดยไม่ได้ใส่ใน .gitignore และไม่ได้ใช้ SOPS เข้ารหัส",
)
pm.timeline = [
TimelineEvent("09:15", "Developer push code + .env to GitHub", "Dev Team"),
TimelineEvent("10:30", "GitHub Secret Scanning Alert triggered", "GitHub"),
TimelineEvent("10:35", "Security team notified via PagerDuty", "Security"),
TimelineEvent("10:45", "Incident Commander assigned", "On-call"),
TimelineEvent("11:00", "Database credentials rotated", "DBA"),
TimelineEvent("11:30", "Git history rewritten to remove secrets", "DevOps"),
TimelineEvent("12:00", "Audit logs reviewed no unauthorized access", "Security"),
TimelineEvent("13:38", "All-clear declared incident closed", "IC"),
]
pm.what_went_well = [
"GitHub Secret Scanning ตรวจพบเร็ว",
"Incident Response ทำงานตามขั้นตอน",
"Credentials rotated ภายใน 30 นาที",
]
pm.what_went_wrong = [
"ไม่มี SOPS หรือ Secret Management",
".gitignore ไม่ครอบคลุม .env",
"Pre-commit hook ไม่ได้ตรวจ Secrets",
]
pm.action_items = [
ActionItem("ติดตั้ง SOPS สำหรับทุก Repository", "DevOps", "P0", "2024-01-22"),
ActionItem("เพิ่ม Pre-commit hook ตรวจ Secrets (gitleaks)", "DevOps", "P0", "2024-01-19"),
ActionItem("อบรม Security Awareness ทีม Dev", "Security", "P1", "2024-02-01"),
ActionItem("Audit .gitignore ทุก Repository", "DevOps", "P1", "2024-01-26"),
]
pm.show()
SOPS กับ CI/CD Pipeline
sops_cicd.py — SOPS in CI/CD Pipeline
GitHub Actions workflow
.github/workflows/deploy.yml
name: Deploy
on:
push:

branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-arn: arn:aws:iam::123456789:role/deploy-role
aws-region: us-east-1
- name: Install SOPS
run: |
wget -qO /usr/local/bin/sops \
https://github.com/getsops/sops/releases/download/v3.8.1/sops-v3.8.1.linux.amd64
chmod +x /usr/local/bin/sops
- name: Decrypt Secrets
run: sops --decrypt k8s/secrets.enc.yaml | kubectl apply -f -
- name: Deploy
run: kubectl apply -k k8s/overlays/production/
GitOps with Flux CD + SOPS
flux create source git my-app \
--url=https://github.com/org/my-app \
--branch=main
flux create kustomization my-app \
--source=my-app \
--path=./k8s/overlays/production \
--decryption-provider=sops \
--decryption-secret=sops-age
cicd_patterns = {
"GitHub Actions + SOPS": {
"flow": "Push -> Actions -> SOPS Decrypt -> kubectl apply",
"auth": "OIDC + IAM Role (ไม่ต้องเก็บ AWS Keys)",
},
"Flux CD + SOPS": {
"flow": "Git Push -> Flux detect -> SOPS Decrypt -> Apply",
"auth": "age Key ใน Kubernetes Secret",
},
"ArgoCD + SOPS": {
"flow": "Git Push -> ArgoCD Sync -> SOPS Plugin Decrypt",
"auth": "argocd-vault-plugin หรือ KSOPS",
},
"Terraform + SOPS": {
"flow": "terraform plan -> SOPS Provider Decrypt -> Apply",
"auth": "AWS KMS / GCP KMS via Provider",
},
}
print("SOPS CI/CD Patterns:")
for pattern, info in cicd_patterns.items():
print(f"\n [{pattern}]")
print(f" Flow: {info['flow']}")
print(f" Auth: {info['auth']}")
Secret Management Comparison
comparison = {
"SOPS": {"type": "File Encryption", "cost": "Free", "complexity": "Low"},
"HashiCorp Vault": {"type": "Secret Server", "cost": "Free/Enterprise", "complexity": "High"},
"AWS Secrets Manager": {"type": "Cloud Service", "cost": "$0.40/secret/mo", "complexity": "Low"},
"Sealed Secrets": {"type": "K8s Native", "cost": "Free", "complexity": "Medium"},
"External Secrets": {"type": "K8s Operator", "cost": "Free", "complexity": "Medium"},
}
print(f"\n\nSecret Management Comparison:")
for tool, info in comparison.items():
print(f" {tool}: {info['type']} | Cost: {info['cost']} | {info['complexity']}")
Best Practices
- SOPS + age: ใช้ age สำหรับ Local Development AWS KMS สำหรับ Production
- Pre-commit: ใช้ gitleaks Pre-commit Hook ตรวจ Secrets ก่อน Commit
- Key Rotation: หมุนเวียน Keys ทุก 90 วัน sops --rotate
- Blameless: Post-mortem ต้อง Blameless ไม่โทษบุคคล
- Action Items: ทุก Post-mortem ต้องมี Action Items พร้อม Owner และ Deadline
- 5 Whys: ใช้ 5 Whys หา Root Cause ที่แท้จริง
SOPS คืออะไร
Secrets OPerationS เข้ารหัสไฟล์ Secrets Mozilla YAML JSON ENV เข้ารหัสเฉพาะ Value AWS KMS GCP KMS age PGP Git ปลอดภัย