1. Thiết lập mTLS giữa Client và AI Inference Gateway
1.1. Tạo chứng chỉ tự ký (Self-Signed CA và Certificates)
Bước đầu tiên là tạo một Certificate Authority (CA) riêng cho cụm Kubernetes để đảm bảo mọi giao tiếp đều được mã hóa và xác thực hai chiều (mTLS). Chúng ta sẽ tạo CA, sau đó tạo certificate cho Gateway (server) và một certificate mẫu cho Client.
Thực hiện các lệnh sau trên node master hoặc máy quản lý để tạo cấu trúc thư mục và chứng chỉ:
mkdir -p /etc/k8s-tls/{ca,server,client}
cd /etc/k8s-tls/ca
# Tạo Private Key cho CA
openssl genrsa -out ca.key 4096
# Tạo Self-Signed Certificate cho CA (hạn 10 năm)
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
-subj "/C=VN/O=AI-Infra/CN=AI-Root-CA"
# Tạo Config cho Server (Gateway)
cat > server.cnf
Kết quả mong đợi: Bạn sẽ có các file .key và .crt trong các thư mục tương ứng. Đây là chứng chỉ gốc và chứng chỉ được ký để sử dụng trong Kubernetes.
1.2. Tạo Kubernetes Secrets và Config cho Gateway
Chuyển các chứng chỉ này vào Kubernetes dưới dạng Secrets. Chúng ta cần tạo Secret cho Server (để Gateway dùng) và Secret cho Client (để Client gửi đi). Gateway sẽ được cấu hình để yêu cầu client certificate.
cd /etc/k8s-tls
# Tạo Secret cho Server (Gateway)
kubectl create secret tls ai-gateway-tls \
--cert=server.crt --key=server.key \
--namespace=ai-inference
# Tạo Secret cho CA (để Gateway xác thực Client)
kubectl create secret generic ai-gateway-ca \
--from-file=ca.crt=ca/ca.crt \
--namespace=ai-inference
# Tạo Secret cho Client (ví dụ: service account gọi API)
kubectl create secret tls ai-client-tls \
--cert=client.crt --key=client.key \
--namespace=ai-inference
Kết quả mong đợi: Các Secret được tạo thành công trong namespace ai-inference. Gateway sẽ mount server cert vào, và client sẽ mount client cert vào.
1.3. Cấu hình Ingress Controller (Nginx) cho mTLS
Cấu hình Ingress để bắt buộc mTLS. Ingress Controller sẽ đóng vai trò là TLS Termination, nhưng ở đây chúng ta cần nó chuyển tiếp yêu cầu xác thực client certificate lên backend hoặc tự xác thực tại gateway. Chúng ta sẽ dùng annotation của Nginx Ingress để yêu cầu client certificate.
Tạo file Ingress manifest:
cat > /tmp/ai-gateway-ingress.yaml
Kết quả mong đợi: Ingress được áp dụng. Khi client không có chứng chỉ hợp lệ, Nginx sẽ trả về lỗi 400 Bad Request hoặc 403 Forbidden tùy cấu hình, đảm bảo chỉ client có cert mới kết nối được.
2. Triển khai OAuth2/OIDC và API Key Validation
2.1. Cài đặt Keycloak hoặc Auth Service
Để xác thực người dùng và cấp phát token, chúng ta sẽ triển khai một instance Keycloak đơn giản trong cluster. Nếu không muốn dùng Keycloak, bạn có thể dùng API Key validation trực tiếp trong Gateway, nhưng OIDC là chuẩn cho bảo mật enterprise.
Triển khai Keycloak qua Helm (giả sử đã có repo bitnami):
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install keycloak bitnami/keycloak \
--namespace=ai-inference \
--set auth.adminUser=admin \
--set auth.adminPassword=AdminPassword123! \
--set httpPort=8080
Kết quả mong đợi: Pod Keycloak chạy trong namespace ai-inference. Bạn có thể truy cập Keycloak UI để tạo Realm và Client.
2.2. Cấu hình API Key Validation trong AI Gateway (FastAPI/Flask)
Đối với các dịch vụ inference nội bộ không cần OIDC phức tạp, việc dùng API Key là hiệu quả nhất. Chúng ta sẽ viết một middleware Python để validate key trước khi gọi model vLLM.
Tạo file `security.py` trong project gateway:
cat > /app/gateway/security.py
Kết quả mong đợi: File Python được tạo. Khi deploy Gateway, bạn cần mount secret chứa API_KEY_1, API_KEY_2 vào container dưới dạng biến môi trường.
2.3. Tích hợp OIDC với Keycloak (Auth Proxy)
Để bảo vệ toàn bộ gateway bằng OAuth2, chúng ta sẽ dùng một reverse proxy như `oauth2-proxy` đứng trước Gateway. Proxy này sẽ xử lý việc redirect login và validate token từ Keycloak.
Tạo manifest cho oauth2-proxy:
cat > /tmp/oauth2-proxy-deployment.yaml
Kết quả mong đợi: oauth2-proxy chạy và chuyển tiếp traffic. Client phải login qua Keycloak để lấy token, proxy sẽ validate token và chuyển request lên Gateway.
3. Áp dụng Network Policies để cô lập Namespace AI
3.1. Cài đặt CNI hỗ trợ NetworkPolicy
Mặc định, Kubernetes không enforce Network Policy nếu không có CNI hỗ trợ (như Calico, Cilium, Weave). Giả sử chúng ta đang dùng Calico (phổ biến nhất cho Proxmox/K3s).
Verify CNI đang chạy:
kubectl get pods -n kube-system | grep calico
Kết quả mong đợi: Thấy các pod calico-node đang chạy. Nếu không, cần install Calico trước khi áp dụng policy.
3.2. Tạo NetworkPolicy để cô lập Namespace
Mục tiêu: Ngăn tất cả traffic vào namespace `ai-inference` trừ khi từ namespace `frontend` hoặc `monitoring`. Ngăn traffic ra ngoài trừ DNS và các service nội bộ cần thiết.
Tạo file policy:
cat > /tmp/ai-network-policy.yaml
Kết quả mong đợi: Policy được áp dụng. Các pod trong ai-inference sẽ bị cắt kết nối từ các namespace lạ. Chỉ các dịch vụ được whitelist mới gọi được.
4. Bảo vệ GPU Access và Ngăn chặn Root Escape
4.1. Cấu hình SecurityContext cho Pod
GPU access thường yêu cầu root hoặc group `video`. Để an toàn, chúng ta dùng `runAsNonRoot`, `readOnlyRootFilesystem` và `allowPrivilegeEscalation: false`. GPU access sẽ được cấp qua Device Plugin hoặc specific capability.
Tạo manifest deployment vLLM với security hardening:
cat > /tmp/vllm-secure-deployment.yaml
Kết quả mong đợi: Pod vLLM chạy với user ID 1000. Không thể chạy lệnh root bên trong container. GPU vẫn được cấp phát qua device plugin. Nếu hacker vào container, họ không thể mount host filesystem hoặc escalate privilege.
4.2. Sử dụng Pod Security Admission (PSA)
Để ngăn chặn vĩnh viễn việc deploy pod không an toàn, bật PSA ở mức "Restricted" cho namespace ai-inference.
kubectl label namespace ai-inference \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted
Kết quả mong đợi: Nếu cố gắng apply một manifest có `runAsRoot: true` hoặc `privileged: true` vào namespace này, Kubernetes sẽ từ chối (Error: pods "..." is forbidden: violates PodSecurity "restricted" policy).
5. Audit Log cho Request Nhạy cảm và Truy cập trái phép
5.1. Cấu hình Audit Policy cho Kubernetes API Server
Để log lại ai đã tạo/delete resource hoặc thay đổi config trong namespace AI, cần cấu hình Audit Policy trên API Server.
Tạo file audit-policy.yaml:
cat > /tmp/audit-policy.yaml
Kết quả mong đợi: Các action nhạy cảm trên resource trong namespace ai-inference sẽ được ghi log chi tiết (bao gồm cả body request/response) vào file audit log của kube-apiserver.
5.2. Log Business Logic trong Gateway (Sensitive Data Redaction)
Log trong ứng dụng Gateway cần được cấu hình để không leak dữ liệu nhạy cảm (như prompt chứa PII, API Key). Sử dụng middleware để mask dữ liệu trước khi log.
Thêm vào `security.py` hoặc `main.py` của Gateway:
import logging
import json
from fastapi import Request
from fastapi.responses import JSONResponse
# Cấu hình logger
logger = logging.getLogger("ai-gateway")
logger.setLevel(logging.INFO)
# Hàm mask dữ liệu nhạy cảm
def mask_sensitive_data(data: dict) -> dict:
sensitive_keys = ["api_key", "password", "prompt", "user_id"]
masked = {}
for k, v in data.items():
if k in sensitive_keys:
masked[k] = "***MASKED***"
else:
masked[k] = v
return masked
async def audit_logging_middleware(request: Request, call_next):
# Log request
body = await request.json()
masked_body = mask_sensitive_data(body)
logger.info(f"Incoming Request: {request.url.path} | Body: {masked_body}")
response = await call_next(request)
# Log response nếu cần
if response.status_code >= 400:
logger.warning(f"Error Response: {request.url.path} | Status: {response.status_code}")
return response
Kết quả mong đợi: Khi xem log (dùng `kubectl logs` hoặc ship về ELK/Splunk), các trường nhạy cảm luôn hiển thị là `***MASKED***`, đảm bảo tuân thủ GDPR và bảo mật dữ liệu.
5.3. Verify Kết quả Bảo mật
Thực hiện các test sau để xác nhận bảo mật đã hoạt động:
- Test mTLS: `curl https://ai-gateway.example.com -v` (không có client cert) -> Phải bị lỗi 400/403.
- Test API Key: `curl -H "Authorization: Bearer invalid-key" https://ai-gateway.example.com/v1/completions` -> Phải trả về 401.
- Test Network Policy: Từ pod trong namespace khác, `curl ai-gateway-service:8443` -> Phải bị timeout hoặc connection refused.
- Test Root Escape: Chạy `kubectl exec -it -- /bin/bash` -> Thử lệnh `whoami` (phải là 1000) và `mount /` (phải bị lỗi Permission denied).
Điều hướng series:
Mục lục: Series: Series: Xây dựng nền tảng AI inference hiệu năng cao với vLLM, TensorRT-LLM và Kubernetes trên Proxmox
« Phần 8: Triển khai đa model và quản lý phiên bản với Model Registry
Phần 10: Troubleshooting nâng cao và tối ưu hóa chi phí vận hành »