# Kubernetes Type of document: How-to guide Product: F5 WAF for NGINX --- This page describes how to install F5 WAF for NGINX using Kubernetes. It explains the common steps necessary for any Kubernetes-based deployment, then provides details specific to Helm or Manifests. ## Before you begin To complete this guide, you will need the following pre-requisites: - A [supported operating system](/waf/fundamentals/technical-specifications.md#supported-operating-systems). - [A functional Kubernetes cluster](https://kubernetes.io/docs/setup/) (installed and running). - [kubectl CLI](https://kubernetes.io/docs/tasks/tools/install-kubectl/) configured and connected to your cluster. - [Docker registry credentials](#additional-subscription-credentials-needed-for-deployments) for private-registry.nginx.com, required to pull images. - Ensure you have an active F5 WAF for NGINX subscription (purchased or trial) and have downloaded the associated [SSL certificate, private key, and JWT license](#download-your-subscription-credentials) file from the MyF5 Customer Portal. - [Helm](https://helm.sh/docs/intro/install/) installed, required for deployment. You should read the [IP intelligence](/waf/policies/ip-intelligence.md) and [Secure traffic using mTLS](/waf/configure/secure-mtls.md) topics for additional set-up configuration if you want to use them immediately. There is another optional topic to [Add a read-only filesystem for Kubernetes](/waf/configure/kubernetes-read-only.md). ## Default security policy and logging profile F5 WAF for NGINX uses built-in default security policy and logging profile after installation. To use custom policies or logging profiles, update your NGINX configuration file accordingly. ## Download your subscription credentials **Note:** To access private-registry.nginx.com, you will need to download the JWT license file even when using NGINX Open Source as a base image. **Note:** If you are deploying with Helm, you will also need the JWT license for the `dockerConfigJson`. 1. Log in to [MyF5](https://my.f5.com/manage/s/). 1. Go to **My Products & Plans > Subscriptions** to see your active subscriptions. 1. Find your NGINX subscription, and select the **Subscription ID** for details. 1. Download the **SSL Certificate**, **Private Key** and **JSON Web Token** files from the subscription page. **Note:** Starting from [NGINX Plus Release 33](nginx/releases.md#r33), a JWT file is required for each NGINX Plus instance. For more information, see [About Subscription Licenses](/solutions/about-subscription-licenses.md). **Note:** When using the provided values.yaml for Helm, setting the `appprotect.config.nginxJWT` value ensures that your JWT license is automatically copied to `/etc/nginx/license.jwt` inside the NGINX container. No additional manual copying of the file is needed when deploying with the provided YAML configuration. ## Create a Dockerfile In the same folder as your credential files, create a _Dockerfile_ based on your [desired operating system](/waf/fundamentals/technical-specifications.md#supported-operating-systems) image using an example from the following sections. Alternatively, you may want make your own image based on a Dockerfile using the official NGINX image: #### Dockerfile based on official image This example uses NGINX Open Source as a base: it requires NGINX to be installed as a package from the official repository, instead of being compiled from source. ```dockerfile # syntax=docker/dockerfile:1 # Base image FROM nginx:1.25.5-bookworm # Install F5 WAF for NGINX 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.5-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 ``` **Note:** If you are not using using `custom_log_format.json` or the IP intelligence feature, you should remove any references to them from your Dockerfile. ### Alpine Linux #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_VER's are 3.22 ARG OS_VER="3.22" # Base image FROM alpine:${OS_VER} # Install NGINX OSS and F5 WAF for NGINX 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;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_VER's are 3.22 ARG OS_VER="3.22" # Base image FROM alpine:${OS_VER} # Install NGINX Plus and F5 WAF for NGINX 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;"] ``` ### Amazon Linux #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Base image FROM amazonlinux:2023 # Install NGINX OSS and F5 WAF for NGINX 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 \ yum -y install wget ca-certificates shadow-utils yum-utils \ && echo "[nginx-mainline]" > /etc/yum.repos.d/nginx.repo \ && echo "name=nginx mainline repo" >> /etc/yum.repos.d/nginx.repo \ && echo "baseurl=http://nginx.org/packages/mainline/amzn/2023/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgcheck=1" >> /etc/yum.repos.d/nginx.repo \ && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgkey=https://nginx.org/keys/nginx_signing.key" >> /etc/yum.repos.d/nginx.repo \ && echo "module_hotfixes=true" >> /etc/yum.repos.d/nginx.repo \ && echo "priority=9" >> /etc/yum.repos.d/nginx.repo \ && echo "[app-protect-x-oss]" > /etc/yum.repos.d/app-protect-oss.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-oss.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-oss/amzn/2023/\$basearch/" >> /etc/yum.repos.d/app-protect-oss.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-oss.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-oss.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-oss.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-oss.repo \ && yum -y install app-protect-module-oss \ && yum clean all \ && rm -rf /var/cache/yum \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Base image FROM amazonlinux:2023 # Install NGINX Plus and F5 WAF for NGINX 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 \ yum -y install wget ca-certificates shadow-utils \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/plus-amazonlinux2023.repo \ && echo "[app-protect-x-plus]" > /etc/yum.repos.d/app-protect-plus.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-plus.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-plus/amzn/2023/\$basearch/" >> /etc/yum.repos.d/app-protect-plus.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-plus.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-plus.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-plus.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-plus.repo \ && yum -y install app-protect-module-plus \ && yum clean all \ && rm -rf /var/cache/yum \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` ### Debian #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_CODENAME's are: bullseye/bookworm ARG OS_CODENAME=bookworm # Base image FROM debian:${OS_CODENAME} # Install NGINX OSS and F5 WAF for NGINX 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 -y \ apt-transport-https \ lsb-release \ ca-certificates \ wget \ gnupg2 \ debian-archive-keyring \ && wget -qO - https://nginx.org/keys/nginx_signing.key | gpg --dearmor | \ tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ http://nginx.org/packages/mainline/debian `lsb_release -cs` nginx\n" | \ tee /etc/apt/sources.list.d/nginx.list \ && wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | gpg --dearmor | \ tee /usr/share/keyrings/nginx-static-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-static-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-static-archive-keyring.gpg] \ 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 \ && DEBIAN_FRONTEND="noninteractive" apt-get install -y nginx=1.25.5-1~`lsb_release -cs` app-protect-module-oss \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_CODENAME's are: bullseye/bookworm ARG OS_CODENAME=bookworm # Base image FROM debian:${OS_CODENAME} # Install NGINX Plus and F5 WAF for NGINX 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 -y \ apt-transport-https \ lsb-release \ ca-certificates \ wget \ gnupg2 \ debian-archive-keyring \ && wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | \ gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/plus/debian `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-plus.list \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect-x-plus/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 \ && DEBIAN_FRONTEND="noninteractive" apt-get install -y app-protect-module-plus \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` ### Oracle Linux #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Base image FROM oraclelinux:8 # Install NGINX OSS and F5 WAF for NGINX 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 \ dnf -y install wget ca-certificates yum-utils \ && echo "[nginx-mainline]" > /etc/yum.repos.d/nginx.repo \ && echo "name=nginx mainline repo" >> /etc/yum.repos.d/nginx.repo \ && echo "baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgcheck=1" >> /etc/yum.repos.d/nginx.repo \ && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgkey=https://nginx.org/keys/nginx_signing.key" >> /etc/yum.repos.d/nginx.repo \ && echo "module_hotfixes=true" >> /etc/yum.repos.d/nginx.repo \ && echo "[app-protect-x-oss]" > /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/8/\$basearch/" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-8-x-oss.repo \ && dnf clean all \ && dnf -y install app-protect-module-oss \ && dnf clean all \ && rm -rf /var/cache/dnf \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Base image FROM oraclelinux:8 # Install NGINX Plus and F5 WAF for NGINX 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 \ dnf -y install wget ca-certificates yum-utils \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/nginx-plus-8.repo \ && echo "[app-protect-x-plus]" > /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/8/\$basearch/" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-8-x-plus.repo \ && dnf clean all \ && dnf -y install app-protect-module-plus \ && dnf clean all \ && rm -rf /var/cache/dnf \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` ### RHEL 8 #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Supported UBI_VERSION's are 7/8/9 ARG UBI_VERSION=8 # Base Image FROM registry.access.redhat.com/ubi${UBI_VERSION}/ubi # Define the ARG again after FROM to use it in this stage ARG UBI_VERSION # Install NGINX OSS and F5 WAF for NGINX 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 \ PKG_MANAGER=dnf; \ if [ "${UBI_VERSION}" = "7" ]; then \ PKG_MANAGER=yum; \ fi \ && $PKG_MANAGER -y install wget ca-certificates yum-utils \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && echo "[nginx-mainline]" > /etc/yum.repos.d/nginx.repo \ && echo "name=nginx mainline repo" >> /etc/yum.repos.d/nginx.repo \ && echo "baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgcheck=1" >> /etc/yum.repos.d/nginx.repo \ && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgkey=https://nginx.org/keys/nginx_signing.key" >> /etc/yum.repos.d/nginx.repo \ && echo "module_hotfixes=true" >> /etc/yum.repos.d/nginx.repo \ && echo "[app-protect-x-oss]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && $PKG_MANAGER clean all \ && $PKG_MANAGER install -y app-protect-module-oss \ && $PKG_MANAGER clean all \ && rm -rf /var/cache/$PKG_MANAGER \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Supported UBI_VERSION's are 7/8/9 ARG UBI_VERSION=8 # Base Image FROM registry.access.redhat.com/ubi${UBI_VERSION}/ubi # Define the ARG again after FROM to use it in this stage ARG UBI_VERSION # Install NGINX Plus and F5 WAF for NGINX 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 \ PKG_MANAGER=dnf; \ if [ "${UBI_VERSION}" = "7" ]; then \ PKG_MANAGER=yum; \ NGINX_PLUS_REPO="nginx-plus-7.4.repo"; \ elif [ "${UBI_VERSION}" = "9" ]; then \ NGINX_PLUS_REPO="plus-${UBI_VERSION}.repo"; \ else \ NGINX_PLUS_REPO="nginx-plus-${UBI_VERSION}.repo"; \ fi \ && $PKG_MANAGER -y install wget ca-certificates \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/${NGINX_PLUS_REPO} \ && echo "[app-protect-x-plus]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && $PKG_MANAGER clean all \ && $PKG_MANAGER install -y app-protect-module-plus \ && $PKG_MANAGER clean all \ && rm -rf /var/cache/$PKG_MANAGER \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` ### RHEL 9 #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Supported UBI_VERSION's are 7/8/9 ARG UBI_VERSION=8 # Base Image FROM registry.access.redhat.com/ubi${UBI_VERSION}/ubi # Define the ARG again after FROM to use it in this stage ARG UBI_VERSION # Install NGINX OSS and F5 WAF for NGINX 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 \ PKG_MANAGER=dnf; \ if [ "${UBI_VERSION}" = "7" ]; then \ PKG_MANAGER=yum; \ fi \ && $PKG_MANAGER -y install wget ca-certificates yum-utils \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && echo "[nginx-mainline]" > /etc/yum.repos.d/nginx.repo \ && echo "name=nginx mainline repo" >> /etc/yum.repos.d/nginx.repo \ && echo "baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgcheck=1" >> /etc/yum.repos.d/nginx.repo \ && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgkey=https://nginx.org/keys/nginx_signing.key" >> /etc/yum.repos.d/nginx.repo \ && echo "module_hotfixes=true" >> /etc/yum.repos.d/nginx.repo \ && echo "[app-protect-x-oss]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && $PKG_MANAGER clean all \ && $PKG_MANAGER install -y app-protect-module-oss \ && $PKG_MANAGER clean all \ && rm -rf /var/cache/$PKG_MANAGER \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Base Image FROM rockylinux:9 # Install NGINX Plus and F5 WAF for NGINX 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 \ dnf -y install wget ca-certificates \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/${NGINX_PLUS_REPO} \ && echo "[app-protect-x-plus]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && dnf clean all \ && dnf install -y app-protect-module-plus \ && dnf clean all \ && rm -rf /var/cache/dnf \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` ### Rocky Linux 9 #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Base Image FROM rockylinux:9 # Install NGINX OSS and F5 WAF for NGINX 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 \ dnf -y install wget ca-certificates yum-utils \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && echo "[nginx-mainline]" > /etc/yum.repos.d/nginx.repo \ && echo "name=nginx mainline repo" >> /etc/yum.repos.d/nginx.repo \ && echo "baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgcheck=1" >> /etc/yum.repos.d/nginx.repo \ && echo "enabled=1" >> /etc/yum.repos.d/nginx.repo \ && echo "gpgkey=https://nginx.org/keys/nginx_signing.key" >> /etc/yum.repos.d/nginx.repo \ && echo "module_hotfixes=true" >> /etc/yum.repos.d/nginx.repo \ && echo "[app-protect-x-oss]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-oss/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-oss.repo \ && dnf clean all \ && dnf install -y app-protect-module-oss \ && dnf clean all \ && rm -rf /var/cache/dnf \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Base Image FROM rockylinux:9 # Install NGINX Plus and F5 WAF for NGINX 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 \ dnf -y install wget ca-certificates \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/dependencies.repo \ && wget -P /etc/yum.repos.d https://cs.nginx.com/static/files/${NGINX_PLUS_REPO} \ && echo "[app-protect-x-plus]" > /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "name=nginx-app-protect repo" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "baseurl=https://pkgs.nginx.com/app-protect-x-plus/centos/${UBI_VERSION}/\$basearch/" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientcert=/etc/ssl/nginx/nginx-repo.crt" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "sslclientkey=/etc/ssl/nginx/nginx-repo.key" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "gpgcheck=0" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && echo "enabled=1" >> /etc/yum.repos.d/app-protect-${UBI_VERSION}-x-plus.repo \ && dnf clean all \ && dnf install -y app-protect-module-plus \ && dnf clean all \ && rm -rf /var/cache/dnf \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` ### Ubuntu #### NGINX Open Source ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_CODENAME's are: focal/jammy ARG OS_CODENAME=jammy # Base image FROM ubuntu:${OS_CODENAME} # Install NGINX OSS and F5 WAF for NGINX 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 -y \ apt-transport-https \ lsb-release \ ca-certificates \ wget \ gnupg2 \ ubuntu-keyring \ && wget -qO - https://nginx.org/keys/nginx_signing.key | gpg --dearmor | \ tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx\n" | \ tee /etc/apt/sources.list.d/nginx.list \ && wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | gpg --dearmor | \ tee /usr/share/keyrings/nginx-static-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-static-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-static-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect-x-oss/ubuntu `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 \ && DEBIAN_FRONTEND="noninteractive" apt-get install -y nginx=1.25.5-1~`lsb_release -cs` app-protect-module-oss \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` #### NGINX Plus ```dockerfile # syntax=docker/dockerfile:1 # Supported OS_CODENAME's are: focal/jammy ARG OS_CODENAME=jammy # Base image FROM ubuntu:${OS_CODENAME} # Install NGINX Plus and F5 WAF for NGINX 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 -y \ apt-transport-https \ lsb-release \ ca-certificates \ wget \ gnupg2 \ ubuntu-keyring \ && wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | \ gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \ && gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/plus/ubuntu `lsb_release -cs` nginx-plus\n" | \ tee /etc/apt/sources.list.d/nginx-plus.list \ && printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://pkgs.nginx.com/app-protect-x-plus/ubuntu `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 \ && DEBIAN_FRONTEND="noninteractive" apt-get install -y app-protect-module-plus \ && ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Expose port EXPOSE 80 # Define stop signal STOPSIGNAL SIGQUIT # Set default command CMD ["nginx", "-g", "daemon off;"] ``` ## Build the Docker image Your folder should contain the following files: - _nginx-repo.crt_ - _nginx-repo.key_ - _license.jwt_ - _Dockerfile_ To build an image, use the following command, replacing as appropriate: ```shell sudo docker build --no-cache --platform linux/amd64 \ --secret id=nginx-crt,src=nginx-repo.crt \ --secret id=nginx-key,src=nginx-repo.key \ -t . ``` Once you have built the image, push it to your private image repository, which should be accessible to your Kubernetes cluster. From this point, the steps change based on your installation method: - [Use Helm to install F5 WAF for NGINX](#use-helm-to-install-f5-waf-for-nginx) - [Use Manifests to install F5 WAF for NGINX](#use-manifests-to-install-f5-waf-for-nginx) ## Use Helm to install F5 WAF for NGINX ### Get the Helm chart To get the Helm chart, first configure Docker for the F5 Container Registry. You will need Docker registry credentials to access private-registry.nginx.com. Create a directory and copy your certificate and key to this directory: ```shell mkdir -p /etc/docker/certs.d/private-registry.nginx.com cp /etc/docker/certs.d/private-registry.nginx.com/client.cert cp /etc/docker/certs.d/private-registry.nginx.com/client.key ``` Then use `helm pull` to get the chart, replacing ``: ```shell helm pull oci://private-registry.nginx.com/nap/nginx-app-protect --version --untar ``` Change the working directory afterwards: ```shell cd nginx-app-protect ``` ### Deploy the Helm chart You will need to edit the `values.yaml` file for a few changes: - Update _appprotect.nginx.image.repository_ and _appprotect.nginx.image.tag_ with the image name chosen during when [building the Docker image](#build-the-docker-image). - Update _appprotect.config.nginxJWT_ with your JSON web token (Only necessary when using NGINX Plus) - Update _dockerConfigJson_ to contain the base64 encoded Docker registration credentials You can encode your credentials with the following command: ```shell echo '{ "auths": { "private-registry.nginx.com": { "username": "", "password": "none" } } }' | base64 -w 0``` ``` Alternatively, you can use `kubectl` to create a secret: ```shell kubectl create secret docker-registry regcred -n \ --docker-server=private-registry.nginx.com \ --docker-username= \ --docker-password=none ``` The `` argument should be the _contents_ of the file, not the file itself. Ensure there are no additional characters such as extra whitespace. Once you have updated `values.yaml`, you can install F5 WAF for NGINX using `helm install`: ```shell helm install . ``` You can verify the deployment is successful with `kubectl get`, replacing `namespace` accordingly: ```shell kubectl get pods -n kubectl get svc -n ``` **Note:** At this stage, you have finished deploying F5 WAF for NGINX and can look at [Post-installation checks](#post-installation-checks). ### Helm Chart parameters This table lists the configurable parameters of the F5 WAF for NGINX Helm chart and their default values. To understand the _mTLS Configuration_ options, view the [Secure traffic using mTLS](/waf/configure/secure-mtls.md) topic. | **Topic** | **Parameter** | **Description** | **Default value** | |-------------|---------|-----------------|-------------------| | **Namespace** | _namespace_ | The target Kubernetes namespace where the Helm chart will be deployed. | N/A | | **F5 WAF for NGINX Configuration** | _appprotect.replicas_ | The number of replicas for the F5 WAF for NGINX deployment. | 1 | | | _appprotect.readOnlyRootFilesystem_ | Specifies if the root filesystem is read-only. | false | | | _appprotect.annotations_ | Custom annotations for the deployment. | {} | | **NGINX Configuration** | _appprotect.nginx.image.repository_ | Docker image repository for NGINX. | \/nginx-app-protect-5 | | | _appprotect.nginx.image.tag_ | Docker image tag for NGINX. | latest | | | _appprotect.nginx.imagePullPolicy_ | Image pull policy. | IfNotPresent | | | _appprotect.nginx.resources_ | The CPU and memory resources of the NGINX container. | requests: cpu=10m,memory=16Mi | | **WAF Config Manager** | _appprotect.wafConfigMgr.image.repository_ | Docker image repository for the WAF Configuration Manager. | private-registry.nginx.com/nap/waf-config-mgr | | | _appprotect.wafConfigMgr.image.tag_ | Docker image tag for the WAF Configuration Manager. | | | | _appprotect.wafConfigMgr.imagePullPolicy_ | Image pull policy. | IfNotPresent | | | _appprotect.wafConfigMgr.resources_ | The CPU and memory resources of the WAF Config Manager container. | requests: cpu=10m,memory=16Mi | | **WAF Enforcer** | _appprotect.wafEnforcer.image.repository_ | Docker image repository for the WAF Enforcer. | private-registry.nginx.com/nap/waf-enforcer | | | _appprotect.wafEnforcer.image.tag_ | Docker image tag for the WAF Enforcer. | | | | _appprotect.wafEnforcer.imagePullPolicy_ | Image pull policy. | IfNotPresent | | | _appprotect.wafEnforcer.env.enforcerPort_ | Port for the WAF Enforcer. | 50000 | | | _appprotect.wafEnforcer.resources_ | The CPU and memory resources of the WAF Enforcer container | requests: cpu=20m,memory=256Mi | | **WAF IP Intelligence** | _appprotect.wafIpIntelligence.enable | Enable or disable the use of the IP intelligence container | false | | | _appprotect.wafIpIntelligence.image.repository_ | Docker image repository for the WAF IP Intelligence. | private-registry.nginx.com/nap/waf-ip-intelligence | | | _appprotect.wafIpIntelligence.image.tag_ | Docker image tag for the WAF Enforcer. | | | | _appprotect.wafIpIntelligence.imagePullPolicy_ | Image pull policy. | IfNotPresent | | | _appprotect.wafIpIntelligence.resources_ | The CPU and memory resources of the IP Intelligence container | requests: cpu=10m,memory=256Mi | | **Config** | _appprotect.config.name_ | The name of the ConfigMap used by the NGINX container. | nginx-config | | | _appprotect.config.annotations_ | The annotations of the ConfigMap. | {} | | | _appprotect.config.nginxJWT_ | JWT license for NGINX. | "" | | | _appprotect.config.nginxConf_ | NGINX configuration file content. | See _values.yaml_ | | | _appprotect.config.nginxDefault_ | Default server block configuration for NGINX. | {} | | | _appprotect.config.entries_ | Extra entries of the ConfigMap for customizing NGINX configuration. | {} | | **mTLS Configuration** | _appprotect.mTLS.serverCert_ | The base64-encoded TLS certificate for the F5 WAF for NGINX Enforcer (server). | "" | | | _appprotect.mTLS.serverKey_ | The base64-encoded TLS key for the F5 WAF for NGINX Enforcer (server). | "" | | | _appprotect.mTLS.serverCACert_ | The base64-encoded TLS CA certificate for the F5 WAF for NGINX Enforcer (server). | "" | | | _appprotect.mTLS.clientCert_ | The base64-encoded TLS certificate for the NGINX (client). | "" | | | _appprotect.mTLS.clientKey_ | The base64-encoded TLS key for the NGINX (client). | "" | | | _appprotect.mTLS.clientCACert_ | The base64-encoded TLS CA certificate for the NGINX (client). | "" | | **Extra Volumes** | _appprotect.volumes_ | The extra volumes of the NGINX container. | [] | | **Extra Volume Mounts** | _appprotect.volumeMounts_ | The extra volume mounts of the NGINX container. | [] | | **Service** | _appprotect.service.nginx.ports.port_ | Service port. | 80 | | | _appprotect.service.nginx.ports.protocol_ | Protocol used. | TCP | | | _appprotect.service.nginx.ports.targetPort_ | Target port inside the container. | 80 | | | _appprotect.service.nginx.type_ | Service type. | NodePort | | **Storage Configuration** | _appprotect.storage.bundlesPath.name_ | Bundles volume name used by WAF Config Manager container for storing policy bundles | app-protect-bundles | | | _appprotect.storage.bundlesPath.mountPath_ | Bundles mount path used by WAF Config Manager container, which is the path to the app_protect_policy_file in nginx.conf. | /etc/app_protect/bundles | | | _appprotect.storage.pv.hostPath_ | Host path for persistent volume. | /mnt/nap5_bundles_pv_data | | | _appprotect.storage.pvc.bundlesPvc.storageClass_ | Storage class for PVC. | manual | | | _appprotect.storage.pvc.bundlesPvc.storageRequest_ | Storage request size. | 2Gi | | **Docker Configuration** | _dockerConfigJson_ | A base64-encoded string representing the Docker registry credentials in JSON format. | N/A | ## Use Manifests to install F5 WAF for NGINX ### Update configuration files Once you have installed F5 WAF for NGINX, you must load it as a module in the main context of your NGINX configuration. ```nginx load_module modules/ngx_http_app_protect_module.so; ``` The Enforcer address must be added at the _http_ context: ```nginx app_protect_enforcer_address 127.0.0.1:50000; ``` And finally, F5 WAF for NGINX can enabled on a _http_, _server_ or _location_ context: ```nginx app_protect_enable on; ``` **Note:** You should only enable F5 WAF for NGINX on _proxy_pass_ and _grpc_pass_ locations. Here are two examples of how these additions could look in configuration files: #### nginx.conf The default path for this file is `/etc/nginx/nginx.conf`. ```nginx {hl_lines=[5, 33]} user nginx; worker_processes auto; # F5 WAF for NGINX 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; # F5 WAF for NGINX app_protect_enforcer_address 127.0.0.1:50000; include /etc/nginx/conf.d/*.conf; } ``` #### default.conf The default path for this file is `/etc/nginx/conf.d/default.conf`. ```nginx {hl_lines=[10]} server { listen 80; server_name domain.com; location / { # F5 WAF for NGINX app_protect_enable on; client_max_body_size 0; default_type text/html; proxy_pass http://127.0.0.1:8080/; } } server { listen 8080; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } ``` ### Create a Secret Before you can start the Manifest deployment, you need a Kubernetes secret for the Docker registry. You can create the secret using `kubectl create`: ```shell kubectl create secret docker-registry regcred --docker-server=private-registry.nginx.com --docker-username= --docker-password=none ``` The `` argument should be the _contents_ of the file, not the file itself. Ensure there are no additional characters such as extra whitespace. ### Create Manifest files The default configuration provided creates two replicas, each hosting NGINX and WAF services together in a single Kubernetes pod. Create all of these files in a single folder (Such as `/manifests`). In each file, replace `/waf:` with your actual image tag. #### waf-storage.yaml **Note:** This configuration uses a _hostPath_ backed persistent volume claim. ```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 ``` #### waf-deployment.yaml ```yaml 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: /waf: 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: 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: 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 ``` #### waf-service.yaml ```yaml apiVersion: v1 kind: Service metadata: name: nginx spec: selector: app: nap5 ports: - protocol: TCP port: 80 targetPort: 80 type: NodePort ``` ### Start the Manifest deployment From the folder containing the YAML files from the previous step (Suggested as `/manifests`), deploy F5 WAF for NGINX using `kubectl`: ```shell kubectl apply -f manifests/ ``` It will apply all the configuration defined in the files to your Kubernetes cluster. You can then check the status of the deployment with `kubectl get`: ```shell kubectl get deployments kubectl get pods kubectl get services ``` You should see output similar to the following: ```text deployment.apps/nap5-deployment created service/nginx created persistentvolume/nap5-bundles-pv created persistentvolumeclaim/nap5-bundles-pvc created ``` **Note:** At this stage, you have finished deploying F5 WAF for NGINX and can look at [Post-installation checks](#post-installation-checks). ## Post-installation checks The following steps check that F5 WAF for NGINX enforcement is operational. They should be ran in the environment with the WAF components. Check that the three processes for F5 WAF for NGINX are running using `ps aux`: - _bd-socket-plugin_ - _nginx: master process_ - _nginx: worker process_ ```shell USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 8 1.3 2.4 3486948 399092 ? Sl 09:11 0:02 /usr/share/ts/bin/bd-socket-plugin tmm_count 4 proc_cpuinfo_cpu_mhz 2000000 total_xml_memory 307200000 total_umu_max_size 3129344 sys_max_account_id 1024 no_static_config root 14 0.0 0.1 71060 26680 ? S 09:11 0:00 nginx: master process /usr/sbin/nginx -c /tmp/policy/test_nginx.conf -g daemon off; root 26 0.0 0.3 99236 52092 ? S 09:12 0:00 nginx: worker process root 28 0.0 0.0 11788 2920 pts/0 Ss 09:12 0:00 bash root 43 0.0 0.0 47460 3412 pts/0 R+ 09:14 0:00 ps aux ``` Verify there are no errors in the file `/var/log/nginx/error.log` and that the policy compiled successfully: ```none 2020/05/10 13:21:04 [notice] 402#402: APP_PROTECT { "event": "configuration_load_start", "configSetFile": "/opt/f5waf/config/config_set.json" } 2020/05/10 13:21:04 [notice] 402#402: APP_PROTECT policy 'app_protect_default_policy' from: /etc/app_protect/conf/NginxDefaultPolicy.json compiled successfully 2020/05/10 13:21:04 [notice] 402#402: APP_PROTECT { "event": "configuration_load_success", "software_version": "1.1.1", "attack_signatures_package":{"revision_datetime":"2019-07-16T12:21:31Z"},"completed_successfully":true} 2020/05/10 13:21:04 [notice] 402#402: using the "epoll" event method 2020/05/10 13:21:04 [notice] 402#402: nginx/1.17.6 (nginx-plus-r20) 2020/05/10 13:21:04 [notice] 402#402: built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) 2020/05/10 13:21:04 [notice] 402#402: OS: Linux 3.10.0-957.27.2.el7.x86_64 2020/05/10 13:21:04 [notice] 402#402: getrlimit(RLIMIT_NOFILE): 1048576:1048576 2020/05/10 13:21:04 [notice] 406#406: start worker processes 2020/05/10 13:21:04 [notice] 406#406: start worker process 407 ``` Check that sending an attack signature in a request returns a response block page containing a support ID: ```shell Request: http://10.240.185.211/?a=