1. บทนำ: ทำไมต้องใช้ Self-Hosted Secrets Server?
ในโลกของ DevOps และ Kubernetes ปัจจุบัน การจัดการ Secrets (รหัสผ่าน, API keys, certificates) เป็นเรื่องสำคัญที่สุดด้าน security หนึ่ง บริษัทไทยหลายแห่งยังคงใช้วิธีเก่าๆ เช่น ใส่ secrets ใน environment variables หรือ commit secrets เข้า Git repository ซึ่งมีความเสี่ยงสูงต่อการรั่วไหลของข้อมูล
ข้อดีของการใช้ Self-Hosted Secrets Server:
- ควบคุมข้อมูล: ไม่ต้องพึ่งพิง cloud provider หรือเสียค่าบริการรายเดือน
- On-premise compliance: เหมาะสำหรับองค์กรที่ต้องรักษาข้อมูลในประเทศ (data sovereignty)
- integration กับ GitLab CI/CD: ตั้งค่า secrets ผ่าน GitLab CI/CD variables ได้ง่าย
- Free & Open Source: ใช้ HashiCorp Vault, Edge Vault หรือ Keycloak ได้ฟรี
- Full control: สามารถกำหนด policies, audit logs, rotation policy เองทั้งหมด
อื่นๆ Free Tier
HashiCorp Vault OSS, Edge Vault, Keycloak + Vault
Cloud-only
AWS Secrets Manager, Azure Key Vault, Google Secret Manager (ต้องเสียค่าบริการ)
2. เปรียบเทียบ Secrets Management Solutions
สำหรับ DevOps engineers ที่ต้องการ self-hosted open-source solution มีตัวเลือกหลักอยู่ 4 ตัว แต่ละตัวมีข้อดีข้อเสียที่ต่างกัน
HashiCorp Vault
อุตสาหกรรมสแตนดาร์ดสำหรับ Secrets Management
Edge Vault
Lightweight, Go-based, ติดตั้งง่าย
Keycloak + Vault
SSO + Secrets Management combo
Doppler (Self-Hosted)
AWS Secrets Manager Alternatives
สำหรับ AWS users ที่ไม่อยากเสียค่าบริการ
3. สิ่งที่ต้องเตรียม (Prerequisites)
Server Requirements
- CPU: 2+ cores (recommended 4 cores)
- RAM: 4GB+ (recommended 8GB)
- Storage: 50GB+ for persistence
- OS: Ubuntu 20.04+/22.04, Debian, or CentOS 8+
- Domain: ต้องมี domain หรือ subdomain (เช่น vault.yourcompany.com)
Software Requirements
- Docker & Docker Compose: สำหรับ containerization (เรcommended)
- NGINX/Apache: สำหรับ reverse proxy + TLS termination
- PostgreSQL/MySQL: สำหรับ storage backend (optional)
- Certbot/Let's Encrypt: สำหรับ TLS certificates
- GitLab CI/CD: สำหรับ integration (ไม่จำเป็นแต่แนะนำ)
คำแนะนำสำหรับบริษัทไทย:
- อย่าใช้ production server ที่ shared กับ services อื่นๆ
- แยก secrets server ออกเป็น isolated network (หรือ VPC)
- ใช้ firewall rules จำกัด access only from CI/CD servers
- ตั้ง audit logging และ backup auto ทุกคืน
- สำหรับพนักงานไทยที่ใช้ GitLab ของบริษัท: ผสาน GitLab SSO กับ Vault JWT auth
4. Architecture Design
เลือก architecture ขึ้นอยู่กับ scale และ requirements ของบริษัท คุณสามารถเลือกได้ 3 แบบหลัก
Single Node (สำหรับ Development/Testing)
ข้อดี:
- ติดตั้งง่ายและรวดเร็ว
- ใช้ resources น้อย
- เหมาะสำหรับ development/testing
- ดูแลรักษาง่าย
ข้อจำกัด:
- Single point of failure
- ไม่เหมาะสำหรับ production
- Scale ได้ยาก
- ไม่มี failover
High Availability (สำหรับ Production)
ข้อดี:
- ไม่มี single point of failure
- High availability 99.99%
- Scale horizontally ได้
- เหมาะสำหรับ production use
- Auto-failover ถ้า node ใดล่ม
ข้อจำกัด:
- ซับซ้อนกว่า single node
- ต้องการ resources มากขึ้น (3+ nodes)
- ต้องตั้งค่า load balancer + storage HA
- ต้องมี expertise ด้าน DevOps
คำแนะนำ:
- Development/Testing: ใช้ Single Node หรือ even memory-only (Edge Vault)
- Production (small team): ใช้ Single Node + external storage backend
- Production (medium/large team): ใช้ HA deployment อย่างน้อย 3 nodes
- Cloud-hosted: consider AWS EKS + EFS สำหรับ storage backend
- ไม่ใช้ file-based storage (file backend) สำหรับ production - ใช้ PostgreSQL/MySQL แทน
5. Step-by-Step Installation
ฉันจะแนะนำการติดตั้ง HashiCorp Vault โดยใช้ Docker & Docker Compose ซึ่งเป็นวิธีที่ง่ายที่สุดและมีความยืดหยุ่นสูงสุดในปัจจุบัน
1. Database Backend Setup (PostgreSQL)
version: '3.8'
services:
vault-db:
image: postgres:15-alpine
container_name: vault-db
environment:
- POSTGRES_USER=vault
- POSTGRES_PASSWORD=your_strong_password_here
- POSTGRES_DB=vault
volumes:
- vault_data:/var/lib/postgresql/data
# Mount schema SQL file for automatic initialization
- ./vault-schema.sql:/docker-entrypoint-initdb.d/init.sql:ro
networks:
- vault-network
volumes:
vault_data:
networks:
vault-network:
driver: bridge
$ docker-compose -f docker-compose.db.yml up -d
# ตรวจสอบ database connection
$ docker ps
$ docker exec -it vault-db psql -U vault -d vault -c "\dt"
# ต้องเห็นตาราง vault_kv_store และอื่นๆ ถึงจะผ่าน
สำคัญมาก! PostgreSQL Database Schema
เมื่อ Vault เริ่มต้นเชื่อมต่อกับ PostgreSQL ครั้งแรก Vault จะไม่สร้าง schema อัตโนมัติ! คุณต้องรันคำสั่ง initialization ด้วยตนเอง
# ตรวจสอบว่า database มี schema หรือไม่
$ docker exec -it vault-db psql -U vault -d vault -c "\dt"
# ถ้าไม่มีตาราง จะเห็น: No relations found
# ให้รันคำสั่งนี้เพื่อสร้าง schema (ต้องทำก่อน start Vault server)
$ docker exec -it vault-db psql -U vault -d vault -c "\i /docker-entrypoint-initdb.d/schema.sql"
# หรือใช้ vault operator init แล้วเช็ค logs ว่ามี error หรือไม่
$ docker logs -f vault
2. Vault Server Setup
version: '3.8'
services:
vault:
image: hashicorp/vault:1.15.3
container_name: vault
restart: always
cap_add:
- IPC_LOCK
environment:
- VAULT_ADDR=http://0.0.0.0:8200
- VAULT_API_ADDR=http://0.0.0.0:8200
- VAULT_CLUSTER_ADDR=https://0.0.0.0:8201
volumes:
- ./vault-config:/vault/config
- ./vault-data:/vault/data
- ./vault-logs:/vault/logs
ports:
- "8200:8200"
- "8201:8201"
- "8202:8202"
networks:
- vault-network
depends_on:
- vault-db
networks:
vault-network:
external: true
name: vault-network
storage "postgresql" {
connection_url = "postgresql://vault:your_strong_password_here@vault-db:5432/vault?sslmode=disable"
}
listener "tcp" {
address = "0.0.0.0:8200"
cluster_address = "0.0.0.0:8201"
tls_disable = true
}
api_addr = "http://vault:8200"
cluster_addr = "https://0.0.0.0:8201"
ui = true
3. NGINX Reverse Proxy + TLS
version: '3.8'
services:
nginx:
image: nginx:alpine
container_name: vault-nginx
ports:
- "443:443"
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
networks:
- vault-network
depends_on:
- vault
networks:
vault-network:
external: true
name: vault-network
events {
worker_connections 1024;
}
http {
# Redirect HTTP to HTTPS
server {
listen 80;
server_name vault.yourcompany.com;
return 301 https://$server_name$request_uri;
}
# HTTPS server
server {
listen 443 ssl;
server_name vault.yourcompany.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://vault:8200;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
สร้าง SSL certificates:
# สร้าง directory สำหรับ SSL
$ mkdir -p ssl
# สร้าง self-signed certificate ( development only)
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout ssl/key.pem \
-out ssl/cert.pem \
-subj "/C=TH/ST=Bangkok/L=Bangkok/O=YourCompany/CN=vault.yourcompany.com"
# หรือใช้ Let's Encrypt (production)
$ certbot certonly --nginx -d vault.yourcompany.com
แก้ไขปัญหา: relation "vault_kv_store" does not exist
ปัญหา: คุณเห็น error ERROR: relation "vault_kv_store" does not exist (SQLSTATE 42P01) ใน Vault logs
สาเหตุ: ปัจจุบัน Vault ไม่ได้สร้าง database schema อัตโนมัติอีกต่อไป (ตั้งแต่ Vault 1.10+) คุณต้องเตรียม database schema ด้วยตนเอง
วิธีแก้ไข:
# 1. เตรียม schema SQL file
$ curl -s https://raw.githubusercontent.com/hashicorp/vault/master/vendor/github.com/hashicorp/vault/storage/sql/mysql/schema.sql \
-o vault-schema.sql
# 2. Copy schema ไปที่ db container
$ docker cp vault-schema.sql vault-db:/vault-schema.sql
# 3. Import schema ไปที่ database
$ docker exec -it vault-db psql -U vault -d vault -f /vault-schema.sql
# 4. ตรวจสอบว่า schema ถูกสร้างแล้ว
$ docker exec -it vault-db psql -U vault -d vault -c "\dt"
# คุณควรเห็นตารางเหล่านี้:
# vault_kv_store
# vault_audit_log
# vault HaMk... (อื่นๆ)
หรือถ้าต้องการใช้ Vault CLI ในการสร้าง schema:
# วิธีที่ 2: ใช้ vault operator init แล้ว check logs
$ docker logs vault | grep -i "sql"
# ถ้าเห็น error เกี่ยวกับ table ให้ทำตามขั้นตอนด้านบน
ดาวน์โหลด Vault Schema SQL
ก่อน start Vault คุณต้องเตรียม schema SQL file สำหรับ PostgreSQL
# ดาวน์โหลด schema สำหรับ PostgreSQL
$ curl -s https://raw.githubusercontent.com/hashicorp/vault/main/operator/raft/migrate/vault_migrations/sql/vault.sql \
-o vault-schema.sql
# หรือสำหรับ Vault version 1.10+ (ใช้ schema สำหรับ PostgreSQL)
$ curl -s https://raw.githubusercontent.com/hashicorp/vault/main/storage/sql/mysql/schema.sql \
-o vault-schema.sql
# ตรวจสอบว่าไฟล์ถูกดาวน์โหลด
$ ls -la vault-schema.sql
$ head -n 20 vault-schema.sql
หมายเหตุ: ไฟล์นี้จะถูก mount เข้า container ผ่าน docker-compose ที่มี path
./vault-schema.sql:/docker-entrypoint-initdb.d/init.sql:ro
PostgreSQL จะรัน script นี้อัตโนมัติเมื่อ container เริ่มครั้งแรก
4. Start Vault & Unseal
# Start all services
$ docker-compose -f docker-compose.db.yml up -d
$ docker-compose -f docker-compose.vault.yml up -d
$ docker-compose -f docker-compose.nginx.yml up -d
# ตรวจสอบ logs
$ docker logs -f vault
# Initialize Vault (first time)
$ docker exec -it vault vault operator init
# ผลลัพท์จะได้:
# Unseal Key 1: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Unseal Key 2: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Unseal Key 3: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Unseal Key 4: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Unseal Key 5: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Initial Root Token: hvs.XXXXXXXXXXXXXXXXXXXXXXXXXXXX
# Unseal Vault (ต้องใส่ 3 keys หรือตาม configuration)
$ docker exec -it vault vault operator unseal
# Login
$ docker exec -it vault vault login hvs.XXXXXXXXXXXXXXXXXXXXXXXXXXXX
# ตรวจสอบ status
$ docker exec -it vault vault status
5. Edge Vault (Lightweight Alternative)
# Download Edge Vault binary
$ wget https://github.com/eyberg/edv/releases/download/v1.0.0/edv-linux-amd64
$ chmod +x edv-linux-amd64
$ sudo mv edv-linux-amd64 /usr/local/bin/edv
# Run Edge Vault (memory only - for dev/test)
$ edv server --addr :8200
# หรือ run ด้วย Docker
$ docker run -p 8200:8200 \
-e EDV_ADDR=:8200 \
-e EDV_STORAGE_TYPE=memory \
eyberg/edv:latest
6. GitLab CI/CD Integration
หลักการของการ integrate GitLab CI/CD กับ Vault คือ:
1) GitLab CI ดึง secrets จาก Vault ผ่าน API
2) ใช้ secrets เป็น environment variables ใน pipeline
3) ไม่เก็บ secrets ใน GitLab CI/CD variables แบบ plain text
GitLab CI/CD Job Example
stages:
- build
- deploy
variables:
VAULT_ADDR: "https://vault.yourcompany.com"
VAULT_ENGINE: "kv-v2"
VAULT_SECRET_PATH: "gitlab/ci"
build:
stage: build
image: alpine:latest
script:
- apk add --no-cache curl jq
- |
# Authenticate with Vault using AppRole
ROLE_ID=$(cat /etc/vault/role_id)
SECRET_ID=$(cat /etc/vault/secret_id)
# Get Vault token
RESPONSE=$(curl -s -X POST "$VAULT_ADDR/v1/auth/approle/login" \
-d "{\"role_id\":\"$ROLE_ID\",\"secret_id\":\"$SECRET_ID\"}")
TOKEN=$(echo $RESPONSE | jq -r '.auth.client_token')
# Read secret from Vault
SECRET_RESPONSE=$(curl -s -H "X-Vault-Token: $TOKEN" \
"$VAULT_ADDR/v1/$VAULT_ENGINE/data/$VAULT_SECRET_PATH")
DB_PASSWORD=$(echo $SECRET_RESPONSE | jq -r '.data.data.db_password')
API_KEY=$(echo $SECRET_RESPONSE | jq -r '.data.data.api_key')
# Export as variables for next jobs
echo "export DB_PASSWORD=$DB_PASSWORD" >> build.env
echo "export API_KEY=$API_KEY" >> build.env
# Use the secrets
echo "✓ Database password retrieved successfully"
echo "✓ API key retrieved successfully"
artifacts:
reports:
dotenv: build.env
expire_in: 1 hour
deploy:
stage: deploy
image: alpine:latest
script:
- apk add --no-cache curl
- |
echo "Deploying with secrets from Vault..."
echo "Database host: $DB_HOST"
echo "API endpoint: $API_ENDPOINT"
# Deploy your application
./deploy.sh
AppRole Authentication in Vault:
# สร้าง AppRole และ secret ID สำหรับ GitLab CI/CD
$ docker exec -it vault vault write auth/approle/role/gitlab-ci \
secret-id-ttl=24h \
token-ttl=1h \
token-policies="gitlab-ci-policy"
# ดึง Role ID และ Secret ID
$ docker exec -it vault vault read -field=role_id auth/approle/role/gitlab-ci/role-id
$ docker exec -it vault vault read -field=secret_id auth/approle/role/gitlab-ci/secret-id
# เก็บ Role ID และ Secret ID ใน GitLab CI/CD Variables
# Settings > CI/CD > Variables > Add Variable
# - VAULT_ROLE_ID: (Role ID from above)
# - VAULT_SECRET_ID: (Secret ID from above)
GitLab CI/CD Variables Setup
Project Settings → CI/CD → Variables:
- VAULT_ADDR: https://vault.yourcompany.com
- VAULT_ROLE_ID: (Role ID จาก Vault)
- VAULT_SECRET_ID: (Secret ID จาก Vault)
- VAULT_ENGINE: kv-v2 (หรือ kv)
- VAULT_SECRET_PATH: gitlab/ci หรือ your-app/secrets
- ตั้ง "Protect variable" = ON (protect)
- ตั้ง "Masked" = ON (ป้องกันการ expose ใน logs)
Secrets in Vault (kv-v2):
# สร้าง secrets ใน Vault
$ docker exec -it vault vault kv put $VAULT_ENGINE/$VAULT_SECRET_PATH \
db_password="your_strong_db_password" \
db_host="postgres.yourcompany.com" \
db_port=5432 \
db_name="app_db" \
api_key="your_api_key_12345" \
api_secret="your_api_secret_67890"
# อ่าน secrets
$ docker exec -it vault vault kv get $VAULT_ENGINE/$VAULT_SECRET_PATH
Secret Rotation in CI/CD
สร้าง job สำหรับ rotation secrets อัตโนมัติ เช่น เปลี่ยน API keys ทุก 30 วัน
#!/bin/bash
# rotate-secrets.sh
VAULT_ADDR="https://vault.yourcompany.com"
SECRET_PATH="gitlab/ci"
NEW_API_KEY=$(openssl rand -base64 32)
NEW_API_SECRET=$(openssl rand -base64 64)
# Authenticate
ROLE_ID=${VAULT_ROLE_ID:-$(cat /etc/vault/role_id)}
SECRET_ID=${VAULT_SECRET_ID:-$(cat /etc/vault/secret_id)}
RESPONSE=$(curl -s -X POST "$VAULT_ADDR/v1/auth/approle/login" \
-d "{\"role_id\":\"$ROLE_ID\",\"secret_id\":\"$SECRET_ID\"}")
TOKEN=$(echo $RESPONSE | jq -r '.auth.client_token')
# Update secrets
curl -s -H "X-Vault-Token: $TOKEN" \
-X POST "$VAULT_ADDR/v1/kv/data/$SECRET_PATH" \
-d "{\"data\": {
\"api_key\": \"$NEW_API_KEY\",
\"api_secret\": \"$NEW_API_SECRET\"
}}" | jq .
# Output new secrets for next pipeline
echo "NEW_API_KEY=$NEW_API_KEY" >>Rotate.env
echo "NEW_API_SECRET=$NEW_API_SECRET" >>Rotate.env
# Notify team (Slack/Email)
echo "✓ Secrets rotated successfully!"
Scheduled Rotation:
Use GitLab CI/CD schedules: Settings → CI/CD → Pipelines Schedules
# .gitlab-ci-rotate.yml
rotate_secrets:
stage: rotate
image: alpine:latest
script:
- apk add --no-cache curl openssl jq
- ./rotate-secrets.sh
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
7. Security Best Practices
1. Encryption
-
Encryption at rest: ใช้ PostgreSQL/MySQL backend ที่มี encryption ที่ disk level (เช่น PostgreSQL TDE, MySQL Transparent Data Encryption)
-
Encryption in transit: ใช้ TLS 1.2+ สำหรับทุก connection ( Vault → Client, Vault → Database)
-
Mandatory TLS: ตั้งค่า vault config ให้ require TLS
2. Access Control
-
RBAC (Role-Based Access Control): สร้าง roles แยกตาม use case
-
Least privilege: ให้สิทธิ์น้อยที่สุดเท่าที่จำเป็น
-
Audit logging: เปิด audit logging เสมอ
3. Policy Examples
# policies/gitlab-ci-policy.hcl
path "kv/data/gitlab/ci" {
capabilities = ["read", "list"]
}
path "kv/metadata/gitlab/ci" {
capabilities = ["list"]
}
# Separate policy for developers
path "kv/data/developers/*" {
capabilities = ["read"]
}
# Admin policy (restricted)
path "sys/*" {
capabilities = ["deny"]
}
path "auth/*" {
capabilities = ["deny"]
}
4. Backup & Recovery
-
Database backup: Backup PostgreSQL/MySQL ทุก 1 ชั่วโมง
-
Unseal keys: เก็บ unseal keys แยกอย่างปลอดภัย (HSM, Hashicorp Sentinel, หรือ physical safe)
-
Root token: เก็บ root token ใน 1Password/Hashicorp Vault ขั้นสูงหรือ physical safe
-
Test recovery: ทดสอบ restore และ unseal process อย่างน้อยทุก quarter
5. Additional Security Hardening
Network Security
- ใช้ firewall rules จำกัด ingress/egress
- เก็บ secrets server ใน isolated network/VPC
- ใช้ mTLS สำหรับ inter-service communication
- Never expose Vault dashboard บน public internet
Authentication
- ใช้ AppRole สำหรับ applications
- ใช้ JWT สำหรับ GitLab CI/CD
- avoid use root token สำหรับ automation
- Enable MFA สำหรับ admin users ( Enterprise feature)
Monitoring
- Integrate Vault audit logs กับ ELK, Grafana Loki
- ตั้ง alerts สำหรับ suspicious activities
- Monitor failed login attempts
- regularly audit active tokens
Secret Rotation
- Rotate database passwords ทุก 30 days
- Rotate API keys ทุก 90 days
- ใช้ Vault's dynamic secrets feature
- Automate rotation ผ่าน CI/CD pipeline
สำหรับบริษัทไทย: Compliance Considerations
- Data sovereignty: Self-hosted ช่วยให้ข้อมูลอยู่ในไทย (เหมาะสำหรับ fintech, banking)
- Personal Data Protection Act (PDPA): Audit logging สำคัญมากสำหรับการพิสูจน์การปฏิบัติตาม PDPA
- Cloud compliance: ถ้าองค์กรมี compliance requirements (ISO 27001, PCI-DSS) ให้ document ทุก security controls
- Security audits: จัดให้มี security audit อย่างน้อยปีละ 1 ครั้ง
8. Migration Guide
คุณอาจต้อง migration จาก environment variables, GitLab CI/CD variables, หรือ secrets management tools อื่นมาใช้ Vault
Migration from Environment Variables
Before (Insecure):
# docker-compose.yml (BAD!)
version: '3.8'
services:
app:
environment:
- DB_PASSWORD=secretpassword123
- API_KEY=api123456789
- AWS_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE
After (Secure with Vault):
# docker-compose.yml (GOOD!)
version: '3.8'
services:
app:
# Remove secrets from env vars
environment:
- VAULT_ADDR=https://vault.yourcompany.com
# Fetch secrets at runtime
command: /bin/bash -c 'source /app/fetch-secrets.sh && ./app'
Migration Script: Export Secrets to Vault
#!/bin/bash
# export-to-vault.sh
# Script to export secrets from env vars to Vault
VAULT_ADDR="https://vault.yourcompany.com"
SECRET_PATH="migrated-secrets"
# Read from old .env file (backup first!)
source .env.backup
# Authenticate
TOKEN=$(curl -s -X POST "$VAULT_ADDR/v1/auth/approle/login" \
-d "{\"role_id\":\"$VAULT_ROLE_ID\",\"secret_id\":\"$VAULT_SECRET_ID\"}" | jq -r '.auth.client_token')
# Export each secret
export_to_vault() {
local name=$1
local value=$2
if [ -n "$value" ] && [ "$value" != "" ]; then
echo "Exporting $name..."
curl -s -H "X-Vault-Token: $TOKEN" \
-X POST "$VAULT_ADDR/v1/kv/data/$SECRET_PATH" \
-d "{\"data\": {\"$name\": \"$value\"}}" | jq .
fi
}
# Export secrets
export_to_vault "db_password" "$DB_PASSWORD"
export_to_vault "db_host" "$DB_HOST"
export_to_vault "api_key" "$API_KEY"
export_to_vault "aws_access_key" "$AWS_ACCESS_KEY"
echo "✓ Migration complete!"
Important Notes:
- Always backup old secrets before migration
- Use encrypted channel for migration (SSH, VPN)
- After migration, rotate ALL secrets immediately
- Remove secrets from git history (git filter-branch)
- Update CI/CD to use Vault instead of env vars
From GitLab CI/CD Variables
ขั้นตอน:
- Create vault secret store: สร้าง secrets ใน Vault แทน GitLab CI variables
- Setup AppRole: สร้าง AppRole สำหรับ GitLab CI/CD
- Update .gitlab-ci.yml: แก้ไข pipeline ให้ดึง secrets จาก Vault
- Remove masked variables: ลบ secrets ออกจาก GitLab CI/CD variables
- Test everything: Test pipeline ก่อนใช้จริง
Security upgrade:
GitLab CI/CD variables ถูกเก็บแบบ encrypted แต่ still accessible to project maintainers. การใช้ Vault ทำให้ secrets ไม่เห็นแม้แต่ตัว GitLab administrators
Checklist หลัง Migration:
9. FAQ ( Frequently Asked Questions)
1. Vault กับ Docker Secrets ต่างกันอย่างไร?
Docker Secrets: ใช้ได้เฉพาะกับ Docker Swarm แบบ native secrets management ของ Docker
Vault: External secret management system ที่ใช้ได้กับทุก orchestration platform (Kubernetes, Docker Swarm, bare metal, cloud)
สรุป:
- Docker Secrets: ง่าย แต่จำกัดเฉพาะ Docker Swarm
- Vault: ซับซ้อนกว่า แต่ flexible และ powerful กว่า
- สำหรับ Kubernetes: ใช้ External Secrets Operator กับ Vault
2. เปิด TLS ใน Vault ยังไง?
ปัจจุบัน Vault documentation แนะนำให้ใช้ reverse proxy (NGINX, Traefik) สำหรับ TLS termination
# vault-config/vault.hcl
listener "tcp" {
address = "0.0.0.0:8200"
cluster_address = "0.0.0.0:8201"
tls_disable = true # Disable dans Vault, use NGINX for TLS
}
# NGINX จัดการ TLS termination
# See section 5.3 สำหรับ NGINX configuration
3. เก็บ unseal keys อย่างปลอดภัย?
Unseal keys ต้องเก็บอย่างปลอดภัยมาก เพราะหากสูญหาย จะไม่สามารถ access secrets ได้เลย (data loss)
เก็บ unseal keys 3/5 copies ใน physical safe พร้อม access control
ใช้ Vault secondary cluster สำหรับเก็บ unseal keys (highly recommended)
เก็บใน 1Password/Bitwarden พร้อม separate storage ที่คนละที่
4. เริ่มต้นใช้งาน Vault ยังไงดี?
แนะนำ path สำหรับทีมไทย:
- Start with Single Node Vault (Docker) for development
- ใช้ AppRole authentication (ง่ายที่สุด)
- เริ่มจาก secrets ง่ายๆ ก่อน: database passwords, API keys
- ตั้ง audit logging และ backup
- ค่อยๆ migrate secrets จาก GitLab CI/CD variables ไป Vault
- Upgrade เป็น HA cluster เมื่อมี production workload
5. ต้องใช้ PostgreSQL backend หรือไม่?
ไม่จำเป็น (Development)
- File backend: เหมาะสำหรับ testing อย่างเดียว
- Memory backend: ข้อมูลหายเมื่อ restart
- Local only ไม่ใช้ cluster mode
จำเป็น (Production)
- PostgreSQL/MySQL/backend ใช้สำหรับ HA deployment
- ต้องใช้ external storage สำหรับ persistence
- File backend ไม่รองรับ cluster mode
10. สรุปและคำแนะนำ
การจัดการ secrets แบบ self-hosted ด้วย open-source tools เป็นทางเลือกที่ดีสำหรับบริษัทไทยที่ต้องการควบคุมข้อมูลของตัวเอง ไม่ต้องพึ่งพิง cloud providers และลด overhead ด้าน cost
สำหรับ DevOps engineers และ SREs ที่ต้องการเริ่มต้น: แนะนำให้เริ่มจาก HashiCorp Vault ด้วย Docker deployment (single node) ก่อน ตามด้วยการ migrate secrets จาก GitLab CI/CD variables
สำหรับ บริษัทขนาดเล็กหรือ startups: ใช้ Edge Vault สำหรับ development/testing และค่อยๆ upgrade ไป production Vault ทีหลัง
สำหรับ องค์กรขนาดกลางถึงใหญ่ที่ใช้ GitLab SSO: พิจารณาใช้ Keycloak + Vault combo เพื่อ unified authentication ทั้ง systems
Quick Start Command:
# Quick start Vault (memory only - for dev/test)
$ docker run -d --name vault \
-p 8200:8200 \
-e VAULT_DEV_ROOT_TOKEN_ID="hvs.devtoken" \
-e VAULT_DEV_LISTEN_ADDRESS="0.0.0.0:8200" \
hashicorp/vault:1.15.3
# Login
$ export VAULT_ADDR="http://localhost:8200"
$ export VAULT_TOKEN="hvs.devtoken"
$ vault status
# Store your first secret
$ vault kv put kv/test message="Hello from Bangkok!"
Happy Secret Management! ถ้ามีคำถามเพิ่มเติม หรือ encounter issues ตอนติดตั้ง สามารถ comment ได้เลยครับ