NGINX Gateway Fabric: WAFPolicy로 F5 WAF 정책 적용

NGINX Gateway Fabric은 F5 WAF for NGINX와 연동하여 Gateway API로 구성된 애플리케이션 트래픽에 WAF 저책을 적용할 수 있습니다. WAFPolicy는 Gateway 또는 HTTPRoute와 같은 리소스를 대상으로 적용할 수 있으며, Gateway에 적용한 정책은 해당 Gateway에 연결된 Route에 상속됩니다.

이번 포스트에서는 하나의 Gateway에 두 개의 HTTPRoute를 연결하고 Gateway-level WAFPolicy를 구성합니다. 각 HTTPRoute에는 별도의 WAFPolciy를 구성하지 않고, Gateway에 적용된 공통 WAF 정책이 두 Route에 동일하게 적용되는 구성을 확인합니다.

정상 요청이 각 백엔드 애플리케이션으로 전달되는지 확인한 뒤 XSS 공격 패턴이 포함된 요청을 발생시켜 두 Route에서 동일하게 차단되는지 검증합니다. 이를 통해 여러 애플리케이션 Route가 하나의 Gateway를 공유하는 환경에서 공통 WAF 정책을 적용하는 구성을 살펴봅니다.

목차

1. 실습 목표
2. 환경 구성
3. 기존 NGF 환경 확인
4. 기존 NGF에 WAF 기능 활성화
5. 테스트 애플리케이션 배포
6. Gateway 생성
7. 복수 HTTPRoute 생성
8. WAF policy bundle 준비
8-1. WAF policy definition ConfigMap 생성
8-2. Bundle server 배포
9. Gateway-level WAFPolicy 생성
10. 동일 공격 요청으로 WAFPolicy 상속 검증
11. 결론

1. 실습 목표

  • 기존 NGINX Gateway Fabric 환경에서 F5 WAF for NGINX 기능을 활성화합니다.
  • 하나의 Gateway에 여러 HTTPRoute를 연결합니다.
  • Gateway를 대상으로 WAFPolicy를 적용합니다.
  • 각 HTTPRoute에는 별도 WAFPolicy를 구성하지 않은 상태에서 Gateway-level 정책이 하위 Route에 적용되는지 확인합니다.
  • 정상 요청과 공격 패턴이 포함된 요청을 비교하여 WAF 정책의 동작을 검증합니다.

2. 환경 구성

구성 요소버전
NGINX Gateway Fabric2.6.5
NGINX Plus1.29.8 (r37.0.2)
Kubernetesv1.36.2
Helmv3.20.0

3. 기존 NGF 환경 확인

먼저 GatewayClass가 정상적으로 등록되어 있는지 확인합니다.

$ kubectl get gatewayclass
NAME CONTROLLER ACCEPTED AGE
nginx gateway.nginx.org/nginx-gateway-controller True 2d23h

이어서 NGINX Gateway Fabric의 Control Plane Pod 상태를 확인합니다.

$ kubectl get pods -n nginx-gateway
NAME READY STATUS RESTARTS AGE
ngf-nginx-gateway-fabric-76bcf4cc77-ft6h9 1/1 Running 0 2d23h

Helm으로 설치한 경우 Deployment 상태도 함께 확인할 수 있습니다.

$ kubectl get deployments -n nginx-gateway
NAME READY UP-TO-DATE AVAILABLE AGE
ngf-nginx-gateway-fabric 1/1 1 1 2d23h

마지막으로 Control Plane에서 사용하는 Service를 확인합니다.

$ kubectl get svc -n nginx-gateway
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ngf-nginx-gateway-fabric ClusterIP 10.108.114.119 <none> 443/TCP 2d23h

4. 기존 NGF에 WAF 기능 활성화

기존 NGINX Gateway Fabric 환경에서 F5 WAF for NGINX를 사용하려면 WAF가 포함된 NGINX Plus 이미지를 사용하고 WAF 기능을 활성화해야 합니다.

F5 WAF for NGINX는 NGINX Plus와 별도의 구독이 필요하며, WAF가 포함된 NGINX Plus 이미지는 private-registry.nginx.com을 통해 제공됩니다.

먼저 private-registry.nginx.com에서 이미지를 가져올 수 있도록 Registry 인증에 사용할 인증서와 key를 준비합니다.

