1. Cấu hình Encryption at Rest cho Persistent Volumes (PV) với Vault và KMS
Chúng ta sẽ sử dụng Vault để lưu trữ các key mã hóa (Data Encryption Keys - DEK) và Kubernetes Secrets để lưu trữ Key Master (KEK) dưới dạng tham chiếu, sau đó áp dụng cơ chế encryption vào StorageClass.
Mục đích là đảm bảo dữ liệu trên disk được mã hóa ngay khi ghi, ngay cả khi disk bị mất vật lý. Vault sẽ đóng vai trò là KMS (Key Management System) trung tâm.
Bước 1: Cài đặt và khởi động Vault trong Kubernetes
Triển khai Vault qua Helm chart với chế độ HCP Vault hoặc standalone, cấu hình backend lưu trữ là Raft để đảm bảo tính sẵn sàng cao.
Tại sao: Cần một KMS tin cậy để quản lý vòng đời của key mã hóa mà không lưu key plaintext trong code hay config file.
Kết quả mong đợi: Vault pod chạy trạng thái "Running", server ready.
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault --set server.dev.enabled=true --set server.dev.root_token="root-token-123456" --set injector.enabled=true
Chờ Vault khởi động và xác nhận trạng thái:
kubectl rollout status deployment/vault-server --timeout=300s
Bước 2: Cấu hình Secrets Engine và tạo Key cho Tenant
Chúng ta sẽ kích hoạt secrets engine "transit" của Vault để tạo key mã hóa cho từng tenant. Mỗi tenant sẽ có một key riêng biệt.
Tại sao: Sử dụng Transit Engine cho phép thực hiện các thao tác mã hóa/giải mã bên ngoài Vault, giúp giảm rủi ro rò rỉ key và hỗ trợ rotation tự động.
Kết quả mong đợi: Key được tạo thành công, trả về key_id và version.
export VAULT_ADDR='http://vault-server.vault.svc.cluster.local:8200'
export VAULT_TOKEN='root-token-123456'
vault secrets enable transit
vault transit create tenant-alpha-key
vault transit create tenant-beta-key
Bước 3: Tạo StorageClass với Kubernetes Encryption Provider
Cấu hình StorageClass sử dụng provider "kms" (hoặc "vault" tùy theo CSI driver) để liên kết với key đã tạo. Ở đây giả sử sử dụng CSI driver hỗ trợ Vault (ví dụ: cloud provider CSI hoặc openEBS).
Tại sao: StorageClass định nghĩa hành vi mặc định của Persistent Volume. Khi PV được tạo từ class này, dữ liệu sẽ tự động được mã hóa bằng key đã chỉ định.
Kết quả mong đợi: StorageClass mới được tạo, hiển thị provisioner và params encryption.
cat > /etc/kubernetes/storage-classes/encrypted-storage-vault.yaml
Verify kết quả phần 1
Kiểm tra xem StorageClass đã được tạo và có tham số encryption chưa:
kubectl get storageclass tenant-encrypted-vault -o yaml | grep -A 5 "parameters"
Tạo một PersistentVolumeClaim (PVC) sử dụng class này và kiểm tra xem PV được provision có thuộc tính encrypted hay không (tùy vào driver CSI cụ thể):
cat > /tmp/encrypted-pvc.yaml
2. Triển khai TLS Mutual Authentication giữa Microservices và Iceberg Catalog
Chúng ta sẽ triển khai mTLS (Mutual TLS) giữa các service nội bộ và Iceberg Catalog (ví dụ: Trino hoặc Spark). Cả client và server đều phải xác thực lẫn nhau bằng chứng chỉ.
Tại sao: Bảo vệ đường truyền dữ liệu (Encryption in Transit) và ngăn chặn các cuộc tấn công Man-in-the-Middle hoặc truy cập trái phép từ service giả mạo.
Bước 1: Tạo CA và Certificate Signing Request (CSR)
Sử dụng OpenSSL để tạo CA nội bộ, sau đó tạo certificate cho Iceberg Catalog (server) và Client (microservice).
Tại sao: Trong môi trường kín (internal cluster), việc sử dụng CA tự ký giúp kiểm soát hoàn toàn vòng đời chứng chỉ mà không phụ thuộc bên thứ 3.
Kết quả mong đợi: Các file .crt (certificate) và .key (private key) được tạo ra.
mkdir -p /etc/pki/iceberg-ca /etc/pki/iceberg-server /etc/pki/iceberg-client
# Tạo CA Root
openssl genrsa -out /etc/pki/iceberg-ca/ca.key 4096
openssl req -x509 -new -nodes -key /etc/pki/iceberg-ca/ca.key -sha256 -days 3650 -out /etc/pki/iceberg-ca/ca.crt -subj "/CN=Iceberg-Root-CA"
# Tạo CSR cho Server (Iceberg Catalog)
openssl genrsa -out /etc/pki/iceberg-server/server.key 2048
openssl req -new -key /etc/pki/iceberg-server/server.key -out /etc/pki/iceberg-server/server.csr -subj "/CN=iceberg-catalog.svc.cluster.local"
openssl x509 -req -in /etc/pki/iceberg-server/server.csr -CA /etc/pki/iceberg-ca/ca.crt -CAkey /etc/pki/iceberg-ca/ca.key -CAcreateserial -out /etc/pki/iceberg-server/server.crt -days 365 -sha256
# Tạo CSR cho Client (Microservice)
openssl genrsa -out /etc/pki/iceberg-client/client.key 2048
openssl req -new -key /etc/pki/iceberg-client/client.key -out /etc/pki/iceberg-client/client.csr -subj "/CN=data-processor.svc.cluster.local"
openssl x509 -req -in /etc/pki/iceberg-client/client.csr -CA /etc/pki/iceberg-ca/ca.crt -CAkey /etc/pki/iceberg-ca/ca.key -CAcreateserial -out /etc/pki/iceberg-client/client.crt -days 365 -sha256
Bước 2: Tạo Kubernetes Secrets từ Certificates
Chuyển đổi các file chứng chỉ và key thành Kubernetes Secrets để mount vào Pod.
Tại sao: Kubernetes Secrets là cơ chế chuẩn để quản lý dữ liệu nhạy cảm trong cluster, giúp các container truy cập chứng chỉ mà không cần hardcode.
Kết quả mong đợi: Secrets 'iceberg-server-tls' và 'iceberg-client-tls' được tạo thành công.
kubectl create secret generic iceberg-server-tls \
--from-file=tls.crt=/etc/pki/iceberg-server/server.crt \
--from-file=tls.key=/etc/pki/iceberg-server/server.key \
--from-file=ca.crt=/etc/pki/iceberg-ca/ca.crt
kubectl create secret generic iceberg-client-tls \
--from-file=tls.crt=/etc/pki/iceberg-client/client.crt \
--from-file=tls.key=/etc/pki/iceberg-client/client.key \
--from-file=ca.crt=/etc/pki/iceberg-ca/ca.crt
Bước 3: Cấu hình Iceberg Catalog (Trino/Spark) sử dụng mTLS
Cấu hình file `catalog.properties` của Iceberg Catalog để bật TLS và yêu cầu client certificate.
Tại sao: Server cần biết nơi lưu trữ chứng chỉ để xác thực client và cần biết nơi lưu key để mã hóa kết nối.
Kết quả mong đợi: Iceberg Catalog khởi động với cấu hình TLS, từ chối kết nối không có chứng chỉ hợp lệ.
cat > /etc/iceberg/catalog.properties
Trong Deployment của Iceberg Catalog, mount secret vào đường dẫn `/etc/certs`:
cat > /etc/k8s/iceberg-catalog-deploy.yaml
Bước 4: Cấu hình Client (Microservice) kết nối qua mTLS
Cấu hình ứng dụng client (ví dụ: Python SDK hoặc Java) để sử dụng chứng chỉ client và trust CA khi gọi Iceberg Catalog.
Tại sao: Client phải gửi chứng chỉ của mình để server xác thực danh tính.
Kết quả mong đợi: Kết nối thành công, log không có lỗi SSL/TLS handshake.
cat > /app/config/iceberg_client_config.py
Verify kết quả phần 2
Sử dụng `curl` để test kết nối mTLS từ một container khác trong cluster:
kubectl exec -it -- bash -c "curl -v --cert /etc/certs/client.crt --key /etc/certs/client.key --cacert /etc/certs/ca.crt https://iceberg-catalog.svc.cluster.local:8080/v1/catalogs"
Kết quả mong đợi: HTTP 200 OK. Nếu chạy curl không có --cert, server sẽ trả về lỗi 403 Forbidden hoặc 401 Unauthorized.
3. Cấu hình Secret Management an toàn cho Keys mã hóa dữ liệu của từng Tenant
Sử dụng Vault Kubernetes Auth Method để tự động cấp phát secret (key mã hóa) cho mỗi tenant khi họ tạo namespace hoặc deployment.
Tại sao: Tránh việc lưu key hardcode trong code hoặc ConfigMap. Mỗi tenant chỉ có quyền truy cập key của chính mình.
Bước 1: Kích hoạt Kubernetes Auth Method trong Vault
Cấu hình Vault để nhận diện Pod của Kubernetes thông qua ServiceAccount Token.
Tại sao: Đây là phương thức xác thực an toàn nhất trong Kubernetes, sử dụng token JWT ngắn hạn được Kubernetes cấp phát.
Kết quả mong đợi: Vault chấp nhận token từ Kubernetes.
vault write auth/kubernetes config \
kubernetes_host="https://kubernetes.default.svc" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
issuer="https://kubernetes.default.svc"
Bước 2: Tạo Role trong Vault cho Tenant
Tạo role "tenant-alpha" trong Vault, ánh xạ với Kubernetes ServiceAccount của tenant đó, và cấp quyền truy cập vào key cụ thể.
Tại sao: Áp dụng nguyên tắc Least Privilege. Tenant Alpha không thể truy cập key của Tenant Beta.
Kết quả mong đợi: Role được tạo, ServiceAccount tương ứng có thể login vào Vault.
vault write auth/kubernetes/role/tenant-alpha \
bound_service_account_names="tenant-alpha-sa" \
bound_service_account_namespaces="tenant-alpha" \
policies="tenant-alpha-policy" \
ttl="1h"
vault policy write tenant-alpha-policy -
Bước 3: Cấu hình Vault Agent Sidecar Injector
Sử dụng Vault Agent Sidecar Injector để tự động mount secret vào container của ứng dụng khi Pod khởi động.
Tại sao: Giảm tải cho developer, không cần code logic lấy secret thủ công, đảm bảo secret luôn được làm mới (rotate) trong runtime.
Kết quả mong đợi: Pod có thêm sidecar container `vault-agent`, secret được mount vào `/vault/secrets`.
cat > /etc/k8s/tenant-app-deploy.yaml
Verify kết quả phần 3
Kiểm tra log của Pod để xem Vault Agent đã inject secret chưa:
kubectl logs -l app=tenant-alpha-app -c vault-agent | grep "vault-agent-inject-transit"
Vào trong container để kiểm tra biến môi trường:
kubectl exec -it -n tenant-alpha -- env | grep VAULT_KEY_ID
Kết quả mong đợi: Biến môi trường chứa key_id của tenant-alpha, không thấy key của tenant-beta.
4. Kiểm tra và xác minh quy trình luân chuyển key mã hóa tự động
Cấu hình tự động luân chuyển (Rotate) key mã hóa trong Vault và đảm bảo ứng dụng tự động nhận key mới mà không cần restart.
Tại sao: Tuân thủ yêu cầu bảo mật về tuổi thọ của key (Key Rotation Policy), giảm thiểu thời gian key bị lộ.
Bước 1: Kích tự động Rotation trong Vault
Cấu hình policy rotation cho key mã hóa, ví dụ: tự động tạo version mới mỗi 90 ngày.
Tại sao: Đảm bảo key cũ hết hạn và key mới được sinh ra tự động theo lịch.
Kết quả mong đợi: Key có version mới, version cũ vẫn còn để giải mã dữ liệu cũ.
vault write transit/rotate tenant-alpha-key
Kiểm tra version của key:
vault read transit/keys/tenant-alpha-key | grep version
Bước 2: Kiểm tra khả năng giải mã dữ liệu cũ với Key mới
Thực hiện giải mã một dữ liệu đã được mã hóa bằng version cũ của key, sử dụng version mới hiện tại.
Tại sao: Vault Transit Engine lưu trữ tất cả các version key. Khi rotate, nó vẫn giữ version cũ để giải mã dữ liệu cũ, đảm bảo không mất dữ liệu.
Kết quả mong đợi: Giải mã thành công, dữ liệu gốc được khôi phục.
# Giả sử chúng ta có ciphertext đã mã hóa trước đó
# Vault sẽ tự động chọn đúng version key để giải mã nếu không chỉ định
vault transit decrypt tenant-alpha-key -plaintext="base64-encoded-ciphertext-here"
Bước 3: Xác minh ứng dụng tự động nhận Key mới
Trong ứng dụng, khi gọi API để mã hóa dữ liệu mới, nó sẽ tự động sử dụng version mới nhất của key.
Tại sao: Đảm bảo dữ liệu mới được bảo vệ bằng key mạnh nhất (mới nhất).
Kết quả mong đợi: Dữ liệu mới được mã hóa với version key cao hơn dữ liệu cũ.
cat > /tmp/test_rotation.py
Verify kết quả phần 4
Kiểm tra logs của Vault để xem hoạt động rotate:
kubectl logs -f -l app=vault-server | grep "rotate"
Thực hiện kiểm tra cuối cùng: Đảm bảo sau khi rotate, dữ liệu cũ vẫn đọc được và dữ liệu mới được mã hóa với key mới.
# Đọc metadata của key để xem các version hiện có
vault read transit/keys/tenant-alpha-key | grep -A 10 "versions"
Kết quả mong đợi: Output hiển thị danh sách các versions (ví dụ: 1, 2, 3), trong đó version mới nhất là version đang được sử dụng để encrypt, và các version cũ vẫn tồn tại để decrypt.
Điều hướng series:
Mục lục: Series: Series: Xây dựng nền tảng Secure Multi-Tenant Data Platform với Kubernetes, Falco, OPA và Apache Iceberg để bảo vệ dữ liệu doanh nghiệp trong môi trường chia sẻ tài nguyên
« Phần 5: Cấu hình Falco để phát hiện xâm nhập và hành vi bất thường thời gian thực
Phần 7: Tự động hóa quy trình onboarding và offboarding cho tenant mới »