Kubernetes 에 NGINX App Protect WAF v5 배포하기
이 가이드에서는 Kubernetes 환경에서 NGINX App Protect WAF v5 릴리스를 배포하는 방법을 설명합니다.
목차
1. 전제 조건
2. Kubernetes 에 NGINX App Protect WAF 를 배포하기 위한 NGINX 이미지 빌드
2-1. 공식 NGINX 이미지 기반 Dockerfile
2-2. NGINX 오픈소스 Dockerfile
2-3. NGINX Plus Dockerfile
2-4. 이미지 빌드
3. Kubernetes 환경 이미지 NGINX 구성
4. Kubernetes NGINX App Protect WAF 서비스 구성
4-1. JWT Token 혹은 Docker Config Secret
4-2. Kubernetes Manifest 배포
4-3. Kubernetes 배포 시작
5. NGINX에서 컴파일된 App Protect Policy 및 Logging Profile 번들 사용
1. 전제 조건
- 활성된 NGINX App Protect WAF 구독
- Kubernetes 클러스터
kubectlCommand-line 도구
2. Kubernetes 에 NGINX App Protect WAF 를 배포하기 위한 NGINX 이미지 빌드
아래 지침에 따라 NGINX 및 NGINX App Protect 모듈이 포함된 Kubernetes 를 위한 Docker 이미지를 빌드하세요.
활성화 된 상업적 NGINX App Protect WAF 라이선스 파일을 다운로드합니다.
nginx-repo.key
nginx-repo.crt
아래 제공된 예제 중 하나를 사용하여 Docker파일을 생성하여 계속 진행합니다.
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 오픈소스 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. 이미지 빌드
Note: Docker Hub와 같은 공용 컨테이너 레지스트리에 NGINX App Protect WAF v5 이미지를 업로드하지 마세요. 그렇게 하면 NGINX Plus 라이선스 계약에 위배됩니다.
이미지를 빌드하려면 nginx-repo.crt, nginx-repo.key 및 Docker파일이 포함된 디렉터리에서 다음 명령을 실행합니다. 여기서 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. Kubernetes 환경 이미지 NGINX 구성
NGINX 구성은 다음과 같이 진행합니다.
1. 기본 컨텍스트에서 NGINX App Protect WAF v5 모듈을 로드합니다.
load_module modules/ngx_http_app_protect_module.so;
2. http 컨텍스트에서 enforcer address를 구성합니다.
app_protect_enforcer_address 127.0.0.1:50000;
3. http/서버/위치 컨텍스트에서 NGINX App Protect WAF를 사용하도록 설정합니다(proxy_pass/grpc_pass 위치에서만 NGINX App Protect WAF를 사용하도록 설정해야 합니다).
app_protect_enable on;
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. Kubernetes NGINX App Protect WAF 서비스 구성
4-1. JWT Token 혹은 Docker Config Secret
1. Kubernetes Secret을 생성합니다.
kubectl create secret docker-registry regcred --docker-server=private-registry.nginx.com --docker-username= --docker-password=none
--docker-username=<JWT Token>의 내용을 포함하며 토큰 자체를 가리키지 않아야 합니다.
JWT 토큰의 내용을 복사할 때 추가 문자나 여분의 공백이 없는지 확인하세요. 추가 문자나 여분의 공백이 있다면 토큰이 무효화되고 레지스트리에 인증하려고 할 때 401 오류가 발생할 수 있습니다.
비밀번호는 비밀번호를 사용하지 않으므로 none으로 설정합니다.
2. Secret을 인증합니다.
kubectl get secret regcred --output=yaml
3. Manifest를 배포할 때 Secret을 사용합니다. 4-2. Kubernetes Manifest 배포 목차를 참고하세요.
4-2. Kubernetes Manifest 배포
이 구성에서는 두 개의 복제본이 배포되며, 각 복제본은 단일 Kubernetes Pod에서 NGINX와 WAF 서비스를 함께 호스팅합니다.
이 포스트에서는 간단하게 설명하기 위해 hostPath를 지원하는 persistent volume 타입의 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. Kubernetes 배포 시작
1. 위의 매니페스트가 /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 디렉터리 내의 모든 파일에 정의된 구성을 쿠버네티스 클러스터에 적용하도록 kubectl에 지시합니다.
2. 배포를 확인합니다.
- 다음 명령어를 사용하여 배포 상태를 확인합니다.
kubectl get deployments
- Pod가 다음과 같이 실행되고 있는지 확인합니다.
kubectl get pods
- 서비스 상태를 확인합니다.
kubectl get services
- NGINX App Protect WAF의 적용 기능을 확인하려면 다음 요청이 거부되었는지 확인하세요.
curl "<node-external-ip>:<node-port>/<script>"
3. 배포를 다시 시작하려면 다음 명령어를 입력하세요.
kubectl rollout restart deployment.apps/nap5-deployment
4. 배포된 리소스를 제거하려면 다음 명령어를 입력하세요.
kubectl delete -f /home/user/k8s
5. NGINX에서 컴파일된 NGINX App Protect Policy 및 Logging Profile 번들 사용
이 설정에서는 컴파일된 정책 및 로깅 프로파일 번들을 클러스터 노드의 /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 마운트를 사용하여 통합할 수 있습니다.
이 가이드는 Kubernetes 에 NGINX App Protect WAF v5를 배포하기 위한 기본 단계를 제공합니다. 특정 요구 사항에 맞게 배포를 조정해야 할 수도 있습니다.
자세한 구성 옵션 및 고급 배포 전략에 대해서는 NGINX App Protect WAF v5 구성 가이드를 참조하세요.