$ mkdir -p /etc/docker/certs.d/private-registry.nginx.com
$ cp <path-to-your-nginx-repo.crt> /etc/docker/certs.d/private-registry.nginx.com/client.cert
$ cp <path-to-your-nginx-repo.key> /etc/docker/certs.d/private-registry.nginx.com/client.key

Registry 인증 정보를 기반으로 imagePullSecret을 생성한 뒤, 현재 설치된 NGINX Gateway Fabric의 Helm Release 이름을 확인합니다.

$ helm list -n nginx-gateway
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
ngf nginx-gateway 2 2026-06-19 10:21:38.276932496 +0900 KST deployed nginx-gateway-fabric-2.6.5 2.6.5

Release 이름이 ngf인 경우 다음과 같이 WAF가 포함된 NGINX Plus 이미지를 지정하고 WAF 기능을 활성화합니다.

$ helm upgrade ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
-n nginx-gateway \
--set nginx.image.repository=private-registry.nginx.com/nginx-gateway-fabric/nginx-plus-f5waf \
--set nginx.plus=true \
--set nginx.config.waf.enable=true \
--set nginx.imagePullSecret=nginx-plus-registry-secret

각 설정의 역할은 다음과 같습니다.

설정설명
nginx.image.repositoryF5 WAF for NGINX가 포함된 NGINX Plus 이미지 지정
nginx.plus=trueNGINX Plus Data Plane 사용
nginx.config.waf.enable=trueF5 WAF for NGINX 기능 활성화
nginx.imagePullSecretPrivate Registry 인증에 사용할 Secret 지정

정상적으로 업그레이드되면 Helm Release의 Revision이 증가하고 STATUSdeployed로 표시됩니다.

Pulled: ghcr.io/nginx/charts/nginx-gateway-fabric:2.6.5
Digest: sha256:6a799f2a46f78db8790bd6e927ace8ee7699940654f3cee667ceeea465894ee9
Release "ngf" has been upgraded. Happy Helming!
NAME: ngf
LAST DEPLOYED: Fri Jun 19 10:21:38 2026
NAMESPACE: nginx-gateway
STATUS: deployed
REVISION: 3
TEST SUITE: None

업그레이드 후 Helm values를 확인하여 WAF 관련 설정이 정상적으로 반영되었는지 확인합니다.

$ helm get values ngf -n nginx-gateway

다음과 같이 WAF 활성화와 NGINX Plus 이미지 설정이 확인되어야 합니다.

USER-SUPPLIED VALUES:
nginx:
config:
waf:
enable: true
image:
repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus-f5waf
imagePullSecret: nginx-plus-registry-secret
plus: true

여기까지 구성하면 NGINX Gateway Fabric에서 F5 WAF for NGINX 기능을 사용할 수 있는 상태가 됩니다. 이후 Gateway와 HTTPRoute를 생성하고 WAFPolciy를 연결하여 실제 애플리케이션 트래픽에 WAF 정책을 적용합니다.

NGINX Gateway Fabric을 설치할 때, Helm 방식이 아닌 Mainfast 방식을 사용하였다면, NginxProxy 리소스를 수정하여 WAF를 활성화 시킬 수 있습니다.

5. 테스트 애플리케이션 배포

Gateway와 WAFPolicy 동작을 확인하기 위해 서로 다른 두 개의 테스트 애플리케이션을 배포합니다.

각 애플리케이션은 nginxdemos/nginx-hello:plain-text 이미지를 사용하며, 각각 별도의 Deployment와 ClusterIP Service로 구성합니다. 이후 두 Service를 서로 다른 HTTPRoute의 Backeend로 연결합니다.

apps.yaml 파일을 생성하고 다음 내용을 작성합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
name: app1
spec:
replicas: 1
selector:
matchLabels:
app: app1
template:
metadata:
labels:
app: app1
spec:
containers:
- name: app1
image: nginxdemos/nginx-hello:plain-text
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: app1
spec:
selector:
app: app1
ports:
- name: http
port: 80
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app2
spec:
replicas: 1
selector:
matchLabels:
app: app2
template:
metadata:
labels:
app: app2
spec:
containers:
- name: app2
image: nginxdemos/nginx-hello:plain-text
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: app2
spec:
selector:
app: app2
ports:
- name: http
port: 80
targetPort: 8080

각 Deployment는 Container의 8080/TCP 포트에서 요청을 처리하고, Service는 80/TCP 포트로 요청을 받아 해당 Pod의 8080/TCP 포트로 전달됩니다.

작성한 리소스를 적용합니다.

$ kubectl apply -f apps.yaml

