Cấu hình JWT cho xác thực tập trung
Bước đầu tiên là thiết lập cơ chế xác thực dựa trên JSON Web Token (JWT) để bảo vệ gateway của OpenFaaS. Chúng ta sẽ sử dụng thư viện faas-cli để tạo cặp khóa bí mật (secret) và công khai (public) cần thiết cho việc ký và xác minh token.
Thực hiện lệnh sau để tạo file chứa key secret cho OpenFaaS:
faas-cli login --username admin --password your_secure_password
Lệnh này sẽ tạo file .faasrc và lưu token xác thực. Nếu bạn muốn cấu hình thủ công bằng file config YAML cho service, hãy tạo file secrets.yaml trong thư mục dự án của bạn.
Tạo file secrets.yaml với nội dung sau để định nghĩa secret chứa JWT key:
apiVersion: v1
kind: Secret
metadata:
name: faas-key
namespace: openfaas
type: Opaque
data:
key: c29tZS1zZWNyZXQta2V5LWZvci1qd3Q=
Chú ý: Giá trị key là base64 của chuỗi bí mật thực tế. Bạn cần tạo secret này trước khi áp dụng. Sau đó, áp dụng file này vào cluster:
kubectl apply -f secrets.yaml -n openfaas
Kết quả mong đợi: Kubernetes tạo resource Secret trong namespace openfaas chứa key dùng để ký JWT.
Cấu hình Gateway nhận JWT
Để gateway OpenFaaS bắt buộc yêu cầu JWT cho mọi request, bạn cần cập nhật giá trị environment variables trong deployment của gateway. Sửa file openfaas-gateway.yaml (hoặc dùng kubectl edit) để thêm biến basic_auth và cấu hình JWT.
Chỉnh sửa deployment gateway với nội dung sau:
apiVersion: apps/v1
kind: Deployment
metadata:
name: openfaas-gateway
namespace: openfaas
spec:
template:
spec:
containers:
- name: gateway
env:
- name: basic_auth
value: "true"
- name: function_creds_secret
value: "faas-key"
- name: jwt_secret
valueFrom:
secretKeyRef:
name: faas-key
key: key
Khởi động lại deployment để áp dụng thay đổi:
kubectl rollout restart deployment openfaas-gateway -n openfaas
Kết quả mong đợi: Gateway sẽ từ chối mọi request không có header Authorization: Bearer <token> hợp lệ.
Verify kết quả
Thử gọi API không có token để xác nhận bị chặn:
curl -v http://your-gateway-ip:8080/function/hello-world
Kết quả mong đợi: Trả về mã lỗi 401 Unauthorized.
Thử gọi API với token hợp lệ (giả sử bạn đã tạo token bằng thư viện JWT với secret đã lưu):
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" http://your-gateway-ip:8080/function/hello-world
Kết quả mong đợi: Trả về mã 200 OK và response của function.
Triển khai mTLS giữa Workers và OpenFaaS
Mutual TLS (mTLS) yêu cầu cả client (Cloudflare Workers) và server (OpenFaaS) phải xác thực lẫn nhau bằng chứng chỉ số. Điều này ngăn chặn các cuộc tấn công giả mạo (spoofing) ngay cả khi attacker biết được địa chỉ IP.
Tạo chứng chỉ CA và Server
Đầu tiên, tạo một Certificate Authority (CA) nội bộ để ký chứng chỉ cho OpenFaaS gateway. Tạo thư mục chứng chỉ và chạy lệnh OpenSSL:
mkdir -p /etc/ssl/private/openfaas && cd /etc/ssl/private/openfaas
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 365 -out ca.crt -subj "/CN=OpenFaaS-CA"
Tiếp theo, tạo chứng chỉ cho server (OpenFaaS gateway). Bạn cần tạo file config OpenSSL openssl.cnf trong thư mục hiện tại:
[req]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = v3_req
[dn]
CN = openfaas-gateway.internal
[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = openfaas-gateway
DNS.2 = openfaas-gateway.openfaas.svc.cluster.local
IP.1 = 10.96.100.1
Thay thế IP.1 bằng IP thực tế của service OpenFaaS gateway trong cluster của bạn. Sau đó tạo key và CSR cho server:
openssl req -new -key ca.key -out server.csr -subj "/CN=openfaas-gateway.internal"
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256 -extfile openssl.cnf -extensions v3_req
Kết quả mong đợi: Có 3 file trong thư mục: ca.crt, server.crt, server.key.
Triển khai chứng chỉ vào Kubernetes
Đưa các file chứng chỉ vào Kubernetes dưới dạng Secret để gateway sử dụng. Tạo file mtls-secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: openfaas-mtls
namespace: openfaas
type: kubernetes.io/tls
data:
tls.crt:
tls.key:
ca.crt:
Thay thế <BASE64_ENCODED...> bằng nội dung base64 của các file tương ứng. Sau đó áp dụng:
kubectl apply -f mtls-secret.yaml -n openfaas
Cập nhật deployment gateway để mount secret này và cấu hình HTTPS với client verification. Sửa openfaas-gateway.yaml:
spec:
template:
spec:
containers:
- name: gateway
ports:
- name: https
containerPort: 8080
volumeMounts:
- name: mtls-cert
mountPath: /certs
readOnly: true
env:
- name: TLS_CERT_FILE
value: /certs/tls.crt
- name: TLS_KEY_FILE
value: /certs/tls.key
- name: TLS_CA_FILE
value: /certs/ca.crt
- name: TLS_CLIENT_VERIFICATION
value: "require"
volumes:
- name: mtls-cert
secret:
secretName: openfaas-mtls
Khởi động lại gateway:
kubectl rollout restart deployment openfaas-gateway -n openfaas
Kết quả mong đợi: Gateway chỉ chấp nối HTTPS và yêu cầu client gửi chứng chỉ hợp lệ đã được ký bởi CA nội bộ.
Cấu hình Cloudflare Workers sử dụng mTLS
Trong Cloudflare Workers, bạn không thể mount chứng chỉ trực tiếp như Kubernetes. Thay vào đó, bạn cần nhúng chứng chỉ client (client.crt và client.key) vào code hoặc lưu trữ trong KV Storage và tải xuống tại runtime.
Tạo chứng chỉ client để Workers sử dụng (chạy trên máy local):
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj "/CN=Cloudflare-Worker-Client"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365 -sha256
Trong code Worker (file src/index.js), cấu hình fetch để gửi chứng chỉ client và xác minh CA của server:
const OPENFAAS_URL = "https://openfaas-gateway.internal:8080";
const CLIENT_CERT = `-----BEGIN CERTIFICATE-----
...nội dung client.crt...
-----END CERTIFICATE-----`;
const CLIENT_KEY = `-----BEGIN PRIVATE KEY-----
...nội dung client.key...
-----END PRIVATE KEY-----`;
const CA_CERT = `-----BEGIN CERTIFICATE-----
...nội dung ca.crt...
-----END CERTIFICATE-----`;
export default {
async fetch(request) {
const response = await fetch(OPENFAAS_URL + "/function/hello-world", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_JWT_TOKEN"
},
body: JSON.stringify({ name: "Alice" }),
// Cloudflare Workers hiện tại chưa hỗ trợ trực tiếp mTLS trong fetch options theo cách truyền thống.
// Cách tiếp cận thực tế là sử dụng proxy hoặc custom certificate authority.
// Tuy nhiên, để minh họa logic mTLS trong code:
// Bạn cần cấu hình custom TLS context nếu dùng environment variables hoặc KV.
});
return response;
}
};
Lưu ý: Cloudflare Workers chạy trên mạng Edge của Cloudflare, không có khả năng mount chứng chỉ client trực tiếp vào socket TCP như ứng dụng server thông thường. Để thực hiện mTLS từ Workers đến OpenFaaS, bạn cần cấu hình OpenFaaS để chấp nhận chứng chỉ đã được Cloudflare cung cấp (nếu dùng Cloudflare Tunnel) hoặc sử dụng một proxy trung gian (như Envoy Proxy) trong cluster Kubernetes để xử lý mTLS thay cho gateway.
Giải pháp thay thế khả thi hơn: Sử dụng Cloudflare Tunnel (cloudflared) để tạo tunnel mTLS từ Edge về Kubernetes, sau đó Workers gọi vào tunnel này.
docker run -d --name cloudflared --restart=always \
-v /etc/cloudflared:/etc/cloudflared \
cloudflare/cloudflared \
tunnel --no-autoupdate run \
--config /etc/cloudflared/config.yml \
my-openfaas-tunnel
Kết quả mong đợi: Cloudflare Workers có thể gọi vào OpenFaaS qua tunnel bảo mật, và mTLS được thiết lập giữa Cloudflare Edge và Kubernetes.
Verify kết quả
Thử gọi API từ Worker không qua tunnel hoặc không có chứng chỉ client hợp lệ:
curl -v --resolve openfaas-gateway.internal:443:YOUR_IP https://openfaas-gateway.internal/function/hello-world
Kết quả mong đợi: Kết nối bị từ chối (Connection refused) hoặc lỗi SSL handshake do không có client certificate.
Thử gọi qua tunnel Cloudflare (nếu đã setup):
curl -v https://my-openfaas-tunnel.trycloudflare.com/function/hello-world
Kết quả mong đợi: Kết nối thành công, mã 200 OK.
Cấu hình WAF trên Cloudflare để chặn attack
Web Application Firewall (WAF) của Cloudflare là lớp bảo vệ đầu tiên chặn các cuộc tấn công phổ biến như SQL Injection, XSS, và Brute Force trước khi request chạm đến hạ tầng Kubernetes.
Thiết lập Custom Rules
Truy cập vào dashboard Cloudflare, chọn domain của bạn, vào menu Security -> WAF -> Custom rules. Tạo rule mới để chặn các request có header đặc biệt của bot độc hại.
Tạo rule với logic sau (sử dụng Expression Language của Cloudflare):
if (http.user_agent contains "sqlmap" or http.user_agent contains "nikto") {
block;
}
Đặt tên rule là Block Known Bad Bots và set action là Block.
Tiếp theo, tạo rule để giới hạn tốc độ (Rate Limiting) cho các endpoint API nhạy cảm. Ví dụ chặn nếu một IP gửi quá 100 request trong 1 phút đến /function/:
if (http.request.uri.path starts with "/function/") {
if (cf.ip.country eq "CN") {
block;
}
}
// Rate Limit Rule
if (cf.ip.src ip in {1.2.3.4}) {
challenge;
}
Để áp dụng rate limiting chính xác hơn, sử dụng tính năng Rate Limiting trong Cloudflare:
Path: /function/*
Match: POST
Rate Limit: 100 requests per minute
Action: Block
Kết quả mong đợi: Cloudflare sẽ chặn các request không hợp lệ và trả về mã 429 Too Many Requests hoặc 403 Forbidden.
Cấu hình Ruleset cho OpenFaaS Gateway
Cloudflare cung cấp các managed rulesets (tập luật có sẵn) để bảo vệ các ứng dụng web phổ biến. Kích hoạt OWASP Core Rule Set cho domain của bạn.
Trong phần WAF -> Managed Rules, tìm OWASP ModSecurity Core Rule Set và bật nó lên. Chọn mức độ Recommended để cân bằng giữa bảo mật và tỷ lệ false positive.
Để bảo vệ cụ thể hơn cho OpenFaaS, tạo một Managed Rule mới để chặn các payload JSON chứa mã độc:
if (http.request.body contains "" or http.request.body contains "exec(") {
block;
}
Kết quả mong đợi: Các request chứa payload độc hại bị chặn ngay tại edge, không tiêu tốn tài nguyên Kubernetes.
Verify kết quả
Thử tấn công SQL Injection giả lập:
curl -X POST https://your-domain.com/function/test -d "{'name': \"' OR '1'='1\"}"
Kết quả mong đợi: Cloudflare trả về mã 403 với thông báo Access Denied hoặc WAF blocked this request.
Thử tấn công Brute Force (gửi nhiều request liên tiếp):
for i in {1..110}; do curl -s -o /dev/null -w "%{http_code}\n" https://your-domain.com/function/hello-world; done
Kết quả mong đợi: Các request sau request thứ 100 sẽ trả về mã 429.
Quản lý và luân chuyển Secrets trong Kubernetes và Cloudflare
Quản lý bí mật (Secrets) là yếu tố then chốt để bảo vệ thông tin nhạy cảm như API keys, database passwords, và encryption keys. Chúng ta sẽ sử dụng Sealed Secrets cho Kubernetes và Cloudflare KV cho Workers.
Sử dụng Sealed Secrets cho Kubernetes
Secrets thông thường trong Kubernetes có thể bị đọc nếu ai đó có quyền get secret. Sealed Secrets mã hóa secret bằng công khai key, chỉ có controller trong cluster mới giải mã được.
Triển khai Sealed Secrets controller:
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/latest/download/controller.yaml
Tạo secret thông thường và đóng gói (seal) nó:
kubectl create secret generic db-creds \
--from-literal=password="SuperSecretPassword123" \
--from-literal=host="postgres.internal" \
-n openfaas --dry-run=client -o yaml | \
kubeseal --format yaml > sealed-db-creds.yaml
Áp dụng file sealed secret:
kubectl apply -f sealed-db-creds.yaml
Kết quả mong đợi: Kubernetes tạo ra một resource SealedSecret. Controller sẽ tự động giải mã và tạo Secret tương ứng trong cluster.
Luân chuyển Secrets (Rotation)
Khi cần thay đổi secret (ví dụ đổi password), bạn chỉ cần cập nhật giá trị trong file YAML ban đầu, chạy lại lệnh kubeseal và áp dụng lại. Kubernetes sẽ tự động cập nhật secret cũ bằng secret mới.
kubectl create secret generic db-creds \
--from-literal=password="NewSuperSecretPassword456" \
-n openfaas --dry-run=client -o yaml | \
kubeseal --format yaml > sealed-db-creds-rotated.yaml
kubectl apply -f sealed-db-creds-rotated.yaml
Kết quả mong đợi: Ứng dụng đang chạy sẽ nhận được secret mới sau khi container khởi động lại (hoặc nếu sử dụng sidecar injector để watch secret).
Quản lý Secrets trong Cloudflare Workers
Với Cloudflare Workers, secrets được lưu trữ an toàn trên server của Cloudflare và được inject vào runtime dưới dạng environment variables. Bạn không thể đọc trực tiếp nội dung secret.
Đặt secret cho Worker sử dụng CLI:
wrangler secret put DB_PASSWORD --env production
Hệ thống sẽ yêu cầu nhập password. Sau khi nhập, secret được mã hóa và lưu trữ.
Để luân chuyển secret trong Workers, chỉ cần chạy lại lệnh put với giá trị mới:
wrangler secret put DB_PASSWORD --env production
Cập nhật Workers để áp dụng secret mới (tùy thuộc vào cách deploy, thường là deploy lại code hoặc wait cho propagation):
wrangler deploy
Kết quả mong đợi: Code Worker có thể truy cập secret qua env.DB_PASSWORD với giá trị mới nhất.
Verify kết quả
Kiểm tra secret trong Kubernetes:
kubectl get secret db-creds -n openfaas -o jsonpath='{.data.password}' | base64 -d
Kết quả mong đợi: In ra password mới (nếu đã rotate).
Kiểm tra secret trong Workers (không thể in trực tiếp nội dung, chỉ có thể kiểm tra biến):
echo $DB_PASSWORD
Trong môi trường production, bạn cần kiểm tra log của Worker để xem nó có truy cập đúng giá trị mới không.
Áp dụng nguyên tắc Least Privilege cho Service Accounts
Nguyên tắc Least Privilege (Quyền hạn tối thiểu) yêu cầu mỗi service account chỉ có quyền thực hiện những tác vụ cần thiết. Trong Kubernetes, điều này được thực hiện qua RBAC (Role-Based Access Control).
Tạo Service Account riêng cho OpenFaaS
Thay vì sử dụng default service account, hãy tạo một service account riêng cho OpenFaaS function với quyền hạn tối thiểu.
cat > openfaas-sa.yaml
Kết quả mong đợi: Service account openfaas-functions được tạo trong namespace openfaas.
Định nghĩa Role với quyền hạn tối thiểu
Tạo Role chỉ cho phép function đọc secret và ghi log, không cho phép tạo/xóa pod hay truy cập node.
cat > openfaas-role.yaml
Kết quả mong đợi: Role function-minimal-role được tạo với quyền hạn giới hạn.
Gán Role cho Service Account
Sử dụng RoleBinding để liên kết Role với Service Account.
cat > openfaas-rolebinding.yaml
Kết quả mong đợi: Service account openfaas-functions giờ có quyền thực hiện các action được định nghĩa trong function-minimal-role.
Áp dụng vào Deployment Function
Cập nhật deployment của function để sử dụng service account mới. Sửa file deployment của function (ví dụ hello-world-deploy.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
namespace: openfaas
spec:
template:
spec:
serviceAccountName: openfaas-functions
containers:
- name: hello-world
image: openfaas/hello-world:latest
Áp dụng lại deployment:
kubectl apply -f hello-world-deploy.yaml
Kết quả mong đợi: Pod chạy với service account openfaas-functions và chỉ có quyền truy cập secrets/configmaps, không thể thao tác các resource khác.
Verify kết quả
Thử thực hiện hành động vượt quyền (ví dụ tạo Pod mới) từ bên trong container function:
kubectl exec -it -n openfaas -- kubectl create pod test-pod
Kết quả mong đợi: Lệnh bị từ chối với thông báo Error from server (Forbidden): pods is forbidden.
Thử đọc secret (hành động được phép):
kubectl exec -it -n openfaas -- kubectl get secret db-creds -n openfaas -o jsonpath='{.data.password}' | base64 -d
Kết quả mong đợi: In ra nội dung secret thành công.
Điều hướng series:
Mục lục: Series: Series: Xây dựng nền tảng Serverless và Edge Computing an toàn với OpenFaaS, Cloudflare Workers và Wasm trên hạ tầng Kubernetes
« Phần 6: Thiết lập kiến trúc Hybrid: Kết nối Serverless và Edge
Phần 8: Giám sát, Logging và Tracing trong môi trường Hybrid »