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. 전제 조건

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 구성 가이드를 참조하세요.

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

* indicates required