생성된 Deployment, Pod, Service 상태를 확인합니다.

$ kubectl get deployment,pods,svc

정상적으로 배포된 경우 다음과 같이 두 Deployment와 Pod가 실행되고, 각각의 ClusterIP Service가 생성됩니다.

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/app1 1/1 1 1 2d23h
deployment.apps/app2 1/1 1 1 2d23h
NAME READY STATUS RESTARTS AGE
pod/app1-8455b5554c-tqrwx 1/1 Running 0 2d23h
pod/app2-657c5d4769-2lml5 1/1 Running 0 2d23h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/app1 ClusterIP 10.111.215.35 <none> 80/TCP 2d23h
service/app2 ClusterIP 10.96.139.192 <none> 80/TCP 2d23h

두 Service는 이후 생성할 app1-routeapp2-routeBackend로 사용합니다.

6. Gateway 생성

두 HTTPRoute가 공통으로 연결될 Gateway를 생성합니다.

Gateway는 클라이언트 트래픽이 유입되는 공통 진입점으로 사용되며, 이후 생성할 app1-routeapp2-route가 동일한 Gateawy를 참조하도록 구성합니다. Gateway가 nginx GatewayClass에 연결되면 NGINX Gateway Fabric이 해당 Gateway를 처리할 Data Plane을 구성합니다.

gateway.yaml 파일을 생성하고 다음 내용을 작성합니다.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shared-gateway
spec:
gatewayClassName: nginx
listeners:
- name: http
port: 80
protocol: HTTP

주요 설정은 다음과 같습니다.

항목설정설명
gatewayClassNamenginxNGINX Gateway Fabric이 관리하는 GatewayClass 지정
listeners.namehttpListener 이름
listeners.port80HTTP 요청을 수신할 포트
listeners.protocolHTTPListener에서 사용할 프로토콜

작성한 Gateway 리소스를 적용합니다.

$ kubectl apply -f gateway.yaml

Gateway 상태를 확인합니다.

$ kubectl get gateway shared-gateway
$ kubectl describe gateway shared-gateway

정상적으로 구성된 경우 Gateway의 Programmed 상태가 True로 표시됩니다.

NAME CLASS ADDRESS PROGRAMMED AGE
shared-gateway nginx True 2d23h

kubectl describe 결과에서는 Accepted=TrueProgrammed=True 상태를 확인할 수 있습니다.

...
Status:
Conditions:
Message: The Gateway is accepted
Reason: Accepted
Status: True
Type: Accepted
Message: The Gateway is programmed
Reason: Programmed
Status: True
Type: Programmed
...

Accepted=True는 Gateway 구성이 NGINX Gateway Fabric에 의해 정상적으로 수락되었음을 의미하며, Programmed=True는 해당 구성이 Data Plane에 반영되어 트래픽을 처리할 수 있는 상태임을 나타냅니다.

이후 두 개의 HTTPRoute를 생성하여 shared-gateway에 연결합니다.

7. 복수 HTTPRoute 생성

shared-gateway에 두 개의 HTTPRoute를 연결하고, 각 Route가 서로 다른 Backend Service로 요청을 전달하도록 구성합니다.

이번 구성에서는 app1-routeapp2-route를 생성하고 각각 다른 Hostname을 사용합니다. 두 HTTPRoute는 동일한 shared-gateway를 참조하므로 이후 Gateway에 적용할 WAFPolciy의 공통 적용 대상이 됩니다.

httproutes.yaml 파일을 생성하고 다음 내용을 작성합니다.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app1-route
spec:
parentRefs:
- name: shared-gateway
hostnames:
- "app1.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app1
port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app2-route
spec:
parentRefs:
- name: shared-gateway
hostnames:
- "app2.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app2
port: 80

주요 설정은 다음과 같습니다.

항목설정 예시설명
parentRefs.nameshared-gatewayHTTPRoute가 연결될 Gateway 지정
hostnamesapp1.example.com해당 Route가 처리할 Hostname 지정
matches.path.typePathPrefix지정된 경로 Prefix를 기준으로 요청 매칭
matches.path.value/모든 하위 경로를 포함하도록 / 지정
backendRefs.nameapp1요청을 전달할 Backend Service 지정
backendRefs.port80Backend Service의 포트 지정

작성한 HTTPRoute를 적용합니다.

$ kubectl apply -f httproutes.yaml

생성된 HTTPRoute를 확인합니다.

$ kubectl get httproute

