Thứ Năm, 6 tháng 8, 2026

Nginx SNI

Nginx SNI
SNI chia làm 2 loại SNI server SNI Client

1. Nginx reject non-SNI server side
# Khối server mặc định để chặn mọi truy cập không khớp SNI,
yêu cầu phải gửi servername sni lên cùng
server {
    listen 443 default_server ssl;
    listen [::]:443 default_server ssl;

    # Từ chối bắt tay SSL ngay lập tức
    ssl_reject_handshake on;
}

# Cấu hình website hợp lệ của bạn
server {
    listen 443 ssl;
    server_name yourdomain.com;

    ssl_certificate     /path/to/cert.crt;
    ssl_certificate_key /path/to/cert.key;
    # ... cấu hình khác
}


2. SNI as client  side (forward proxy)
Mặc định, Nginx không tự động gửi SNI khi kết nối với Upstream.
Nếu máy chủ Upstream yêu cầu SNI để trả về chứng chỉ đúng,
bạn bắt buộc phải bật cấu hình Client-side SNI thông qua các
chỉ thị proxy_ssl_server_name proxy_ssl_name
server {
    listen 443 ssl;
    server_name proxy.example.com;

    ssl_certificate /etc/ssl/certs/proxy.crt;
    ssl_certificate_key /etc/ssl/certs/proxy.key;

    location / {
        # 1. Chuyển tiếp request đến upstream qua HTTPS
        proxy_pass https://backend_server;

        # 2. BẬT Client-side SNI (Mặc định là off)
        proxy_ssl_server_name on;

        # 3. Định nghĩa tên miền sẽ gửi trong TLS Handshake đến Upstream
        # Thường sử dụng biến $host (tên miền client gửi lên) hoặc một chuỗi cố định như 'backend.com'
        proxy_ssl_name $host;

        # (Tùy chọn) Đảm bảo Header Host của HTTP cũng trùng khớp với SNI
        proxy_set_header Host $host;
    }
}

TLS Handshake Flow with SNI
 




Thứ Tư, 29 tháng 4, 2026

GatewayAPI collection

https://oneuptime.com/blog/tag/gateway-api?page=4&pageSize=25 
Contents
 
GatewayAPI 2
001. GatewayAPI - 1.Cài đặt bản Standard 2
001. GatewayAPI - 1.Cài đặt bản Experimeltal 2
001. GatewayAPI - nginx từ HELM 3
001. Tạo GatewayClass 3
002. ingress2gateway 4
003. Tạo pod mẫu để test 4
TESTED-0: Create Gateway mới 4
TESTED-1 HttpRoute basic 5
TESTED-2: Tích hợp certmanager 5
TESTED-3: Multi Hostname và ssl - Basic 7
TESTED-4: ListenerSet 8
TESTED-5: Traffic Split 11
TESTED-6: Header Route 12
TESTED-7.1: Header Modify 13
TESTED-8: Method+Path route 15
TESTED-9: Path route only 16
TESTED-10 Method Route only 17
TESTED-11: Query Parameter Route 18
TESTED-12: URL rewrite 19
TESTED-13: Mirror request 20
TESTED-14 ReferenceGrant 21
TESTED-14.1: HttpRoute->Services khác namespace 21
TESTED-14.2: Gateway->Secret khác namespace 23
OK-15: ListenerSet->Secret 24
ReferenceGrant - Các ví dụ khác 25
TEST CHƯA OK-15: Increase timeout 25
TESTED-18: Redirect 301/302 26
TESTED-19: TLS Passthought 27
TESTED-20: TCP/UDP Route 29
TESTED-21: BackendTLSPolicy 30
22: CORS 32
(NOT)Ví dụ 26-A: mTLS Frontend 32
(NOT)Ví dụ 26-B: mTLS Backend 32
(NOT)Ví dụ 27: HTTP2.0 Support Backend 32
TESTED-31: basic authen 33
Nginx GW Fabric Advance 35
????-32: SnippetsFilter + SnipetsPolicies 35
ClientSettingsPolicy 38
UpstreamSettingsPolicy 38
Session-persistence 38
Authenticationfilters 38
Nginxgateways 38
nginxproxies 38
observabilitypolicies 38
proxysettingspolicies 38
ratelimitpolicies 38
snippetsfilters 38
snippetpolicies_v2 39
upstreamsettingspolicies 39
Kiến trúc GWAPI 39
Security cho GatewayAPI 40
1. Giới hạn NS cho GW và httpRoute 40



GatewayAPI
001. GatewayAPI - 1.Cài đặt bản Standard
Tham khảo trong file cilium đã viết để cài đặt
Toàn bộ tài liệu https://gateway-api.sigs.k8s.io/guides/getting-started/
https://docs.nginx.com/nginx-gateway-fabric/get-started/#install-the-helm-chart 
Kiểm tra bản mới nhất ở link này: https://gateway-api.sigs.k8s.io/guides/getting-started/introduction/ 
Bước 1: Cài CRD
wget https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml 
k apply -f standard-install.yaml

Bước 2: Cài gatewayclass: nginx
Bản mới nhất ở đây https://docs.nginx.com/nginx-gateway-fabric/install/helm/#installing-the-gateway-api-resources

Kiểm tra độ tương thích trước khi cài version: https://github.com/nginx/nginx-gateway-fabric#technical-specifications 
helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
  --namespace nginx-gateway \
  --create-namespace \
  --version 2.6.2 \
  --wait

cat <<EOF > gatewayclass.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: nginx
spec:
  controllerName: gateway.nginx.org/nginx-gateway-controller
EOF

k apply -f gatewayclass.yaml
k get gatewayclasses.gateway.networking.k8s.io

001. GatewayAPI - 1.Cài đặt bản Experimeltal
Bước 1: Cài CRD với tính năng Experimental, thực chất bước này không cần cài nữa
Tìm bản mới nhất trên này https://gateway-api.sigs.k8s.io/guides/getting-started/introduction/  và trên này https://github.com/kubernetes-sigs/gateway-api/releases 
(ko cần cài, làm luôn bước 2)wget https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/experimental-install.yaml 
(ko cần cài, làm luôn bước 2)k apply --server-side -f experimental-install.yaml

Bước 2: Cài Nginx gateway Fabric từ link
Bản cài chính thức, đã test: https://docs.nginx.com/nginx-gateway-fabric/install/manifests/open-source-experimental/ 
Link git của nó: https://github.com/nginx/nginx-gateway-fabric/tree/main/config/crd/gateway-api 
kubectl kustomize "https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/experimental?ref=v2.6.7" | kubectl apply --server-side -f –

nếu gặp lỗi thì hãy xóa
kubectl delete crd tcproutes.gateway.networking.k8s.io
kubectl delete crd udproutes.gateway.networking.k8s.io

backendtlspolicies.gateway.networking.k8s.io 
gatewayclasses.gateway.networking.k8s.io 
gateways.gateway.networking.k8s.io 
grpcroutes.gateway.networking.k8s.
httproutes.gateway.networking.k8s.
listenersets.gateway.networking.k8s.io 
referencegrants.gateway.networking.k8s.io 
tcproutes.gateway.networking.k8s.io 
tlsroutes.gateway.networking.k8s.io 
udproutes.gateway.networking.k8s.
xbackendtrafficpolicies.gateway.networking.x-k8s.io d
xmeshes.gateway.networking.x-k8s.io 

Bước 3: Cài bổ xung CRD nâng cao rành riêng cho Nginx fabric 
https://docs.nginx.com/nginx-gateway-fabric/install/manifests/open-source-experimental/#deploy-the-custom-resource-definitions 
kubectl apply --server-side -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v2.6.7/deploy/crds.yaml
authenticationfilters.gateway.nginx.org 
clientsettingspolicies.gateway.nginx.org 
nginxgateways.gateway.nginx.org 
nginxproxies.gateway.nginx.org serverside-applied
observabilitypolicies.gateway.nginx.org serverside-applied
proxysettingspolicies.gateway.nginx.org serverside-applied
ratelimitpolicies.gateway.nginx.org serverside-applied
snippetsfilters.gateway.nginx.org serverside-applied
snippetspolicies.gateway.nginx.org serverside-applied
upstreamsettingspolicies.gateway.nginx.org serverside-applied
wafpolicies.gateway.nginx.org serverside-applied

Bước 4: Cài đặt deployment
wget  https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v2.6.7/deploy/experimental/deploy.yaml
NOTE1: vim deploy.yaml, dòng cuối
# NHỚ ĐỔI TỪ LOCAL-> CLUSTER cho svc, để vào được web
externalTrafficPolicy: Cluster

k apply -f deploy.yaml


NOTE2: muốn bật snippets ta phải sửa thêm 3 chỗ là  RBAC và sửa deployment
Xem file mẫu, không apply https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/main/deploy/snippets/deploy.yaml 
229,230d211
<   - snippetsfilters
<   - snippetspolicies
245,246d225
<   - snippetsfilters/status
<   - snippetspolicies/status


      containers:
      - args:
        - controller
        - --gateway-ctlr-name=gateway.nginx.org/nginx-gateway-controller
        ...
        - --leader-election-lock-name=nginx-gateway-leader-election
        - --snippets



001. GatewayAPI - nginx từ HELM
Bản mới nhất ở đây https://docs.nginx.com/nginx-gateway-fabric/install/helm/#installing-the-gateway-api-resources
Kiểm tra phiên bản: https://github.com/nginx/nginx-gateway-fabric/pkgs/container/charts%2Fnginx-gateway-fabric/versions?filters%5Bversion_type%5D=tagged 
Kiểm tra độ tương thích trước khi cài version: https://github.com/nginx/nginx-gateway-fabric#technical-specifications 
helm pull oci://ghcr.io/nginx/charts/nginx-gateway-fabric --version 0.0.0-edge
tar –xvzf 
cd nginx-gateway-fabric
helm install ngf . \
  --namespace nginx-gateway \
  --create-namespace \
  --wait
