NGINX Web Application Firewall v5 Kubernetes에 배포
이 가이드에서는 Kubernetes 환경에서 NGINX Web Application Firewall v5 (NGINX App Protect WAF v5) 릴리스를 배포하는 방법을 설명합니다.
목차
1. 전제 조건
2. NGINX Web Application Firewall 배포를 위한 NGINX 이미지 빌드
2-1. 공식 NGINX 이미지 기반 Dockerfile
2-2. NGINX Open Source Dockerfile
2-3. NGINX Plus Dockerfile
2-4. NGINX Web Application Firewall 이미지 빌드
3. NGINX 설정
4. NGINX Web Application Firewall 서비스 설정
4-1. JWT Token, Docker Config Secret
4-2. Manifest 배포
4-3. 배포 시작
5. NGINX에서 컴파일된 정책 및 로깅 프로필 번들 사용
6. NGINX Web Application Firewall 문제 해결
1. 전제 조건
- MyF5에서 NGINX App Protect WAF 구독(구매 또는 평가판)
- Kubernetes 클러스터
kubectlCommand-line 도구
2. NGINX Web Application Firewall 배포를 위한 NGINX 이미지 빌드
아래 지침에 따라 NGINX 및 NGINX App Protect 모듈이 포함된 Docker 이미지를 빌드하세요.
MyF5에 로그인하여 유효한 NGINX App Protect WAF 구독 메뉴에서 아래 두 파일을 다운로드합니다.
nginx-repo.key
nginx-repo.crt
아래 제공된 예제 중 하나를 사용하여 Dockerfile을 생성하여 계속 진행합니다.
2-1. 공식 NGINX 이미지 기반 Dockerfile
Note:
이 예제에서는 공식 NGINX 오픈소스 이미지를 기반으로 사용하지만, 중요한 점은 NGINX를 source에서 컴파일하는 것이 아니라 공식 NGINX 리포지토리에서 패키지로 설치해야 한다는 것입니다.
# syntax=docker/dockerfile:1
# Base image
FROM nginx:1.25.4-bookworm
# Install NGINX App Protect WAF v5 module
RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \
--mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \
apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y \
apt-transport-https \
lsb-release \
ca-certificates \
wget \
gnupg \
&& wget https://cs.nginx.com/static/keys/nginx_signing.key \
&& gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/nginx.gpg \
--import nginx_signing.key \
&& chmod 644 /etc/apt/trusted.gpg.d/nginx.gpg \
&& printf "deb https://pkgs.nginx.com/app-protect-x-oss/debian `lsb_release -cs` nginx-plus\n" | \
tee /etc/apt/sources.list.d/nginx-app-protect.list \
&& wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx \
&& apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y nginx=1.25.4-1~bookworm app-protect-module-oss \
&& apt-get remove --purge --auto-remove -y apt-transport-https lsb-release gnupg wget \
&& rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx-app-protect.list
2-2. NGINX Open Source Dockerfile
운영 체제(OS)에 맞는 적절한 Dockerfile 예제를 선택합니다.
# syntax=docker/dockerfile:1
# Supported OS_VER's are 3.16/3.17
ARG OS_VER="3.17"
# Base image
FROM alpine:${OS_VER}
# Install NGINX OSS and NGINX App Protect WAF v5 module
RUN --mount=type=secret,id=nginx-crt,dst=/etc/apk/cert.pem,mode=0644 \
--mount=type=secret,id=nginx-key,dst=/etc/apk/cert.key,mode=0644 \
apk add openssl curl ca-certificates \
&& printf "%s%s%s%s\n" \
"http://nginx.org/packages/mainline/alpine/v" \
`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release` \
"/main" \
| tee -a /etc/apk/repositories \
&& wget -O /etc/apk/keys/nginx_signing.rsa.pub https://cs.nginx.com/static/keys/nginx_signing.rsa.pub \
&& printf "https://pkgs.nginx.com/app-protect-x-oss/alpine/v`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release`/main\n" | \
tee -a /etc/apk/repositories \
&& apk update \
&& apk add app-protect-module-oss \
&& ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log \
&& rm -rf /var/cache/apk/*
# Expose port
EXPOSE 80
# Define stop signal
STOPSIGNAL SIGQUIT
# Set default command
CMD ["nginx", "-g", "daemon off;"]
이미지를 빌드할 준비가 되었습니다.
2-3. NGINX Plus Dockerfile
운영 체제(OS)에 맞는 적절한 Dockerfile 예제를 선택합니다.
# syntax=docker/dockerfile:1
# Supported OS_VER's are 3.16/3.17
ARG OS_VER="3.17"
# Base image
FROM alpine:${OS_VER}
# Install NGINX Plus and NGINX App Protect WAF v5 module
RUN --mount=type=secret,id=nginx-crt,dst=/etc/apk/cert.pem,mode=0644 \
--mount=type=secret,id=nginx-key,dst=/etc/apk/cert.key,mode=0644 \
wget -O /etc/apk/keys/nginx_signing.rsa.pub https://cs.nginx.com/static/keys/nginx_signing.rsa.pub \
&& printf "https://pkgs.nginx.com/plus/alpine/v`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release`/main\n" | \
tee -a /etc/apk/repositories \
&& printf "https://pkgs.nginx.com/app-protect-x-plus/alpine/v`egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release`/main\n" | \
tee -a /etc/apk/repositories \
&& apk update \
&& apk add app-protect-module-plus \
&& ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log \
&& rm -rf /var/cache/apk/*
# Expose port
EXPOSE 80
# Define stop signal
STOPSIGNAL SIGQUIT
# Set default command
CMD ["nginx", "-g", "daemon off;"]
2-4. NGINX Web Application Firewall 이미지 빌드
Note:
Docker Hub와 같은 공용 컨테이너 레지스트리에 절대 NGINX App Protect WAF v5 이미지를 업로드하지 마세요. NGINX Plus 라이선스 계약에 위배됩니다.
이미지를 빌드하려면 nginx-repo.crt, nginx-repo.key 및 Dockerfile이 포함된 디렉터리에서 다음 명령을 실행합니다. 여기서 nginx-app-protect-5는 이미지 태그의 예시입니다.
sudo docker build --no-cache \
--secret id=nginx-crt,src=nginx-repo.crt \
--secret id=nginx-key,src=nginx-repo.key \
-t nginx-app-protect-5 .
그리고, private image repository로 push하여 Kubernetes 클러스터에서 접근할 수 있도록 합니다.
3. NGINX 설정
nginx 구성에서:
1. 메인 컨텍스트에서 NGINX App Protect WAF v5 모듈을 불러옵니다.
load_module modules/ngx_http_app_protect_module.so;
2. http 컨텍스트에서 Enforcer 주소를 구성합니다.
app_protect_enforcer_address 127.0.0.1:50000;
3. http/server/location 컨텍스트에서 NGINX App Protect WAF를 활성화합니다.(NGINX App Protect WAF는 proxy_pass/grpc_pass location에서만 활성화해야 합니다.
app_protect_enable on;
이 가이드에서는 다음 파일을 사용했습니다.
# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
# NGINX App Protect WAF
load_module modules/ngx_http_app_protect_module.so;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
# NGINX App Protect WAF
app_protect_enforcer_address 127.0.0.1:50000;
include /etc/nginx/conf.d/*.conf;
}
4. NGINX Web Application Firewall 서비스 설정
4-1. JWT Token, Docker Config Secret
1. Kubernetes Secret을 생성합니다.
kubectl create secret docker-registry regcred --docker-server=private-registry.nginx.com --docker-username=<JWT Token> --docker-password=none
주의할 점은 –docker-username=<JWT Token> 에 토큰 자체가 아닌, 토큰의 내용이 포함되어야 합니다.
JWT 토큰의 내용을 복사할 때 추가 문자나 공백이 없는지 확인하세요. 추가 문자나 여분의 공백이 있다면 토큰이 무효화되고 레지스트리에 인증하려고 할 때 401 오류가 발생할 수 있습니다.
비밀번호를 사용하지 않았으므로 –docker-password는 none으로 설정합니다.
2. Secret을 확인합니다.
kubectl get secret regcred --output=yaml
3. Deployment에 생성한 Secret을 사용합니다.
이제 Manifest 배포에 사용할 Secret이 준비되었습니다.
4-2. Manifest 배포
이 구성에서는 두 개의 pod replica가 배포되며, 각 replica는 단일 Kubernetes Pod에서 NGINX와 NGINX Web Application Firewall 서비스를 함께 호스팅합니다.
간단한 설명을 위해, 이 가이드에서는 hostPath 기반의 persistent volume claim을 사용했습니다.
nap5-storage.yaml:
apiVersion: v1
kind: PersistentVolume
metadata:
name: nap5-bundles-pv
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 2Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: "/mnt/nap5_bundles_pv_data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nap5-bundles-pvc
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
volumeName: nap5-bundles-pv
아래는 nap5-deployment.yaml 예제입니다.<your-private-registry>/nginx-app-protect-5:<your-tag>를 실제 이미지 태그로 바꿉니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nap5-deployment
spec:
selector:
matchLabels:
app: nap5
replicas: 2
template:
metadata:
labels:
app: nap5
spec:
imagePullSecrets:
- name: regcred
containers:
- name: nginx
image: <your-private-registry>/nginx-app-protect-5:<your-tag>
imagePullPolicy: IfNotPresent
volumeMounts:
- name: app-protect-bd-config
mountPath: /opt/app_protect/bd_config
- name: app-protect-config
mountPath: /opt/app_protect/config
- name: waf-enforcer
image: private-registry.nginx.com/nap/waf-enforcer:<version-tag>
imagePullPolicy: IfNotPresent
env:
- name: ENFORCER_PORT
value: "50000"
volumeMounts:
- name: app-protect-bd-config
mountPath: /opt/app_protect/bd_config
- name: waf-config-mgr
image: private-registry.nginx.com/nap/waf-config-mgr:<version-tag>
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- all
volumeMounts:
- name: app-protect-bd-config
mountPath: /opt/app_protect/bd_config
- name: app-protect-config
mountPath: /opt/app_protect/config
- name: app-protect-bundles
mountPath: /etc/app_protect/bundles
volumes:
- name: app-protect-bd-config
emptyDir: {}
- name: app-protect-config
emptyDir: {}
- name: app-protect-bundles
persistentVolumeClaim:
claimName: nap5-bundles-pvc
마지막으로, nap5-service.yaml 파일입니다.
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nap5
ports:
- protocol: TCP
port: 80
targetPort: 80
type: NodePort
4-3. 배포 시작
1. 위의 yaml 파일들이 /home/user/k8s 디렉터리에 저장되어 있다고 가정하면, 다음 명령을 실행하여 배포할 수 있습니다.
kubectl apply -f /home/user/k8s
출력 예제는 다음과 같습니다.
deployment.apps/nap5-deployment created
service/nginx created
service/waf-enforcer created
persistentvolume/nap5-bundles-pv created
persistentvolumeclaim/nap5-bundles-pvc created
이 명령어는 /home/user/k8s 디렉터리 내의 모든 파일에 정의된 구성을 Kubernetes 클러스터에 적용하도록 kubectl에 지시합니다.
2. 배포를 확인합니다.
- 다음 명령어를 사용하여 deployment의 상태를 확인합니다.
kubectl get deployments
- Pod가 다음과 같이 실행되고 있는지 확인합니다.
kubectl get pods
- 서비스 상태를 확인합니다.
kubectl get services
- NGINX Web Application Firewall의 적용을 확인하기 위해, 다음 요청이 거부되는 것을 확인합니다.
curl "<node-external-ip>:<node-port>/<script>"
3. deployment를 재시작하려면 다음 명령어를 입력합니다.
kubectl rollout restart deployment.apps/nap5-deployment
4. 배포된 리소스를 제거하려면 다음 명령어를 입력하세요.
kubectl delete -f /home/user/k8s
5. NGINX에서 컴파일된 정책 및 로깅 프로필 번들 사용
이 설정에서는 컴파일된 정책 및 로깅 프로필 번들을 클러스터 노드의 /mnt/nap5_bundles_pv_data에 복사합니다. 그리고, NGINX 설정에서 /etc/app_protect/bundles에서 이 파일을 참조합니다.
예를 들어 /mnt/nap5_bundles_pv_data/ 경로의 custom_policy.tgz를 적용하려면 다음을 사용합니다.
app_protect_policy_file "/etc/app_protect/bundles/custom_policy.tgz";
NGINX 구성은 configmap 마운트를 사용하여 통합할 수 있습니다.
6. NGINX Web Application Firewall 문제 해결
1. Pod Failures : Pod가 실패하면, 다음 명령어를 통해 로그를 확인하고, 에러 메세지를 확인합니다.
kubectl logs [pod 이름] -c [컨테이너 이름]
기본 컨테이너 이름은 다음과 같습니다.
- nginx
- waf-enforcer
- waf-config-mgr
2. 연결 문제 : service와 deployment의 설정을 확인합니다. 특히 포트 매핑과 selectors 설정을 확인합니다.
3. 권한 문제 : 기본적으로 waf-config-mgr 컨테이너와 waf-enforcer 컨테이너는 사용자 ID와 그룹 ID가 101:101로 설정되어 동작합니다. 번들 파일들이 해당 ID를 통해 접근할 수 있는지 확인하세요.
이 가이드는 Kubernetes에 NGINX Web Application Firewall(NGINX App Protect WAF) v5를 배포하기 위한 기본적인 과정을 설합니다. 특정 요구 사항에 맞게 배포 과정 조정해야 할 수도 있습니다.
자세한 구성 옵션 및 고급 배포 전략에 대해서는 NGINX App Protect WAF v5 구성 가이드를 참조하세요.