정상적으로 생성된 경우 다음과 같이 각 Route와 Hostname을 확인할 수 있습니다.

NAME HOSTNAMES AGE
app1-route ["app1.example.com"] 8m40s
app2-route ["app2.example.com"] 8m40s

HTTPRoute가 shared-gateway에 정상적으로 연결되었는지 확인합니다.

$ kubectl describe httproute app1-route
$ kubectl describe httproute app2-route

정상적으로 연결된 경우 각 HTTPRoute의 Status에서 Accepted=True를 확인할 수 있습니다.

여기까지 구성하면 하나의 Gateway를 기준으로 서로 다른 두 Hostname과 Backend Service가 연결됩니다. 다음 단계에서는 두 Route에 공통으로 적용할 WAF Policy Bundle을 준비합니다.

8. WAF policy bundle 준비

NGINX Gateway Fabric의 WAFPolicy는 WAF Policy JSON 파일을 직접 참조하지 않고, F5 WAF for NGINX에서 사용할 수 있도록 컴파일된 Policy Bundle을 참조합니다.

따라서 WAF Policy JSON을 작성한 뒤 WAF Compiler를 사용하여 .tgz 형식의 Bundle로 컴파일하고, 생성된 Bundle을 WAFPolicy에서 접근할 수 있도록 HTTP로 제공합니다.

8-1. WAF policy definition ConfigMap 생성

먼저 WAF Policy JSON을 ConfigMap으로 생성합니다.

이번 정책에서는 All Signatures Signature Set을 사용하고, 탐지된 공격 시그니처에 대해 alarmblock을 활성화합니다. 이후 XSS 패턴이 포함된 요청을 발생시켜 차단 여부를 확인합니다.

waf-policy-definitions.yaml 파일을 생성하고 다음 내용을 작성합니다.

apiVersion: v1
kind: ConfigMap
metadata:
name: waf-policy-definitions
data:
attack-signatures-blocking.json: |
{
"policy": {
"name": "attack-signatures-blocking",
"template": {
"name": "POLICY_TEMPLATE_NGINX_BASE"
},
"applicationLanguage": "utf-8",
"enforcementMode": "blocking",
"signature-sets": [
{
"name": "All Signatures",
"block": true,
"alarm": true
}
]
}
}
항목설정설명
template.namePOLICY_TEMPLATE_NGINX_BASE기본 WAF Policy Template 사용
applicationLanguageutf-8애플리케이션에서 사용할 문자 인코딩
enforcementModeblocking위반이 탐지된 요청을 차단
signature-sets.nameAll Signatures전체 공격 Signature Set 적용
alarmtrueSignature 탐지 시 이벤트 기록
blocktrueSignature에 매칭되는 요청 차단

작성한 ConfigMap을 적용합니다.

$ kubectl apply -f waf-policy-definitions.yaml

생성된 ConfigMap을 확인합니다.

$ kubectl get configmap waf-policy-definitions

예상 출력은 다음과 같습니다.

NAME DATA AGE
waf-policy-definitions 1 53s

8-2. bundle server 배포

다음으로 WAF Policy JSON을 Policy Bundle로 컴파일하고, 생성된 Bundle을 HTTP로 제공하는 bundle-server를 배포합니다.

bundle-server Pod는 다음 순서로 동작합니다.

  1. initContainer에서 WAF Compiler를 실행하여 attack-signatures-blocking.jsonattack-signatures-blocking.tgz로 컴파일합니다.
  2. 생성된 Bundle을 공유 볼륨에 저장합니다.
  3. NGINX 컨테이너가 동일한 볼륨을 /usr/share/nginx/html에 마운트하여 Bundle 파일을 HTTP로 제공합니다.

bundle-server.yaml 파일을 생성하고 다음 내용을 작성합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
name: bundle-server
spec:
replicas: 1
selector:
matchLabels:
app: bundle-server
template:
metadata:
labels:
app: bundle-server
spec:
imagePullSecrets:
- name: nginx-plus-registry-secret
initContainers:
- name: compile-attack-signatures
image: private-registry.nginx.com/nap/waf-compiler:5.13.1
args:
- -p
- /policies/attack-signatures-blocking.json
- -o
- /bundles/attack-signatures-blocking.tgz
volumeMounts:
- name: policies
mountPath: /policies
- name: bundles
mountPath: /bundles
containers:
- name: bundle-server
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: bundles
mountPath: /usr/share/nginx/html
volumes:
- name: policies
configMap:
name: waf-policy-definitions
- name: bundles
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: bundle-server
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: bundle-server