001. Tạo GatewayClass
cat <<EOF > gatewayclass.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: nginx
spec:
  controllerName: gateway.nginx.org/nginx-gateway-controller
EOF

k apply -f gatewayclass.yaml
k get gatewayclasses.gateway.networking.k8s.io

Để xem GatewayAPI hỗ trợ những chức năng nào, ta gõ như sau
# k get gatewayclasses.gateway.networking.k8s.io nginx -o yaml
 

002. ingress2gateway
wget https://github.com/kubernetes-sigs/ingress2gateway/releases/download/v1.0.0/ingress2gateway_Linux_x86_64.tar.gz 
ingress2gateway print --providers=ingress-nginx --all-namespaces > gateway-api-manifests.yaml 
ingress2gateway print --providers=ingress-nginx --input-file=./ingress1.yaml

003. Tạo pod mẫu để test
k create ns app-namespace1
k create ns app-namespace2
k -n app-namespace1 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace1 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace1 create deployment web1a --image=traefik/whoami --replicas=1
k -n app-namespace1 expose deployment web1a --name=svc-web1a --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace1 create deployment web1b --image=traefik/whoami --replicas=1
k -n app-namespace1 expose deployment web1b --name=svc-web1b --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace2 create deployment web2 --image=traefik/whoami --replicas=1
k -n app-namespace2 expose deployment web2 --name=svc-web2 --port=80 --target-port=80 --type=ClusterIP

TESTED-0: Create Gateway mới
https://gateway-api.sigs.k8s.io/guides/getting-started/simple-gateway/
***Chú ý: có thể tạo nhiều gateway, mỗi gw sẽ có 1 ip LB riêng

k create ns infra-gateway01

openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout tls.key   -out tls.crt   -subj "/CN=HELLO-WORLD-gateway/O=HELLO-WORLDe"
kubectl -n infra-gateway01 create secret tls default-cert --key tls.key   --cert tls.crt 

cat << EOF > 01.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
  namespace: infra-gateway01
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: default-cert #chú ý phải có tạo secret ở trên
    allowedRoutes:
      namespaces:
        from: All
EOF

k apply -f 01.simple-gateway.yaml

TESTED-1 HttpRoute basic
cat << EOF > 01.simple-httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app-http
  namespace: app-namespace1
spec:
  parentRefs:
  - name: my-gateway #chú ý trùng tên gateway
    namespace: infra-gateway01
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /v1/api  #có thể để thành / nếu muốn route all traffic.
    backendRefs:
    - name: svc-web1 #chú ý trùng tên svc
      port: 80
EOF

k apply -f 01.simple-httproute.yaml

curl -v http://test.tuan.name.vn/v1/api
curl -vk https://test.tuan.name.vn/v1/api 


TESTED-2: Tích hợp certmanager
Xem mục chính CertManager, cài như bình thường
https://freedium-mirror.cfd/https://faun.pub/kubernetes-gateway-api-a-complete-step-by-step-setup-guide-397d0ff5375f 
https://docs.nginx.com/nginx-gateway-fabric/traffic-security/integrate-cert-manager/ 
*** Chú ý Tuấn: ở đây ta phải tạo Certificate.yaml mới, sau đó mới add vào gateway
cat << EOF > 02.certmanager-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: test-tuan-name-vn-tls
  namespace: nginx-gateway
spec:
  secretName: test-tuan-name-vn-tls-secret
  duration: 2160h # 90 ngày
  renewBefore: 360h # Tự Gia hạn trước khi hết hạn 15 ngày (360 giờ)
  issuerRef:
    name: letsencrypt-stag
    kind: ClusterIssuer
  commonName: test.tuan.name.vn
  dnsNames: #có hỗ trợ multi ssl trên cùng 1 ssl file
  - test.tuan.name.vn
EOF


cat << EOF > 02.certmanager-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
  namespace: nginx-gateway
  annotations:
    # Tùy chọn: Một số controller dùng annotation này để tự động map cert
    cert-manager.io/cluster-issuer: letsencrypt-stag
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: default-cert
    allowedRoutes:
      namespaces:
        from: All
  - name: https-test-tuan-name-vn
    protocol: HTTPS
    port: 443
    hostname: "test.tuan.name.vn"
    tls:
      mode: Terminate
      certificateRefs:
      - name: test-tuan-name-vn-tls-secret
    allowedRoutes:
      namespaces:
        from: All
EOF

cat << EOF > 02.certmanager-httproute.yaml
# HTTP
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app-web1-http-redirect
  namespace: app-namespace1
spec:
  parentRefs:
  - name: my-gateway #chú ý trùng tên gateway
    namespace: nginx-gateway
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 302 # Chuyển hướng tạm thời 302 sang 443
---
# HTTPS
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app-web1-https-route
  namespace: app-namespace1
spec:
  parentRefs:
  - name:  my-gateway
    namespace: nginx-gateway
    sectionName: https-test-tuan-name-vn # Khớp với 'name' của listener 443 trong Gateway
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: svc-web1 #chú ý trùng tên svc
      port: 80
EOF
Kết quả:
curl -v http://test.tuan.name.vn
#< HTTP/1.1 302 Moved Temporarily
#< Location: https://test.tuan.name.vn/

curl -v https://test.tuan.name.vn
#*  subject: CN=test.tuan.name.vn
#*  start date: May  1 16:43:03 2026 GMT
#*  expire date: Jul 30 16:43:02 2026 GMT
#*  issuer: C=US; O=(STAGING) Let's Encrypt; CN=(STAGING) Tenuous Tomato R13



TESTED-3: Multi Hostname và ssl - Basic
k create ns infra-gateway03
k create ns app-namespace1
k create ns app-namespace2

k -n infra-gateway03 delete secret default-cert-domain1
k -n infra-gateway03 delete secret default-cert-domain2
k -n infra-gateway03 delete secret default-cert

openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout tls1.key   -out tls1.crt   -subj "/CN=*.domain1.com/O=Default Certificate"
kubectl create secret tls default-cert-domain1 --key tls1.key   --cert tls1.crt   -n infra-gateway03

openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout tls2.key   -out tls2.crt   -subj "/CN=*.domain2.com/O=Default Certificate"
kubectl create secret tls default-cert-domain2 --key tls2.key   --cert tls2.crt   -n infra-gateway03

openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout tls.key   -out tls.crt   -subj "/CN=default-gateway/O=Default Certificate"
kubectl create secret tls default-cert --key tls.key   --cert tls.crt   -n infra-gateway03



cat << EOF > 03.multi-wildcard.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: wildcard-gateway
  namespace: infra-gateway03
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80 # Đây là default
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    protocol: HTTPS
    port: 443 # Đây là default
    tls:
      mode: Terminate
      certificateRefs:
      - name: default-cert
    allowedRoutes:
      namespaces:
        from: All
  - name: https-wildcard-domain1
    protocol: HTTPS
    port: 443
    hostname: "*.domain1.com"
    tls:
      mode: Terminate
      certificateRefs:
      - name: default-cert-domain1
    allowedRoutes:
      namespaces:
        from: All
  - name: https-wildcard-domain2
    protocol: HTTPS
    port: 443
    hostname: "*.domain2.com"
    tls:
      mode: Terminate
      certificateRefs:
      - name: default-cert-domain2
    allowedRoutes:
      namespaces:
        from: All
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app1-domain1-route
  namespace: app-namespace1
spec:
  parentRefs:
  - name: wildcard-gateway
    namespace: infra-gateway03
    sectionName: https-wildcard-domain1 # Gắn đúng vào listener của domain1
  hostnames:
  - "app1.domain1.com" # Chỉ định subdomain cụ thể
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: svc-web1
      port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app22-domain1-route
  namespace: app-namespace2
spec:
  parentRefs:
  - name: wildcard-gateway
    namespace: infra-gateway03
    sectionName: https-wildcard-domain2 # Gắn đúng vào listener của domain1
  hostnames:
  - "app2.domain2.com" # Chỉ định subdomain cụ thể
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: svc-web2
      port: 80
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k apply -f 03.multi-wildcard.yaml



curl --resolve app1.domain1.com:443:192.168.88.151 -vk https://app1.domain1.com
*  subject: CN=*.domain1.com; O=Default Certificate

curl --resolve app2.domain2.com:443:192.168.88.151 -vk https://app2.domain2.com
*  subject: CN=*.domain2.com; O=Default Certificate




TESTED-4: ListenerSet
https://gateway-api.sigs.k8s.io/guides/user-guides/listener-set/ 
Cách tiếp cận này giúp bạn giải quyết 2 vấn đề lớn:
Phân quyền (Self-service): Đội Platform chỉ cần quản lý 1 Gateway dùng chung. Từng đội phát triển ứng dụng ở các namespace khác nhau tự tạo ListenerSet để cài đặt domain và SSL của riêng họ.
Vượt giới hạn: Giúp cluster phá vỡ giới hạn cứng 64 listeners trên một Gateway duy nhất của Kubernetes.
 


k delete ns team-1-ns ; k create ns team-1-ns
k delete ns team-2-ns ; k create ns team-2-ns
k delete ns infra-gateway04 ; k create ns infra-gateway04

kubectl create deployment team-1-app -n team-1-ns --image=traefik/whoami --port=80
kubectl expose deployment team-1-app -n team-1-ns --name=team-1-service --port=80 --target-port=80

kubectl create deployment team-2-app -n team-2-ns --image=traefik/whoami --port=80
kubectl expose deployment team-2-app -n team-2-ns --name=team-2-service --port=80 --target-port=80

openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout tls3.key   -out tls3.crt   -subj "/CN=*.first.foo.com/O=Default Certificate"
kubectl create secret tls first-workload-cert --key tls3.key   --cert tls3.crt  -n team-1-ns

openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout tls4.key   -out tls4.crt   -subj "/CN=*.second.foo.com/O=Default Certificate"
kubectl create secret tls second-workload-cert --key tls4.key   --cert tls4.crt  -n team-2-ns

cat << EOF > 04.listerner-set.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: shared-gateway
  namespace: infra-gateway04
spec:
  gatewayClassName: nginx
  allowedListeners:
    namespaces:
      from: All
  listeners:
  - name: foo
    hostname: foo.com
    protocol: HTTP
    port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
  name: first-workload-listeners
  namespace: team-1-ns
spec:
  parentRef:
    namespace: infra-gateway04
    name: shared-gateway
    kind: Gateway
    group: gateway.networking.k8s.io
  listeners:
  - name: first
    hostname: "*.first.foo.com"
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        group: ""
        name: first-workload-cert
---
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
  name: second-workload-listeners
  namespace: team-2-ns
spec:
  parentRef:
    namespace: infra-gateway04
    name: shared-gateway
    kind: Gateway
    group: gateway.networking.k8s.io
  listeners:
  - name: second
    hostname: "*.second.foo.com"
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        group: ""
        name: second-workload-cert
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k apply -f 04.listerner-set.yaml
sleep 5
k get gateway -A
k get listenersets.gateway.networking.k8s.io –A
k get svc –A

cat << EOF > 041.httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: team-1-route
  namespace: team-1-ns # Đặt cùng namespace với ListenerSet của Team 1
spec:
  parentRefs:
  - group: gateway.networking.k8s.io
    kind: ListenerSet # <--- Bắt buộc chỉ định là ListenerSet thay vì Gateway
    name: first-workload-listeners # Tên của ListenerSet tương ứng
    sectionName: first # Tên listener bên trong ListenerSet đó
  hostnames:
  - "*.first.foo.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: team-1-service # Service backend nằm trong team-1-ns
      port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: team-2-route
  namespace: team-2-ns # Đặt cùng namespace với ListenerSet của Team 2
spec:
  parentRefs:
  - group: gateway.networking.k8s.io
    kind: ListenerSet # <--- Chỉ định ListenerSet làm cha
    name: second-workload-listeners
    sectionName: second
  hostnames:
  - "*.second.foo.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: team-2-service # Service backend nằm trong team-2-ns
      port: 80
EOF

k apply -f 041.httproute.yaml

curl -vk --resolve test.first.foo.com:443:192.168.88.152 https://test.first.foo.com
*  issuer: CN=*.first.foo.com; O=Default Certificate

curl -vk --resolve test.second.foo.com:443:192.168.88.152 https://test.second.foo.com  
*  issuer: CN=*.second.foo.com; O=Default Certificate

Xóa rác sau khi test
k delete ns infra-gateway ; k delete ns team-1-ns ; k delete ns team-2-ns


TESTED-5: Traffic Split
https://gateway-api.sigs.k8s.io/guides/traffic-splitting/ 
k create ns app-namespace05
k -n app-namespace05 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace05 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace05 create deployment web1a --image=traefik/whoami --replicas=1
k -n app-namespace05 expose deployment web1a --name=svc-web1a --port=80 --target-port=80 --type=ClusterIP


cat << EOF > 05.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway05
  namespace: infra-gateway05
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF

k create ns infra-gateway05
k apply -f 05.simple-gateway.yaml
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung


cat << EOF > 05.traffic-splitting-httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: demo-route-split
  namespace: app-namespace05
spec:
  parentRefs:
  - name: my-gateway05 #chú ý trùng tên gateway
    namespace: infra-gateway05
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /test5
    backendRefs:
    - name: svc-web1  #đây là svc1 của pod1
      port: 80
      weight: 75
    - name: svc-web1a  #đây là svc2 của pod1
      port: 80
      weight: 25
EOF

k create ns app-namespace05
k apply -f 05.traffic-splitting-httproute.yaml

curl -vk --resolve test.tuan.name.vn:80:192.168.88.153 http://test.tuan.name.vn/test5

# Run multiple requests
for i in {1..20}; do
  curl -s --resolve test.tuan.name.vn:80:192.168.88.153 http://test.tuan.name.vn/test5| grep Hostname;
done

nên ưu tiên chia traffic như tỉ lệ sau
 

TESTED-6: Header Route
https://gateway-api.sigs.k8s.io/guides/traffic-splitting/#canary-traffic-rollout 
k create ns app-namespace06
k -n app-namespace06 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace06 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace06 create deployment web1a --image=traefik/whoami --replicas=1
k -n app-namespace06 expose deployment web1a --name=svc-web1a --port=80 --target-port=80 --type=ClusterIP


cat << EOF > 06.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway06
  namespace: infra-gateway06
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k create ns infra-gateway06
k apply -f 06.simple-gateway.yaml

cat << EOF > 06.traffic-splitting-header-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: demo-route-headers
  namespace: app-namespace06
spec:
  parentRefs:
  - name: my-gateway06 #chú ý trùng tên gateway
    namespace: infra-gateway06
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /test6
      headers:
      - name: version #vị trí header nằm ở đây version=v2
        value: v2
    backendRefs:
    - name: svc-web1a
      port: 80
  - matches:
    - path:
        type: PathPrefix
        value: /test6
    backendRefs:
    - name: svc-web1
      port: 80
EOF

k create ns app-namespace06
k apply -f 06.traffic-splitting-header-route.yaml

# Default request goes to v1
curl --resolve test.tuan.name.vn:80:192.168.88.154 http://test.tuan.name.vn/test6
Hostname: web1-888886b4d-tg4jv
# Request with header goes to v2
curl -H "version: v2" --resolve test.tuan.name.vn:80:192.168.88.154 http://test.tuan.name.vn/test6
Hostname: web1-888886b4d-t6rbg

Kết quả cho ta thấy khi thêm Header thì sẽ route sang 1 pod khác


Ví dụ khác về header route #tham khảo, chưa test
https://oneuptime.com/blog/post/2026-02-09-httproute-traffic-routing/view 
# httproute-headers.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: header-routing
  namespace: default
spec:
  parentRefs:
    - name: http-gateway
  hostnames:
    - "example.com"
  rules:
    # Route mobile users to mobile backend
    - matches:
        - headers:
            - name: User-Agent
              type: RegularExpression
              value: ".*(Mobile|Android|iPhone).*"
      backendRefs:
        - name: mobile-service
          port: 8080

    # Route beta users to canary backend
    - matches:
        - headers:
            - name: X-Beta-User
              type: Exact
              value: "true"
      backendRefs:
        - name: canary-service
          port: 8080

    # Default backend
    - matches:
        - path:
            type: PathPrefix
            value: "/"
      backendRefs:
        - name: stable-service
          port: 8080


TESTED-7.1: Header Modify
https://gateway-api.sigs.k8s.io/guides/http-header-modifier/ 
k create ns app-namespace07
k -n app-namespace07 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace07 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace07 create deployment web1a --image=traefik/whoami --replicas=1
k -n app-namespace07 expose deployment web1a --name=svc-web1a --port=80 --target-port=80 --type=ClusterIP


cat << EOF > 07.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway07
  namespace: infra-gateway07
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k create ns infra-gateway07
k apply -f 07.simple-gateway.yaml


cat << EOF > 07.http-header-modifier.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: header-manipulation-route
  namespace: app-namespace07 # Namespace chứa ứng dụng của bạn
spec:
  parentRefs:
  - name: my-gateway07 #chú ý trùng tên gateway
    namespace: infra-gateway07
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /test7
    # 🛠️ CẤU HÌNH THAO TÁC VỚI HEADER NẰM Ở ĐÂY
    filters:
    # 1. Thao tác với REQUEST HEADERS (Gửi từ Client -> Backend)
    - type: RequestHeaderModifier
      requestHeaderModifier:
        # Thêm header mới (Nếu đã tồn tại sẽ bị ghi đè)
        set:
        - name: X-Environment-Type
          value: "Production"
        # Cộng dồn thêm giá trị vào header đã có
        add:
        - name: X-Forwarded-For-Custom
          value: "nginx-fabric-gateway"
        # Xóa bỏ header nhạy cảm trước khi đẩy vào Backend
        remove:
        - "X-Internal-Secret"
        - "Authorization-Debug"
    # 2. Thao tác với RESPONSE HEADERS (Trả từ Backend -> Client)
    - type: ResponseHeaderModifier
      responseHeaderModifier:
        # Thêm header chuẩn bảo mật cho Client
        set:
        - name: Strict-Transport-Security
          value: "max-age=999999; includeSubDomains"
        - name: X-Frame-Options
          value: "DENY"
        # Thêm thông tin định danh hệ thống
        add:
        - name: Server-Trace
          value: "gateway-node-01xxxx"
        # Ẩn bớt các header lộ thông tin hệ thống backend
        remove:
        - "X-Powered-By"
        - "X-AspNet-Version"
    backendRefs:
    - name: svc-web1
      port: 80
EOF

k apply -f 07.http-header-modifier.yaml


curl --resolve test.tuan.name.vn:80:192.168.88.150 -v http://test.tuan.name.vn/test7
< Server-Trace: gateway-node-01xxxx
< Strict-Transport-Security: max-age=999999; includeSubDomains
#Header resposne mới đã được thêm vào.


TESTED-8: Method+Path route 