policies 볼륨에는 앞에서 생성한 ConfigMap의 WAF Policy JSON이 마운트되고, bundles 볼륨은 WAF Compiler와 NGINX 컨테이너가 함께 사용하는 공유 공간으로 사용됩니다.

작성한 리소스를 적용합니다.

$ kubectl apply -f bundle-server.yaml

Deployment, Pod, Service 상태를 확인합니다.

$ kubectl get deployments bundle-server
$ kubectl get pods -l app=bundle-server
$ kubectl get svc bundle-server

정상적으로 배포된 경우 다음과 같이 확인할 수 있습니다.

NAME READY UP-TO-DATE AVAILABLE AGE
bundle-server 1/1 1 1 30s
NAME READY STATUS RESTARTS AGE
bundle-server-6645858f5-ddwsp 1/1 Running 0 46s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
bundle-server ClusterIP 10.97.208.228 <none> 80/TCP 52s

Pod가 시작될 때 initContainer가 먼저 WAF Policy를 컴파일하고 정상적으로 완료된 이후 NGINX 컨테이너가 실행됩니다. 따라서 Pod가 Running 상태라면 생성된 Policy Bundle을 bundle-server Service를 통해 제공할 수 있는 상태입니다.

이후 WAFPolicy에서는 bundle-server의 HTTP URL을 지정하여 생성된 attack-signatures-blocking.tgz Bundle을 참조합니다.

9. Gateway-level WAFPolicy 생성

준비한 WAF Policy Bundle을 사용하여 shared-gateway에 적용할 WAFPolicy를 생성합니다.

targetRefs에서 Gateway를 지정하면 해당 WAFPolicy는 Gateway-level 정책으로 동작합니다. 이번 구성에서는 shared-gateway를 대상으로 지정하여 연결된 app1-routeapp2-route에 동일한 WAF 정책이 적용되도록 구성합니다.

gateway-waf-policy.yaml 파일을 생성하고 다음 내용을 작성합니다.

apiVersion: gateway.nginx.org/v1alpha1
kind: WAFPolicy
metadata:
name: gateway-waf-policy
spec:
type: HTTP
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: shared-gateway
policySource:
httpSource:
url: http://bundle-server.default.svc.cluster.local/attack-signatures-blocking.tgz # url의 형태는 "Service 이름.namespace.svc.cluster.local.앞에서 waf-compiler가 만든 WAF bundle 파일 이름" 입니다.
securityLogs:
- destination:
type: stderr
logSource:
defaultProfile: log_blocked

주요 설정은 다음과 같습니다.

항목설정설명
typeHTTPHTTP 트래픽에 적용할 WAFPolicy
targetRefs.kindGateway정책 적용 대상의 리소스 종류
targetRefs.nameshared-gatewayWAFPolicy를 적용할 Gateway
policySource.httpSource.urlhttp://bundle-server...tgz앞에서 생성한 WAF Policy Bundle의 위치
securityLogs.destination.typestderrSecurity Log 출력 위치
defaultProfilelog_blocked차단된 요청에 대한 Security Log 기록

적용한 WAFPolicy를 적용합니다.

$ kubectl apply -f gateway-waf-policy.yaml

생성된 WAFPolicy를 확인합니다.

$ kubectl get wafpolicy gateway-waf-policy

예상 출력은 다음과 같습니다.

NAME AGE
gateway-waf-policy 7s

gateway-waf-policytargetRefsshared-gateway를 참조합니다. 따라서 이 정책은 개별 HTTPRoute가 아닌 Gateway를 대상으로 적용됩니다.

app1-routeapp2-route는 모두 동일한 shared-gateway에 연결되어 있으므로 두 Route에는 Gateway-level WAFPolicy가 공통으로 적용됩니다.

다음 단계에서는 두 Route에 정상 요청과 동일한 공격 요청을 전달하여 WAF 정책이 공통으로 적용되는지 검증합니다.

10. 동일 공격 요청으로 WAFPolicy 상속 검증

app1-routeapp2-route에 동일한 요청을 전달하여 Gateway-level WAFPolicy가 두 HTTPRoute에 공통으로 적용되는지 확인합니다.

Gateway에 적용된 WAFPolicy는 해당 Gateway에 연결된 HTTPRoute에 상속되므로, 별도의 Route-level WAFPolicy를 구성하지 않은 두 Route에는 동일한 WAF 정책이 적용됩니다.