https://gateway-api.sigs.k8s.io/guides/http-method-matching/
A POST request to /v8/api will be routed to infra-backend-v1.
A GET request to /v8/api will be routed to infra-backend-v2.

k create ns app-namespace08
k -n app-namespace08 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace08 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace08 create deployment web1a --image=traefik/whoami --replicas=1
k -n app-namespace08 expose deployment web1a --name=svc-web1a --port=80 --target-port=80 --type=ClusterIP


cat << EOF > 08.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway08
  namespace: infra-gateway08
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k create ns infra-gateway08
k apply -f 08.simple-gateway.yaml


cat << EOF > 08.http-method-matching.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: method-and-path-matching
  namespace: app-namespace08
spec:
  parentRefs:
  - name: my-gateway08
    namespace: infra-gateway08
    sectionName: http
  hostnames:
  - "test.tuan.name.vn"
  rules:
  # Quy tắc 1: Phải là POST VÀ đường dẫn bắt đầu bằng /v8/api
  - matches:
    - path:
        type: PathPrefix
        value: /v8/api
      method: POST
    backendRefs:
    - name: svc-web1
      port: 80

  # Quy tắc 2: Phải là GET VÀ đường dẫn bắt đầu bằng /v8/api
  - matches:
    - path:
        type: PathPrefix
        value: /v8/api
      method: GET
    backendRefs:
    - name: svc-web1a
      port: 80
EOF

k apply -f 08.http-method-matching.yaml
Kiểm tra
curl --resolve test.tuan.name.vn:80:192.168.88.151 -v -XGET test.tuan.name.vn/v8/api
Hostname: web1a-d5f6f44bf-nzl4d

curl --resolve test.tuan.name.vn:80:192.168.88.151 -v -XPOST test.tuan.name.vn/v8/api
Hostname: web1-84c9884bbb-7mmb8

k delete -f 08.http-method-matching.yaml
k delete ns app-namespace08
k delete ns infra-gateway08


TESTED-9: Path route only


k create ns app-namespace09
k -n app-namespace09 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace09 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace09 create deployment web1a --image=traefik/whoami --replicas=1
k -n app-namespace09 expose deployment web1a --name=svc-web1a --port=80 --target-port=80 --type=ClusterIP

cat << EOF > 09.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway09
  namespace: infra-gateway09
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k create ns infra-gateway09
k apply -f 09.simple-gateway.yaml


cat << EOF > 09.path-route-only.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: demo-route-paths
  namespace: app-namespace09 # Namespace chứa ứng dụng của bạn
spec:
  parentRefs:
  - name: my-gateway09 #chú ý trùng tên gateway
    namespace: infra-gateway09
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /v1a
    backendRefs:
    - name: svc-web1a
      port: 80
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: svc-web1
      port: 80
EOF

k apply -f 09.path-route-only.yaml
Kiểm tra
curl --resolve test.tuan.name.vn:80:192.168.88.150 -v test.tuan.name.vn
curl --resolve test.tuan.name.vn:80:192.168.88.150 -v test.tuan.name.vn/v1a

k delete -f 09.path-route-only.yaml
k delete ns app-namespace09
k delete ns infra-gateway09

TESTED-10 Method Route only

k create ns app-namespace10
k -n app-namespace10 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace10 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace10 create deployment web1a --image=traefik/whoami --replicas=1
k -n app-namespace10 expose deployment web1a --name=svc-web1a --port=80 --target-port=80 --type=ClusterIP

cat << EOF > 10.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway10
  namespace: infra-gateway10
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k create ns infra-gateway10
k apply -f 10.simple-gateway.yaml




cat << EOF > 10.method-route-only.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: method-matching
  namespace: app-namespace10 # Namespace chứa ứng dụng của bạn
spec:
  parentRefs:
  - name: my-gateway10 #chú ý trùng tên gateway
    namespace: infra-gateway10
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - matches:
    - method: POST
    backendRefs:
    - name: svc-web1
      port: 80
  - matches:
    - method: GET
    backendRefs:
    - name: svc-web1a
      port: 80
EOF

k apply -f 10.method-route-only.yaml

curl -XPOST --resolve test.tuan.name.vn:80:192.168.88.150 -v test.tuan.name.vn
Hostname: web1-84c9884bbb-75lgc
curl -XGET --resolve test.tuan.name.vn:80:192.168.88.150 -v test.tuan.name.vn/v1a
Hostname: web1a-d5f6f44bf-dkl6x

k delete -f 10.method-route-only.yaml
k delete ns app-namespace10
k delete ns infra-gateway10




TESTED-11: Query Parameter Route
https://gateway-api.sigs.k8s.io/guides/http-query-param-matching/ 
k create ns app-namespace11
k -n app-namespace11 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace11 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace11 create deployment web1a --image=traefik/whoami --replicas=1
k -n app-namespace11 expose deployment web1a --name=svc-web1a --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace11 create deployment web1b --image=traefik/whoami --replicas=1
k -n app-namespace11 expose deployment web1b --name=svc-web1b --port=80 --target-port=80 --type=ClusterIP

cat << EOF > 11.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway11
  namespace: infra-gateway11
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k create ns infra-gateway11
k apply -f 11.simple-gateway.yaml



cat << EOF > 11.httproute-query-params.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: query-routing
  namespace: app-namespace11 # Namespace chứa ứng dụng của bạn
spec:
  parentRefs:
  - name: my-gateway11 #chú ý trùng tên gateway
    namespace: infra-gateway11
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn"
  rules:
    # Route debug requests to debug backend
    - matches:
        - queryParams:
            - name: debug
              type: Exact
              value: "true"
      backendRefs:
        - name: svc-web1a
          port: 80

    # Route specific API versions
    - matches:
        - queryParams:
            - name: api_version
              type: Exact
              value: "2.0"
      backendRefs:
        - name: svc-web1b
          port: 80

    # Default routing
    - backendRefs:
        - name: svc-web1
          port: 80

EOF

k apply -f 11.httproute-query-params.yaml
Kiểm tra
Nguyên lý
grep -r 'api_version' /etc/nginx/conf.d/matches.json
{"1_0":[{"redirectPath":"/_ngf-internal-rule0-route0","params":["debug=Exact=true"]},{"redirectPath":"/_ngf-internal-rule0-route1","params":["api_version=Exact=2.0"]},{"redirectPath":"/_ngf-internal-rule0-route2","any":true}]}

curl --resolve test.tuan.name.vn:80:192.168.88.150 test.tuan.name.vn/v1a?debug=true
curl --resolve test.tuan.name.vn:80:192.168.88.150 test.tuan.name.vn/v1a?debug=api_version=2.0

k delete -f 11.httproute-query-params.yaml
k delete ns app-namespace11
k delete ns infra-gateway11


TESTED-12: URL rewrite
k create ns app-namespace12
k -n app-namespace12 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace12 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace12 create deployment web1a --image=traefik/whoami --replicas=1
k -n app-namespace12 expose deployment web1a --name=svc-web1a --port=80 --target-port=80 --type=ClusterIP

cat << EOF > 12.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway12
  namespace: infra-gateway12
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k create ns infra-gateway12
k apply -f 12.simple-gateway.yaml



cat << EOF > 12.httproute-url-rewrite.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: url-rewrite
  namespace: app-namespace12 # Namespace chứa ứng dụng của bạn
spec:
  parentRefs:
  - name: my-gateway12 #chú ý trùng tên gateway
    namespace: infra-gateway12
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn"
  rules:
    # Rewrite /v1/api/* to /api/*
    - matches:
        - path:
            type: PathPrefix
            value: "/v1/api"
      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: "/api"
      backendRefs:
        - name: svc-web1
          port: 80

    # Rewrite /old-path to /new-path
    - matches:
        - path:
            type: PathPrefix
            value: "/old-path"
      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplaceFullPath
              replaceFullPath: "/new-path"
      backendRefs:
        - name: svc-web1
          port: 80
EOF

k apply -f 12.httproute-url-rewrite.yaml


k delete -f 12.httproute-url-rewrite.yaml
k delete ns app-namespace12
k delete ns infra-gateway12
Kiểm tra
curl --resolve test.tuan.name.vn:80:192.168.88.150 test.tuan.name.vn/v1/api/111
#Hostname: web1-888886b4d-tg4jv
#GET /api/111 HTTP/1.1 <- đây là kết quả pod đang hiển thị
curl --resolve test.tuan.name.vn:80:192.168.88.150 test.tuan.name.vn/old-path
#Hostname: web1-888886b4d-tg4jv
#GET /new-path HTTP/1.1 <- đây là kết quả pod đang hiển thị

k delete -f 12.httproute-url-rewrite.yaml


TESTED-13: Mirror request
https://gateway-api.sigs.k8s.io/guides/http-request-mirroring/ 
https://docs.nginx.com/nginx-gateway-fabric/traffic-management/mirror/ 

k create ns app-namespace13
k -n app-namespace13 create deployment web1 --image=nginx:alpine --replicas=1
k -n app-namespace13 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace13 create deployment web1a --image=nginx:alpine --replicas=1
k -n app-namespace13 expose deployment web1a --name=svc-web1a --port=80 --target-port=80 --type=ClusterIP

cat << EOF > 13.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway13
  namespace: infra-gateway13
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k create ns infra-gateway13
k apply -f 13.simple-gateway.yaml

cat << EOF > 13.httproute-mirroring.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: traffic-mirroring
  namespace: app-namespace13
spec:
  parentRefs:
  - name: my-gateway13 #chú ý trùng tên gateway
    namespace: infra-gateway13
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: "/"
      backendRefs:
        # Primary backend main pod
        - name: svc-web1
          port: 80

      filters:
        # Mirror to debug-pod
        - type: RequestMirror
          requestMirror:
            backendRef:
              name: svc-web1a
              port: 80
EOF

k apply -f 13.httproute-mirroring.yaml

Kiểm tra
curl --resolve test.tuan.name.vn:80:192.168.88.150 test.tuan.name.vn/
curl --resolve test.tuan.name.vn:80:192.168.88.150 test.tuan.name.vn/
curl --resolve test.tuan.name.vn:80:192.168.88.150 test.tuan.name.vn/
k -n app-namespace1  logs web1a-xxxxxxxxxx
#Ta thấy ở đây web1a cũng nhận được request tương tự
172.31.180.212 - - [01/Aug/2026:13:39:05 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/8.5.0" "192.168.88.14"
172.31.180.212 - - [01/Aug/2026:13:39:10 +0000] "GET / HTTP/1.1" 200 896 "-" "curl/8.5.0" "192.168.88.14"

k delete -f 13.httproute-mirroring.yaml

TESTED-14 ReferenceGrant


TESTED-14.1: HttpRoute->Services khác namespace
https://oneuptime.com/blog/post/2026-02-09-gateway-api-referencegrant-cross-namespace/view 
Kịch bản là tạo HTTPRoute với 1 số /path đặc biệt: từ namespace  AAA nhưng lại trỏ vào SVC của namespace BBB. Ta cần khai báo ReferenceGrant

Tạo gateway 
k create ns infra-gateway141
openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout tls.key   -out tls.crt   -subj "/CN=HELLO-WORLD-gateway/O=HELLO-WORLDe"
kubectl -n infra-gateway141 create secret tls default-cert --key tls.key   --cert tls.crt 


cat << EOF > 14.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway141
  namespace: infra-gateway141
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k apply -f 14.simple-gateway.yaml


k create ns app-namespace14-aaa
k create ns app-namespace14-bbb
k -n app-namespace14-aaa create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace14-aaa expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace14-bbb create deployment web1b --image=traefik/whoami --replicas=1
k -n app-namespace14-bbb expose deployment web1b --name=svc-web1b --port=80 --target-port=80 --type=ClusterIP
k -n app-namespace14-bbb create deployment web1c --image=traefik/whoami --replicas=1
k -n app-namespace14-bbb expose deployment web1c --name=svc-web1c --port=80 --target-port=80 --type=ClusterIP


cat << EOF > 14.1.httproute-cross-namespace.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: cross-namespace-route
  namespace: app-namespace14-aaa
spec:
  parentRefs:
    - name: my-gateway141
      namespace: infra-gateway141
  hostnames:
    - "test.tuan.name.vn"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: "/api-bbb"
      backendRefs:
        - name: svc-web1b
          namespace: app-namespace14-bbb
          port: 80
    - matches:
        - path:
            type: PathPrefix
            value: "/api-aaa"
      backendRefs:
        - name: svc-web1
          namespace: app-namespace14-aaa
          port: 80
---
# ReferenceGrant allowing cross-namespace reference
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-frontend-to-backend
  namespace: app-namespace14-bbb
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespace: app-namespace14-aaa
  to:
    - group: ""
      kind: Service
      name: svc-web1b
    - group: ""
      kind: Service
      name: svc-web1c
EOF

k apply -f 14.1.httproute-cross-namespace.yaml

curl --resolve test.tuan.name.vn:80:192.168.88.150 test.tuan.name.vn/api-bbb
Hostname: web1b-78f579969d-fv7st

curl --resolve test.tuan.name.vn:80:192.168.88.150 test.tuan.name.vn/api-aaa
Hostname: web1-84c9884bbb-2dgk6


k -n app-namespace14-bbb delete referencegrants.gateway.networking.k8s.io allow-frontend-to-backend
Không gọi được nữa 
curl --resolve test.tuan.name.vn:80:192.168.88.150 test.tuan.name.vn/api-bbb
<center><h1>500 Internal Server Error</h1></center>

k delete ns app-namespace14-aaa
k delete ns app-namespace14-bbb

TESTED-14.2: Gateway->Secret khác namespace
https://oneuptime.com/blog/post/2026-02-09-gateway-api-referencegrant-cross-namespace/view 
https://gateway-api.sigs.k8s.io/guides/tls/#cross-namespace-certificate-references 
# Certificate in certs namespace
k create ns app-namespace142
k create ns infra-gateway142
k -n app-namespace142 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace142 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP
openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout tls.key   -out tls.crt   -subj "/CN=*.tuan.name.vn/O=Default Certificate"
kubectl -n app-namespace142 create secret tls ssl-web1 --key tls.key   --cert tls.crt 

cat << EOF > 142.cross-secret-referenceGrant.yaml
# Grant access from infrastructure namespace
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-gateway-to-certs
  namespace: app-namespace142
spec:
  from:
  - group: gateway.networking.k8s.io
    kind: Gateway
    namespace: infra-gateway142
  to:
  - group: ""
    kind: Secret
    name: ssl-web1
EOF

k apply -f 142.cross-secret-referenceGrant.yaml

openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout tls.key   -out tls.crt   -subj "/CN=*.default.vn/O=Default Certificate"
kubectl -n infra-gateway142 create secret tls ssl-web1 --key tls.key   --cert tls.crt 

cat << EOF > 142.cross-secret.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway142
  namespace: infra-gateway142
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80 # Đây là default
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    protocol: HTTPS
    port: 443 # Đây là default
    tls:
      mode: Terminate
      certificateRefs:
      - name: default-cert
    allowedRoutes:
      namespaces:
        from: All
  - name: https-wildcard-domain1
    protocol: HTTPS
    port: 443
    hostname: "*.tuan.name.vn"
    tls:
      mode: Terminate
      certificateRefs:
      - name: ssl-web1
        namespace: app-namespace142
    allowedRoutes:
      namespaces:
        from: All
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: tes-cross-secret
  namespace: app-namespace142
spec:
  parentRefs:
  - name: wildcard-gateway
    namespace: infra-gateway03
    sectionName: https-wildcard-domain1 # Gắn đúng vào listener của domain1
  hostnames:
  - "test.tuan.name.vn" # Chỉ định subdomain cụ thể
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: svc-web1
      port: 80
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k apply -f 142.cross-secret.yaml



curl --resolve test.tuan.name.vn:443:192.168.88.150 -vk https://test.tuan.name.vn
*  subject: CN=*.tuan.name.vn; O=Default Certificate

# Thực hiện xóa referenceGrant, Thì sẽ không gọi được nữa. 
k -n app-namespace142 delete referencegrants.gateway.networking.k8s.io allow-gateway-to-certs

root@cicd:~/gatewayapi# curl --resolve test.tuan.name.vn:443:192.168.88.150 -vk https://test.tuan.name.vn
* Added test.tuan.name.vn:443:192.168.88.150 to DNS cache
* Hostname test.tuan.name.vn was found in DNS cache
*   Trying 192.168.88.150:443...
* connect to 192.168.88.150 port 443 from 192.168.88.20 port 59690 failed: Connection refused
* Failed to connect to test.tuan.name.vn port 443 after 1 ms: Couldn't connect to server
* Closing connection
curl: (7) Failed to connect to test.tuan.name.vn port 443 after 1 ms: Couldn't connect to server



*  subject: CN=*.domain2.com; O=Default Certificate
OK-15: ListenerSet->Secret
Tương tự giống Gateway đọc Secret
Trường hợp này dành cho việc ListenerSet đặt ở 1 namespace khác với Secret.
Nhưng không cần thiết làm như này cho lắm. Vì tiêu chuẩn google thiết kê theo mô hình sau:
https://gateway-api.sigs.k8s.io/guides/user-guides/listener-set/
 
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-teams-to-access-certs
  namespace: xxxx # <--- PHẢI đặt tại Namespace CHỨA tài nguyên đích (Secret)
spec:
  from:
  - group: gateway.networking.k8s.io
    kind: ListenerSet
    namespace: yyyy # <--- PHẢI đặt tại Namespace CHỨA ListenerSet
  - group: gateway.networking.k8s.io
    kind: ListenerSet
    namespace: zzzz # <--- PHẢI đặt tại Namespace CHỨA ListenerSet
  to:
  - group: ""
    kind: Secret               # Tài nguyên được phép truy cập chéo

ReferenceGrant - Các ví dụ khác
https://oneuptime.com/blog/post/2026-02-09-gateway-api-referencegrant-cross-namespace/view
https://oneuptime.com/blog/post/2026-02-09-cross-namespace-referencegrant/view#multi-tenant-gateway-architecture


TEST CHƯA OK-15: Increase timeout
All of timeout Gateway Api https://oneuptime.com/blog/post/2026-02-09-httproute-timeout-policies/view#graceful-timeout-handling 
Đầu tiên ta tạo 1 web bằng python sleep 10 giây trễ mới trả lời client mesages.
k create ns app-namespace15


cat << EOF > 15.deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-delay-python
  namespace: app-namespace15
  labels:
    app: api-delay
spec:
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api-delay
  template:
    metadata:
      labels:
        app: api-delay
    spec:
      containers:
        - name: python-server
          image: python:3.10-alpine
          ports:
            - containerPort: 8080
          command: ["python3", "-c"]
          args:
            - |
              import http.server
              import time

              class DelayedHandler(http.server.BaseHTTPRequestHandler):
                  def do_GET(self):
                      # Ép hệ thống dừng đúng 3 giây trước khi xử lý tiếp
                      time.sleep(10)
                      self.send_response(200)
                      self.send_header("Content-type", "application/json")
                      self.end_headers()
                      self.wfile.write(b'{"status": "success", "message": "Delayed by 10 seconds"}')

              server = http.server.HTTPServer(('0.0.0.0', 8080), DelayedHandler)
              print("Server đang chạy tại port 8080...")
              server.serve_forever()
EOF

k apply -f 15.deployment.yaml

k -n app-namespace15 expose deployment api-delay-python --name=svc-web1 --port=8080 --target-port=8080 --type=ClusterIP
k -n app-namespace15 expose deployment api-delay-python --name=svc-web2 --port=8080 --target-port=8080 --type=LoadBalancer
curl 192.168.88.151:8080
#{"status": "success", "message": "Delayed by 10 seconds"}
k -n app-namespace15 delete svc svc-web2

cat << EOF > 15.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway15
  namespace: infra-gateway15
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k create ns infra-gateway15
k apply -f 15.simple-gateway.yaml



cat << EOF > 15.httproute-timeouts.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: timeout-configuration
  namespace: app-namespace15 # Namespace chứa ứng dụng của bạn
spec:
  parentRefs:
  - name: my-gateway15 #chú ý trùng tên gateway
    namespace: infra-gateway15
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn"
  rules:
    # Fast endpoints with short timeout
    - matches:
        - path:
            type: PathPrefix
            value: "/health"
      timeouts:
        request: 10s           # Tổng thời gian request tối đa
        backendRequest: 2s     # Thời gian chờ Backend phản hồi (tương tự proxy_read_timeout)
      backendRefs:
        - name: svc-web1
          port: 8080

    # Slow endpoints with longer timeout
    - matches:
        - path:
            type: PathPrefix
            value: "/reports"
      timeouts:
        request: 60s
        backendRequest: 55s
      backendRefs:
        - name: svc-web1
          port: 8080
EOF

k apply -f 15.httproute-timeouts.yaml
Test
curl -w '\n\n Thoi Gian Phan Hoi La: %{time_total} giay\n' -vk --resolve test.tuan.name.vn:80:192.168.88.152 http://test.tuan.name.vn/health
Thoi Gian Phan Hoi La: 10.016382 giay
curl -w '\n\n Thoi Gian Phan Hoi La: %{time_total} giay\n' -vk --resolve test.tuan.name.vn:80:192.168.88.152 http://test.tuan.name.vn/reports
Thoi Gian Phan Hoi La: 10.016382 giay


k delete ns app-namespace15
k delete ns infra-gateway15


TESTED-18: Redirect 301/302
k create ns app-namespace18
k -n app-namespace18 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace18 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP

cat << EOF > 18.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway18
  namespace: infra-gateway18
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF
# Mục đích tạo thêm gw để dễ test. Còn thực tế gateway sẽ dùng chung

k create ns infra-gateway18
k apply -f 18.simple-gateway.yaml



cat << EOF > 18.httproute-redirect.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: redirect-example
  namespace: app-namespace18 # Namespace chứa ứng dụng của bạn
spec:
  parentRefs:
  - name: my-gateway18 #chú ý trùng tên gateway
    namespace: infra-gateway18
    sectionName: http #chú ý trùng tên section
  hostnames:
  - "test.tuan.name.vn" #Ta có thể bỏ hostnames để redirect https cho toàn bộ GW
  rules:
    # Redirect to new domain
    - filters:
        - type: RequestRedirect
          requestRedirect:
            hostname: test.tuan.name.vn
            statusCode: 302
            scheme: https
EOF

k apply -f 18.httproute-redirect.yaml
Kết quả
curl --resolve test.tuan.name.vn:80:192.168.88.150 -vk http://test.tuan.name.vn
< HTTP/1.1 302 Moved Permanently
< Location: https://test.tuan.name.vn/

TESTED-19: TLS Passthought
https://oneuptime.com/blog/post/2026-02-09-gateway-api-tlsroute-passthrough-tls/view 
https://oneuptime.com/blog/post/2026-02-09-tlsroute-passthrough/view
https://gateway-api.sigs.k8s.io/guides/tls-routing/ 

Cách hoạt động: Gateway hoàn toàn không giải mã dữ liệu. Nó chỉ đọc trường SNI (Server Name Indication) trong thông điệp TLS ClientHello của client để biết request muốn gửi tới domain nào, sau đó chuyển tiếp nguyên vẹn luồng traffic đã mã hóa xuống backend.
Yêu cầu: Việc giải mã TLS và quản lý chứng chỉ hoàn toàn do chính dịch vụ backend đảm nhận. Tầng Gateway điều hướng bằng tài nguyên TLSRoute thay vì HTTPRoute.
Tiêu chí TLS Passthrough (Chuyển tiếp) TLS Termination (Chấm dứt)
Bảo mật Bảo mật End-to-End tuyệt đối. Khóa bí mật nằm tại Pod ứng dụng, không bị lộ ra tầng Gateway chung. Tập trung khóa bí mật tại Gateway. Nếu Gateway bị tấn công, toàn bộ traffic của các ứng dụng có thể bị lộ.
Quản lý Cert Phân tán: Các đội phát triển tự quản lý chứng chỉ trên từng ứng dụng của họ. Tập trung: Đội hạ tầng quản lý toàn bộ chứng chỉ tại Gateway.
Hiệu năng Rất cao & Độ trễ thấp: Gateway không tốn tài nguyên CPU để giải mã/mã hóa lại dữ liệu. Tốn tài nguyên CPU của Gateway để xử lý quá trình bắt tay (handshake) và giải mã liên tục.
Khả năng Định tuyến Hạn chế: Chỉ có thể định tuyến dựa trên tên miền (SNI). Không thể đọc Header, Path (/api), hay Cookie. Linh hoạt (Layer 7): Có thể định tuyến nâng cao dựa vào Cookie, HTTP Headers, Method, hoặc các đường dẫn cụ thể.
An toàn (WAF/Ghi log) Kém: Gateway không thể kiểm tra mã độc hay áp dụng luật bảo mật WAF do dữ liệu bị mã hóa hoàn toàn. Tốt: Dễ dàng ghi log chi tiết URL, kiểm tra các lỗ hổng bảo mật trực tiếp tại tầng Gateway.

Bước 1 . Chuẩn bị deployment, configmaps, sefcret 

k create ns app-namespace19
cat << EOF > 19.configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: app-namespace19
data:
  nginx.conf: |
    server {
        listen 80;
        server_name localhost;
        
        # Tự động chuyển hướng từ HTTP sang HTTPS (Tùy chọn)
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        server_name localhost;

        ssl_certificate /etc/nginx/ssl/tls.crt;
        ssl_certificate_key /etc/nginx/ssl/tls.key;

        location / {
            root /usr/share/nginx/html;
            index index.html index.htm;
        }
    }
EOF

k apply -f 19.configmap.yaml

openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout tls.key   -out tls.crt   -subj "/CN=*.tuan.name.vn/O=Default Certificate"
kubectl -n app-namespace19 create secret tls nginx-ssl-secret --key tls.key   --cert tls.crt 


cat << EOF > 19.deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: app-namespace19
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
          name: http
        - containerPort: 443
          name: https
        volumeMounts:
        # Gắn file cấu hình NGINX vào container
        - name: config-volume
          mountPath: /etc/nginx/conf.d/default.conf
          subPath: nginx.conf
        # Gắn chứng chỉ SSL từ Secret vào container
        - name: ssl-volume
          mountPath: /etc/nginx/ssl
          readOnly: true
      volumes:
      - name: config-volume
        configMap:
          name: nginx-config
      - name: ssl-volume
        secret:
          secretName: nginx-ssl-secret
EOF

k apply -f 19.deployment.yaml


kubectl -n app-namespace19 expose deployment nginx-deployment --name=nginx-service-http --port=80 --target-port=80 --type=ClusterIP
kubectl -n app-namespace19 expose deployment nginx-deployment --name=nginx-service-https --port=443 --target-port=443 --type=ClusterIP



cat << EOF > 19.gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: nginx-gateway
  namespace: infra-gateway19
spec:
  gatewayClassName: nginx
  listeners:
  - name: tls-passthrough-listener
    protocol: TLS
    port: 443
    tls:
      mode: Passthrough
    allowedRoutes:
      kinds:
      - kind: TLSRoute
      namespaces:
        from: All
---
apiVersion: gateway.networking.k8s.io/v1
kind: TLSRoute
metadata:
  name: nginx-tls-route
  namespace: app-namespace19
spec:
  parentRefs:
  - name: nginx-gateway
    namespace: infra-gateway19
    sectionName: tls-passthrough-listener
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - backendRefs:
    - name: nginx-service-https
      port: 443
EOF

k create ns infra-gateway19
k apply -f 19.gateway.yaml


curl -vk --resolve test.tuan.name.vn:443:192.168.88.150 https://test.tuan.name.vn
*  subject: CN=*.tuan.name.vn; O=Default Certificate


TESTED-20: TCP/UDP Route
https://oneuptime.com/blog/post/2026-02-09-gateway-api-tcproute-udproute-layer4/view
https://gateway-api.sigs.k8s.io/guides/tcp/ 

k create ns app-namespace20
k -n app-namespace20 create deployment web1 --image=traefik/whoami --replicas=1
k -n app-namespace20 expose deployment web1 --name=svc-web1 --port=80 --target-port=80 --type=ClusterIP



cat << EOF > 20.gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: shared-tcp-gateway
  namespace: infra-gateway20
spec:
  gatewayClassName: nginx
  listeners:
  - name: tcp-web-listener
    protocol: TCP
    port: 8080
    allowedRoutes:
      kinds:
      - kind: TCPRoute
      namespaces:
        from: All
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
  name: web1-tcp-route
  namespace: app-namespace20
spec:
  parentRefs:
  - name: shared-tcp-gateway
    namespace: infra-gateway20
    sectionName: tcp-web-listener
  rules:
  - backendRefs:
    - name: svc-web1
      port: 80
EOF

k apply -f 20.gateway.yaml
k create ns infra-gateway20

curl 192.168.88.150:8080
Hostname: web1-84c9884bbb-2q882




TESTED-21: BackendTLSPolicy
Việc dùng BackendTLSPolicy là cho trường  hợp backend đằng sau có SSL
https://gateway-api.sigs.k8s.io/api-types/backendtlspolicy/#:~:text=are%20not%20allowed.-,WellKnownCACertificates,of%20choice%20for%20more%20information. 

https://gateway-api.sigs.k8s.io/guides/tls/#using-system-certificates 

k create ns app-namespace21
cat << EOF > 21.configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: app-namespace21
data:
  nginx.conf: |
    server {
        listen 80;
        server_name localhost;
        
        # Tự động chuyển hướng từ HTTP sang HTTPS (Tùy chọn)
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        server_name test.tuan.name.vn;

        ssl_certificate /etc/nginx/ssl/tls.crt;
        ssl_certificate_key /etc/nginx/ssl/tls.key;

        location / {
            root /usr/share/nginx/html;
            index index.html index.htm;
        }
    }
EOF

k apply -f 21.configmap.yaml

openssl req -x509 -nodes -days 365 -newkey rsa:2048   -keyout tls.key   -out tls.crt   -subj "/CN=*.tuan.name.vn/O=Default Certificate"
kubectl -n app-namespace21 create secret tls nginx-ssl-secret --key tls.key   --cert tls.crt 

cat << EOF > 21.deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: app-namespace21
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
          name: http
        - containerPort: 443
          name: https
        volumeMounts:
        # Gắn file cấu hình NGINX vào container
        - name: config-volume
          mountPath: /etc/nginx/conf.d/default.conf
          subPath: nginx.conf
        # Gắn chứng chỉ SSL từ Secret vào container
        - name: ssl-volume
          mountPath: /etc/nginx/ssl
          readOnly: true
      volumes:
      - name: config-volume
        configMap:
          name: nginx-config
      - name: ssl-volume
        secret:
          secretName: nginx-ssl-secret
EOF

k apply -f 21.deployment.yaml

kubectl -n app-namespace21 expose deployment nginx-deployment --name=nginx-service-http --port=80 --target-port=80 --type=ClusterIP
kubectl -n app-namespace21 expose deployment nginx-deployment --name=nginx-service-https --port=443 --target-port=443 --type=ClusterIP



apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: external-gateway
  namespace: infra-gateway21
spec:
  gatewayClassName: nginx
  listeners:
  - name: http-listener
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: nginx-http-route
  namespace: app-namespace21
spec:
  parentRefs:
  - name: external-gateway
    namespace: infra-gateway21
    sectionName: http-listener
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - backendRefs:
    - name: nginx-service-https
      port: 443

Lựa chọn 1 trong 2 cách:
CÁCH 1: 
# Chú ý cert của deployment nên là cert xịn, nếu cert đểu thì gọi lỗi 502 bad gateway
apiVersion: gateway.networking.k8s.io/v1
kind: BackendTLSPolicy
metadata:
  name: gateway-to-backend-tls
  namespace: app-namespace21
spec:
  targetRefs:
  - group: ""
    kind: Service
    name: nginx-service-https
  validation:
    hostname: "test.tuan.name.vn"
    wellKnownCACertificates: System

CÁCH 2: Nếu cert là đểu, thì dùng cách này
# CHÚ Ý: BACKEND TLS không được tạo từ Secret, Mà phải được tạo từ configmap 
kubectl get secret nginx-ssl-secret -n app-namespace21 -o jsonpath='{.data.tls\.crt}' | base64 -d > ca.crt
kubectl create configmap nginx-ca-cert --from-file=ca.crt=ca.crt -n app-namespace21
---
apiVersion: gateway.networking.k8s.io/v1
kind: BackendTLSPolicy
metadata:
  name: nginx-backend-tls-policy
  namespace: app-namespace21
spec:
  targetRefs:
  - group: ""
    kind: Service
    name: nginx-service-https
  validation:
    caCertificateRefs:
    - group: ""
      kind: ConfigMap
      name: nginx-ca-cert
    hostname: test.tuan.name.vn


22: CORS
https://gateway-api.sigs.k8s.io/guides/http-cors/
https://docs.nginx.com/nginx-gateway-fabric/traffic-security/cors/


Cần nghiên cứu thêm

(NOT)Ví dụ 26-A: mTLS Frontend
https://gateway-api.sigs.k8s.io/guides/tls/#basic-client-validation 
https://docs.nginx.com/nginx-gateway-fabric/traffic-security/client-validation/

(NOT)Ví dụ 26-B: mTLS Backend
https://docs.nginx.com/nginx-gateway-fabric/traffic-security/secure-backend/ 


(NOT)Ví dụ 27: HTTP2.0 Support Backend
https://gateway-api.sigs.k8s.io/guides/backend-protocol/



TESTED-31: basic authen
https://docs.nginx.com/nginx-gateway-fabric/traffic-security/basic-authentication/ 
https://docs.nginx.com/nginx-gateway-fabric/traffic-security/integrate-cert-manager/

k create ns infra-gateway31
cat << EOF > 31.deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coffee
spec:
  replicas: 2
  selector:
    matchLabels:
      app: coffee
  template:
    metadata:
      labels:
        app: coffee
    spec:
      containers:
      - name: coffee
        image: nginxdemos/nginx-hello:plain-text
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: coffee
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: coffee
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tea
spec:
  replicas: 2
  selector:
    matchLabels:
      app: tea
  template:
    metadata:
      labels:
        app: tea
    spec:
      containers:
      - name: tea
        image: nginxdemos/nginx-hello:plain-text
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: tea
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: tea
EOF

k -n infra-gateway31 apply -f 31.deployment.yaml


cat << EOF > 31.simple-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: cafe-gateway
  namespace: infra-gateway31
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    hostname: "test.tuan.name.vn"
EOF
k apply -f 31.simple-gateway.yaml

cat << EOF > 31.secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: basic-auth
  namespace: infra-gateway31
type: nginx.org/htpasswd
data:
  # Base64 of "htpasswd -bn user1 password1"
  auth: dXNlcjE6JGFwcjEkWEFKeU5yekgkY0Rjdy9YMVBCZTFmTjltQVBweXpxMA==
---
apiVersion: gateway.nginx.org/v1alpha1
kind: AuthenticationFilter
metadata:
  name: basic-auth
  namespace: infra-gateway31
spec:
  type: Basic
  basic:
    secretRef:
      name: basic-auth
    realm: "Restricted basic-auth"
EOF

k apply -f 31.secret.yaml

cat << EOF > 31.httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: cafe-routes
  namespace: infra-gateway31
spec:
  parentRefs:
  - name: cafe-gateway
    sectionName: http
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - matches:
      - path:
          type: PathPrefix
          value: /coffee
    backendRefs:
      - name: coffee
        port: 80
    filters:
      - type: ExtensionRef
        extensionRef:
          group: gateway.nginx.org
          kind: AuthenticationFilter
          name: basic-auth
  - matches:
      - path:
          type: PathPrefix
          value: /tea
    backendRefs:
      - name: tea
        port: 80
EOF

k apply -f 31.httproute.yaml
Test:
curl -vk --resolve test.tuan.name.vn:443:192.168.88.150 http://test.tuan.name.vn/coffee
< HTTP/1.1 401 Unauthorized
<head><title>401 Authorization Required</title></head>

curl -vk --resolve test.tuan.name.vn:443:192.168.88.150 http://test.tuan.name.vn/coffee -u user1:password1
< HTTP/1.1 200 OK

curl -vk --resolve test.tuan.name.vn:443:192.168.88.150 http://test.tuan.name.vn/tea
< HTTP/1.1 200 OK

Ta có thể vào pod nginx-gateway để kiểm tra config như ssau:
    location = /coffee {
        auth_basic "Restricted basic-auth";
        auth_basic_user_file /etc/nginx/secrets/basic_auth_infra-gateway31_basic-auth;

cat /etc/nginx/secrets/basic_auth_infra-gateway31_basic-auth
user1:$apr1$XAJyNrzH$cDcw/X1PBe1fN9mAPpyzq0


Nginx GW Fabric Advance

????-32: SnippetsFilter + SnipetsPolicies

 
https://docs.nginx.com/nginx-gateway-fabric/traffic-management/snippets/
Tiêu chí phân biệt SnippetsFilter SnippetsPolicy
Bản chất tài nguyên Hoạt động như một Filter (Bộ lọc tuyến đường). Hoạt động như một Direct Policy Attachment (Chính sách đính kèm trực tiếp).
Phạm vi tác động (Scope) Cục bộ (Local) - Chỉ ảnh hưởng tới một Rule cụ thể trong Route. Toàn cục (Global) - Ảnh hưởng tới toàn bộ Gateway và tất cả Route thuộc Gateway đó.
Đối tượng gắn kết (target) Gắn bên trong mảng filters của tài nguyên HTTPRoute hoặc GRPCRoute. Gắn qua trường targetRefs chỉ định trực tiếp đến một hoặc nhiều tài nguyên Gateway.
Mục đích sử dụng chính Thay thế cho các annotation dạng Proxy cũ trên từng Endpoint (như chỉnh timeout websocket, bật/tắt buffer cho 1 API). Thiết lập cấu hình mặc định, dùng chung cho toàn bộ Gateway (như cấu hình SSL parameters, bộ nhớ đệm dùng chung, kích thước buffer lớn).
Vị trí chèn lý tưởng trong nginx.conf Phù hợp nhất cho ngữ cảnh: http.server.location. Phù hợp nhất cho ngữ cảnh: main, http, http.server.
Namespace yêu cầu Phải nằm cùng Namespace với tài nguyên Route chứa nó. Phải nằm cùng Namespace với tài nguyên Gateway mà nó nhắm tới.

SnippetsFilter
SnippetsPolicy
 



k create ns infra-gateway32


apiVersion: apps/v1
kind: Deployment
metadata:
  name: coffee
  namespace: infra-gateway32
spec:
  replicas: 1
  selector:
    matchLabels:
      app: coffee
  template:
    metadata:
      labels:
        app: coffee
    spec:
      containers:
        - name: coffee
          image: nginxdemos/nginx-hello:plain-text
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: coffee
  namespace: infra-gateway32
spec:
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app: coffee
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tea
  namespace: infra-gateway32
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tea
  template:
    metadata:
      labels:
        app: tea
    spec:
      containers:
        - name: tea
          image: nginxdemos/nginx-hello:plain-text
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: tea
  namespace: infra-gateway32
spec:
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app: tea


apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway
  namespace: infra-gateway32
spec:
  gatewayClassName: nginx
  listeners:
    - name: http
      port: 80
      protocol: HTTP
      hostname: "*.tuan.name.vn"

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: coffee
  namespace: infra-gateway32
spec:
  parentRefs:
    - name: gateway
      sectionName: http
  hostnames:
    - "test.tuan.name.vn"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /coffee
      backendRefs:
        - name: coffee
          port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: tea
  namespace: infra-gateway32
spec:
  parentRefs:
    - name: gateway
      sectionName: http
  hostnames:
    - "test.tuan.name.vn"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /tea
      backendRefs:
        - name: tea
          port: 80


curl -vk --resolve test.tuan.name.vn:443:192.168.88.150 http://test.tuan.name.vn/coffee
< HTTP/1.1 200 OK
curl -vk --resolve test.tuan.name.vn:443:192.168.88.150 http://test.tuan.name.vn/tea
< HTTP/1.1 200 OK


apiVersion: gateway.nginx.org/v1alpha1
kind: SnippetsFilter
metadata:
  name: limit-except-sf
  namespace: infra-gateway32
spec:
  snippets:
    - context: http.server.location
      value: |
        limit_except GET {
          deny all;
        }


apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: coffee
  namespace: infra-gateway32
spec:
  parentRefs:
    - name: gateway
      sectionName: http
  hostnames:
    - "test.tuan.name.vn"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /coffee
      filters:
        - type: ExtensionRef
          extensionRef:
            group: gateway.nginx.org
            kind: SnippetsFilter
            name: limit-except-sf
      backendRefs:
        - name: coffee
          port: 80
Test kiểm tra:

curl -vk --resolve test.tuan.name.vn:443:192.168.88.150 http://test.tuan.name.vn/coffee -X GET
curl -vk --resolve test.tuan.name.vn:443:192.168.88.150 http://test.tuan.name.vn/coffee -X POST





TESTED-33: ClientSettingsPolicy
https://docs.nginx.com/nginx-gateway-fabric/traffic-management/client-settings/ 
client_max_body_size: Dung lượng upload lên
client_body_timeout:thời gian chờ body gửi lên hoàn tất  
keepalive_requests: lượng reuqest tối đa gửi trên 1 kết nối TCP, default là 1000 
keepalive_time: thời gian request tồn tại , default là 1 h 
keepalive_timeout : default 75s
keepalive_min_timeout 
Những phần có thể setting trong ClientSettingPolicy
  spec  <Object> -required-
    body        <Object>
      maxSize   <string>
      timeout   <string>
    keepAlive   <Object>
      minTimeout        <string>
      requests  <integer>
      time      <string>
      timeout   <Object>
        header  <string>
        server  <string>




Rút gọn bằng 4 lệnh sau:
kubectl -n ingra-gateway33 create deployment coffee --image=nginxdemos/nginx-hello:plain-text --replicas=1 --port=8080 
kubectl -n ingra-gateway33 expose deployment coffee --port=80 --target-port=8080 --name=coffee
kubectl -n ingra-gateway33 create deployment tea --image=nginxdemos/nginx-hello:plain-text --replicas=1 --port=8080
kubectl -n ingra-gateway33 expose deployment tea --port=80 --target-port=8080 --name=tea

apiVersion: apps/v1
kind: Deployment
metadata:
  name: coffee
  namespace: infra-gateway33
spec:
  replicas: 1
  selector:
    matchLabels:
      app: coffee
  template:
    metadata:
      labels:
        app: coffee
    spec:
      containers:
      - name: coffee
        image: nginxdemos/nginx-hello:plain-text
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: coffee
  namespace: infra-gateway33
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: coffee
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tea
  namespace: infra-gateway33
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tea
  template:
    metadata:
      labels:
        app: tea
    spec:
      containers:
      - name: tea
        image: nginxdemos/nginx-hello:plain-text
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: tea
  namespace: infra-gateway33
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: tea
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway
  namespace: infra-gateway33
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    hostname: "*.tuan.name.vn"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: coffee
  namespace: infra-gateway33
spec:
  parentRefs:
  - name: gateway
    sectionName: http
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /coffee
    backendRefs:
    - name: coffee
      port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: tea
  namespace: infra-gateway33
spec:
  parentRefs:
  - name: gateway
    sectionName: http
  hostnames:
  - "test.tuan.name.vn"
  rules:
  - matches:
    - path:
        type: Exact
        value: /tea
    backendRefs:
    - name: tea
      port: 80
---
apiVersion: gateway.nginx.org/v1alpha1
kind: ClientSettingsPolicy
metadata:
  name: gateway-client-settings
  namespace: infra-gateway33
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: Gateway
    name: gateway
  body:
    maxSize: "50" # sizes without a unit are bytes. -> in production , maybe change to 500m

curl -vk --resolve test.tuan.name.vn:443:192.168.88.150 http://test.tuan.name.vn/coffee -XPOST -d 'this payload is greater than fifty bytes by four bytes'
< HTTP/1.1 413 Request Entity Too Large



UpstreamSettingsPolicy
https://docs.nginx.com/nginx-gateway-fabric/traffic-management/upstream-settings/ 
Những thành phần có thể setting cho khối upstream {.....}
  spec  <Object> -required-
    hashMethodKey       <string>
    keepAlive   <Object>
      connections       <integer>
      requests  <integer>
      time      <string>
      timeout   <string>
    loadBalancingMethod <string>
    enum: round_robin, least_conn, ip_hash, hash, ....



Session-persistence
https://docs.nginx.com/nginx-gateway-fabric/traffic-management/session-persistence/ 
Tương đương ip-hash để giữ phiên client connect đến backend
Session persistence ensures that multiple requests from the same client are consistently routed to the same backend Pod
  spec  <Object> -required-
    hashMethodKey       <string>
    keepAlive   <Object>
      connections       <integer>
      requests  <integer>
      time      <string>
      timeout   <string>
    loadBalancingMethod <string>
    enum: round_robin, least_conn, ip_hash, hash, ....

apiVersion: gateway.nginx.org/v1alpha1
kind: UpstreamSettingsPolicy
metadata:
  name: lb-method
spec:
  targetRefs:
  - group: core
    kind: Service
    name: coffee
  loadBalancingMethod: "ip_hash"



NginxGateway
Đây chính là pod controler của fabric trong namespace nginx-gateway. Ta có  thể sửa log mode của pod controler này
# k get nginxgateways.gateway.nginx.org -A
NAMESPACE       NAME                   AGE
nginx-gateway   nginx-gateway-config   24d

# k -n nginx-gateway get pod
NAME                            READY   STATUS    RESTARTS         AGE
nginx-gateway-f8f5c5455-vhdts   1/1     Running   18 (3h33m ago)   24d

# k -n nginx-gateway edit nginxgateways nginx-gateway-config
spec:
  logging:
    level: debug #info , debug, error

k -n nginx-gateway logs nginx-gateway-f8f5c5455-vhdts  -f



NginxProxy 
Sửa được rất nhiều thứ: https://docs.nginx.com/nginx-gateway-fabric/how-to/data-plane-configuration/
1. Mạng & Giao thức: Bật/tắt nhanh HTTP/2, chọn chuẩn IP (IPv4/IPv6), và cấu hình giữ nguyên IP gốc của người dùng (RewriteClientIP).
2. Hệ thống & Giám sát: Đổi cấp độ ghi log (như bật chế độ debug), format access log và cấu hình đẩy dữ liệu theo dõi hệ thống sang OpenTelemetry.
3. Tài nguyên Kubernetes: Thay đổi số lượng Pod (replicas), giới hạn phần cứng (CPU/RAM), hoặc vá cấu hình nâng cao (patches) cho Deployment, Service và DaemonSet của NGINX.


observabilitypolicies
https://docs.nginx.com/nginx-gateway-fabric/monitoring/tracing/

proxysettingspolicies
https://docs.nginx.com/nginx-gateway-fabric/traffic-management/proxy-settings/
proxy_buffering
proxy_buffer_size
proxy_buffers
proxy_busy_buffers_size
proxy_connect_timeout
proxy_read_timeout
proxy_send_timeout



 

ratelimitpolicies
https://docs.nginx.com/nginx-gateway-fabric/traffic-management/rate-limit/





Kiến trúc GWAPI
 
 
 

Security cho GatewayAPI
1. Giới hạn NS cho GW và httpRoute
Không Nên nên
   


Nginx SNI

Nginx SNI SNI chia làm 2 loại là SNI server và SNI Client 1. Nginx reject non-SNI – server side # Khối server mặc định để c...