먼저 각 HTTPRoute에 정상 요청을 전달합니다.

$ curl -H "Host: app1.example.com" http://127.0.0.1:8080/
$ curl -H "Host: app2.example.com" http://127.0.0.1:8080/

정상적으로 구성된 경우 각 요청은 HTTPRoute에 연결된 Backend Service로 전달됩니다.

Server address: 10.244.49.159:8080
Server name: app1-8455b5554c-tqrwx
Date: 22/Jun/2026:02:50:58 +0000
URI: /
Request ID: 83859c7d3e2ef9578143db326c8206f9
Server address: 10.244.49.163:8080
Server name: app2-657c5d4769-2lml5
Date: 22/Jun/2026:02:50:58 +0000
URI: /
Request ID: 13a977dcf08ef999965b3962ec403888

다음으로 XSS 패턴이 포함된 동일한 요청을 두 HTTPRoute에 전달합니다.

$ curl -H "Host: app1.example.com" \
"http://127.0.0.1:8080/?q=<script>alert(1)</script>"
$ curl -H "Host: app2.example.com" \
"http://127.0.0.1:8080/?q=<script>alert(1)</script>"

Gateway-level WAFPolicy가 정상적으로 적용된 경우 두 요청 모두 F5 WAF for NGINX에서 차단되고 Request Rejected 응답을 반환합니다.

<html><head><title>Request Rejected</title></head>
<body>
The requested URL was rejected. Please consult with your administrator.
Your support ID is: 5853220945358267012
</body></html>

두 HTTPRoute에서 동일한 공격 요청이 차단되는 것을 통해 shared-gateway에 적용한 WAFPolicyapp1-routeapp2-route에 공통으로 상속되어 동작하는 것을 확인할 수 있습니다.

차단 응답에서 반환된 Support ID를 이용하여 Data Plane Pod의 Security Log도 확인합니다.

$ kubectl logs shared-gateway-nginx-7dd5fb469d-dl8sg -n default --all-containers=true | grep 5853220945358267012

Security Log에서는 요청의 차단 여부와 적용된 WAF 정책, 탐지된 Violation 및 Attack Signature를 확인할 수 있습니다.

request_status="blocked"
outcome="REJECTED"
outcome_reason="SECURITY_WAF_VIOLATION"
policy_name="attack-signatures-blocking"
support_id="5853220945358267012"
severity="Critical"
violations="Illegal meta character in value,Attack signature detected,Violation Rating Threat detected,Bot Client Detected"
sig_names="XSS script tag end (Parameter) (2),XSS script tag (Parameter),alert() (Parameter)..."

request_status="blocked"outcome="REJECTED"를 통해 요청이 WAF에 의해 차단되었음을 확인할 수 있으며, policy_name에서는 앞에서 구성한 attack-signatures-blocking 정책이 적용된 것을 확인할 수 있습니다.

11. 결론

이번 구성에서는 NGINX Gateway Fabric에서 F5 WAF for NGINX 기능을 활성화하고, 하나의 Gateway에 연결된 두 HTTPRoute를 대상으로 Gateway-level WAFPolicy를 적용했습니다.

WAFPolicy는 개별 HTTPRoute가 아닌 shared-gateway를 대상으로 구성했지만, app1-routeapp2-route 모두에서 동일한 WAF 정책이 적용되는 것을 확인했습니다. Gateway-level WAFPolicy는 해당 Gateway에 연결된 Route에 상속되므로 여러 Route에 공통 보안 정책을 적용할 수 있습니다.

정상 요청은 각 HTTPRoute에 연결된 Backend Service로 전달되었으며, XSS 패턴이 포함된 요청은 두 Route에서 모두 차단되었습니다. Security Log에서도 request_status="blocked", outcome="REJECTED"와 함께 적용된 정책 및 탐지된 Attack Signature를 확인할 수 있었습니다.

이와 같은 Gateway-level WAFPolicy 구성을 사용하면 여러 애플리케이션 Route가 하나의 Gateway를 공유하는 환경에서 동일한 WAF 정책을 반복해서 구성하지 않고 공통으로 적용할 수 있습니다. 필요에 따라 특정 Route에 별도의 Route-level WAFPolicy를 적용하면 해당 Route에서 Gateway-level 정책을 대체하는 구성도 가능합니다.

NGINX STORE에 문의하여 더 자세한 정보를 확인하세요.

NGINX STORE를 통한 솔루션 도입 및 기술지원 무료 상담 신청

* indicates required