diff --git a/.github/config/config-plus-gcr-release b/.github/config/config-plus-gcr-release index 0af0ae550d..0a29939d56 100644 --- a/.github/config/config-plus-gcr-release +++ b/.github/config/config-plus-gcr-release @@ -1,6 +1,7 @@ export TARGET_REGISTRY=gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/release declare -a PLUS_TAG_POSTFIX_LIST=("" "-ubi" "-alpine" "-alpine-fips" "-mktpl" "-alpine-mktpl" "-alpine-mktpl-fips") declare -a NAP_WAF_TAG_POSTFIX_LIST=("" "-ubi" "-mktpl" "-ubi-mktpl" "-alpine-fips") +declare -a NAP_WAFV5_TAG_POSTFIX_LIST=("" "-ubi" "-alpine-fips") declare -a NAP_DOS_TAG_POSTFIX_LIST=("" "-ubi" "-mktpl" "-ubi-mktpl") declare -a NAP_WAF_DOS_TAG_POSTFIX_LIST=("" "-ubi" "-mktpl" "-ubi-mktpl") declare -a ADDITIONAL_TAGS=("latest" "${ADDITIONAL_TAG}") diff --git a/.github/config/config-plus-nginx b/.github/config/config-plus-nginx index de809c41b8..969f28b4d1 100644 --- a/.github/config/config-plus-nginx +++ b/.github/config/config-plus-nginx @@ -2,6 +2,7 @@ export TARGET_REGISTRY=docker-mgmt.nginx.com export TARGET_NAP_WAF_DOS_IMAGE_PREFIX="nginx-ic-nap-dos/nginx-plus-ingress" declare -a PLUS_TAG_POSTFIX_LIST=("" "-ubi" "-alpine" "-alpine-fips") declare -a NAP_WAF_TAG_POSTFIX_LIST=("" "-ubi" "-alpine-fips") +declare -a NAP_WAFV5_TAG_POSTFIX_LIST=("" "-ubi" "-alpine-fips") declare -a NAP_DOS_TAG_POSTFIX_LIST=("" "-ubi") declare -a NAP_WAF_DOS_TAG_POSTFIX_LIST=("" "-ubi") declare -a ADDITIONAL_TAGS=("latest" "${ADDITIONAL_TAG}") diff --git a/.github/scripts/copy-images.sh b/.github/scripts/copy-images.sh index b63fa618e5..b729509a8e 100755 --- a/.github/scripts/copy-images.sh +++ b/.github/scripts/copy-images.sh @@ -28,19 +28,25 @@ TARGET_OSS_IMAGE_PREFIX=${TARGET_OSS_IMAGE_PREFIX:-"nginx-ic/nginx-ingress"} SOURCE_PLUS_IMAGE_PREFIX=${SOURCE_PLUS_IMAGE_PREFIX:-"nginx-ic/nginx-plus-ingress"} SOURCE_NAP_WAF_IMAGE_PREFIX=${SOURCE_NAP_WAF_IMAGE_PREFIX:-"nginx-ic-nap/nginx-plus-ingress"} +SOURCE_NAP_WAFV5_IMAGE_PREFIX=${SOURCE_NAP_WAFV5_IMAGE_PREFIX:-"nginx-ic-nap-v5/nginx-plus-ingress"} SOURCE_NAP_DOS_IMAGE_PREFIX=${SOURCE_NAP_DOS_IMAGE_PREFIX:-"nginx-ic-dos/nginx-plus-ingress"} SOURCE_NAP_WAF_DOS_IMAGE_PREFIX=${SOURCE_NAP_WAF_DOS_IMAGE_PREFIX:-"nginx-ic-dos-nap/nginx-plus-ingress"} +SOURCE_NAP_WAFV5_DOS_IMAGE_PREFIX=${SOURCE_NAP_WAFV5_DOS_IMAGE_PREFIX:-"nginx-ic-dos-nap-v5/nginx-plus-ingress"} TARGET_PLUS_IMAGE_PREFIX=${TARGET_PLUS_IMAGE_PREFIX:-"nginx-ic/nginx-plus-ingress"} TARGET_NAP_WAF_IMAGE_PREFIX=${TARGET_NAP_WAF_IMAGE_PREFIX:-"nginx-ic-nap/nginx-plus-ingress"} +TARGET_NAP_WAFV5_IMAGE_PREFIX=${TARGET_NAP_WAFV5_IMAGE_PREFIX:-"nginx-ic-nap/nginx-plus-ingress"} TARGET_NAP_DOS_IMAGE_PREFIX=${TARGET_NAP_DOS_IMAGE_PREFIX:-"nginx-ic-dos/nginx-plus-ingress"} TARGET_NAP_WAF_DOS_IMAGE_PREFIX=${TARGET_NAP_WAF_DOS_IMAGE_PREFIX:-"nginx-ic-dos-nap/nginx-plus-ingress"} +TARGET_NAP_WAFV5_DOS_IMAGE_PREFIX=${TARGET_NAP_WAFV5_DOS_IMAGE_PREFIX:-"nginx-ic-dos-nap-v5/nginx-plus-ingress"} declare -a OSS_TAG_POSTFIX_LIST=("" "-ubi" "-alpine") declare -a PLUS_TAG_POSTFIX_LIST=("" "-ubi" "-alpine" "-alpine-fips") declare -a NAP_WAF_TAG_POSTFIX_LIST=("" "-ubi" "-alpine-fips") +declare -a NAP_WAFV5_TAG_POSTFIX_LIST=() declare -a NAP_DOS_TAG_POSTFIX_LIST=("" "-ubi") declare -a NAP_WAF_DOS_TAG_POSTFIX_LIST=("" "-ubi") +declare -a NAP_WAFV5_DOS_TAG_POSTFIX_LIST=() declare -a ADDITIONAL_TAGS=("latest" "${ADDITIONAL_TAG}") CONFIG_PATH=${CONFIG_PATH:-~/.nic-release/config} @@ -152,6 +158,29 @@ if $PUBLISH_WAF; then done fi done + for postfix in "${NAP_WAFV5_TAG_POSTFIX_LIST[@]}"; do + image=${SOURCE_REGISTRY}/${SOURCE_NAP_WAFV5_IMAGE_PREFIX}:${SOURCE_TAG}${postfix} + echo "Processing image ${image}" + new_tag=${TARGET_REGISTRY}/${TARGET_NAP_WAFV5_IMAGE_PREFIX}:${TARGET_TAG}${postfix} + if $IS_IMMUTABLE && skopeo --override-os linux --override-arch amd64 inspect docker://${new_tag} > /dev/null 2>&1; then + echo " ECR is immutable & tag ${new_tag} already exists, skipping." + else + echo " Pushing image NAP WAFV5 ${new_tag}..." + if ! $DRY_RUN; then + skopeo copy --retry-times 5 ${ARCH_OPTS} ${SOURCE_OPTS} ${TARGET_OPTS} docker://${image} docker://${new_tag} + fi + for tag in "${ADDITIONAL_TAGS[@]}"; do + if [ -z "${tag}" ]; then + continue + fi + additional_tag=${TARGET_REGISTRY}/${TARGET_NAP_WAFV5_IMAGE_PREFIX}:${tag}${postfix} + echo " Pushing image NAP WAFV5 ${additional_tag}..." + if ! $DRY_RUN; then + skopeo copy --retry-times 5 ${ARCH_OPTS} ${SOURCE_OPTS} ${TARGET_OPTS} docker://${image} docker://${additional_tag} + fi + done + fi + done else echo "Skipping Publish Plus WAF flow" fi diff --git a/.github/workflows/build-plus.yml b/.github/workflows/build-plus.yml index 53f56eed9f..83540e894e 100644 --- a/.github/workflows/build-plus.yml +++ b/.github/workflows/build-plus.yml @@ -123,8 +123,8 @@ jobs: uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 with: images: | - name=gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic${{ contains(inputs.nap_modules, 'dos') && '-dos' || '' }}${{ contains(inputs.nap_modules, 'waf') && '-nap' || '' }}/nginx-plus-ingress - name=docker-mgmt.nginx.com/nginx-ic${{ contains(inputs.nap_modules, 'waf') && '-nap' || '' }}${{ contains(inputs.nap_modules, 'dos') && '-dos' || '' }}/nginx-plus-ingress,enable=${{ inputs.publish-nginx-reqistry && ! contains(inputs.target, 'aws') }} + name=gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic${{ contains(inputs.nap_modules, 'dos') && '-dos' || '' }}${{ contains(inputs.nap_modules, 'waf') && '-nap' || '' }}${{ contains(inputs.image, 'v5') && '-v5' || '' }}/nginx-plus-ingress + name=docker-mgmt.nginx.com/nginx-ic${{ contains(inputs.nap_modules, 'waf') && '-nap' || '' }}${{ contains(inputs.image, 'v5') && '-v5' || '' }}${{ contains(inputs.nap_modules, 'dos') && '-dos' || '' }}/nginx-plus-ingress,enable=${{ inputs.publish-nginx-reqistry && ! contains(inputs.target, 'aws') }} name=709825985650.dkr.ecr.us-east-1.amazonaws.com/nginx/nginx-plus-ingress${{ contains(inputs.nap_modules, 'dos') && '-dos' || '' }}${{ contains(inputs.nap_modules, 'waf') && '-nap' || '' }},enable=${{ inputs.publish-aws-market-place && contains(inputs.target, 'aws') }} flavor: | suffix=${{ contains(inputs.image, 'ubi') && '-ubi' || '' }}${{ contains(inputs.image, 'alpine') && '-alpine' || '' }}${{ contains(inputs.target, 'aws') && '-mktpl' || '' }}${{ contains(inputs.image, 'fips') && '-fips' || ''}},onlatest=true @@ -205,6 +205,7 @@ jobs: PREBUILT_BASE_IMG=gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-base/plus:${{ inputs.base-image-md5 }}-${{ inputs.image }}${{ steps.nap_modules.outputs.name != '' && format('-{0}', steps.nap_modules.outputs.name) || '' }} IC_VERSION=${{ github.ref_type == 'tag' && steps.meta.outputs.version || 'CI' }} ${{ inputs.nap_modules != '' && format('NAP_MODULES={0}', steps.nap_modules.outputs.modules) || '' }} + ${{ contains(inputs.image, 'v5') && 'WAF_VERSION=v5' || '' }} ${{ (contains(inputs.target, 'aws') && inputs.nap_modules != '') && format('NAP_MODULES_AWS={0}', steps.nap_modules.outputs.modules) || '' }} secrets: | "nginx-repo.crt=${{ inputs.nap_modules != '' && secrets.NGINX_AP_CRT || secrets.NGINX_CRT }}" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e784f987e9..4e7c4dc0b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -739,6 +739,22 @@ jobs: target: goreleaser platforms: "linux/amd64" nap_modules: waf + - image: alpine-plus-nap-v5-fips + target: goreleaser + platforms: "linux/amd64" + nap_modules: waf + - image: debian-plus-nap-v5 + target: goreleaser + platforms: "linux/amd64" + nap_modules: waf + - image: ubi-9-plus-nap-v5 + target: goreleaser + platforms: "linux/amd64" + nap_modules: waf + - image: ubi-8-plus-nap-v5 + target: goreleaser + platforms: "linux/amd64" + nap_modules: waf uses: ./.github/workflows/build-plus.yml with: platforms: ${{ matrix.platforms }} diff --git a/Makefile b/Makefile index 94468a59ab..486634438d 100644 --- a/Makefile +++ b/Makefile @@ -31,8 +31,8 @@ export DOCKER_BUILDKIT = 1 .PHONY: help help: Makefile ## Display this help - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "; printf "Usage:\n\n make \033[36m\033[0m [VARIABLE=value...]\n\nTargets:\n\n"}; {printf " \033[36m%-30s\033[0m %s\n", $$1, $$2}' - @grep -E '^(override )?[a-zA-Z_-]+ \??\+?= .*? ## .*$$' $< | sort | awk 'BEGIN {FS = " \\??\\+?= .*? ## "; printf "\nVariables:\n\n"}; {gsub(/override /, "", $$1); printf " \033[36m%-30s\033[0m %s\n", $$1, $$2}' + @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "; printf "Usage:\n\n make \033[36m\033[0m [VARIABLE=value...]\n\nTargets:\n\n"}; {printf " \033[36m%-30s\033[0m %s\n", $$1, $$2}' + @grep -E '^(override )?[a-zA-Z0-9_-]+ \??\+?= .*? ## .*$$' $< | sort | awk 'BEGIN {FS = " \\??\\+?= .*? ## "; printf "\nVariables:\n\n"}; {gsub(/override /, "", $$1); printf " \033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: all all: test lint verify-codegen update-crds debian-image @@ -141,6 +141,13 @@ alpine-image-plus-fips: build ## Create Docker image for Ingress Controller (Alp alpine-image-nap-plus-fips: build ## Create Docker image for Ingress Controller (Alpine with NGINX Plus, NGINX App Protect WAF and FIPS) $(DOCKER_CMD) $(PLUS_ARGS) --build-arg BUILD_OS=alpine-plus-nap-fips --build-arg NGINX_AGENT=$(NGINX_AGENT) +.PHONY: alpine-image-nap-v5-plus-fips +alpine-image-nap-v5-plus-fips: build ## Create Docker image for Ingress Controller (Alpine with NGINX Plus, NGINX App Protect WAFv5 and FIPS) + $(DOCKER_CMD) $(PLUS_ARGS) \ + --build-arg BUILD_OS=alpine-plus-nap-v5-fips \ + --build-arg NGINX_AGENT=$(NGINX_AGENT) \ + --build-arg WAF_VERSION=v5 + .PHONY: debian-image-plus debian-image-plus: build ## Create Docker image for Ingress Controller (Debian with NGINX Plus) $(DOCKER_CMD) $(PLUS_ARGS) --build-arg BUILD_OS=debian-plus @@ -149,6 +156,14 @@ debian-image-plus: build ## Create Docker image for Ingress Controller (Debian w debian-image-nap-plus: build ## Create Docker image for Ingress Controller (Debian with NGINX Plus and NGINX App Protect WAF) $(DOCKER_CMD) $(PLUS_ARGS) --build-arg BUILD_OS=debian-plus-nap --build-arg NAP_MODULES=waf --build-arg NGINX_AGENT=$(NGINX_AGENT) +.PHONY: debian-image-nap-v5-plus +debian-image-nap-v5-plus: build ## Create Docker image for Ingress Controller (Debian with NGINX Plus and NGINX App Protect WAFv5) + $(DOCKER_CMD) $(PLUS_ARGS) \ + --build-arg BUILD_OS=debian-plus-nap-v5 \ + --build-arg NAP_MODULES=waf \ + --build-arg NGINX_AGENT=$(NGINX_AGENT) \ + --build-arg WAF_VERSION=v5 + .PHONY: debian-image-dos-plus debian-image-dos-plus: build ## Create Docker image for Ingress Controller (Debian with NGINX Plus and NGINX App Protect DoS) $(DOCKER_CMD) $(PLUS_ARGS) --build-arg BUILD_OS=debian-plus-nap --build-arg NAP_MODULES=dos @@ -169,6 +184,14 @@ ubi-image-plus: build ## Create Docker image for Ingress Controller (UBI with NG ubi-image-nap-plus: build ## Create Docker image for Ingress Controller (UBI with NGINX Plus and NGINX App Protect WAF) $(DOCKER_CMD) $(PLUS_ARGS) --secret id=rhel_license,src=rhel_license --build-arg BUILD_OS=ubi-9-plus-nap --build-arg NAP_MODULES=waf --build-arg NGINX_AGENT=$(NGINX_AGENT) +.PHONY: ubi-image-nap-v5-plus +ubi-image-nap-v5-plus: build ## Create Docker image for Ingress Controller (UBI with NGINX Plus and NGINX App Protect WAFv5) + $(DOCKER_CMD) $(PLUS_ARGS) --secret id=rhel_license,src=rhel_license \ + --build-arg BUILD_OS=ubi-9-plus-nap-v5 \ + --build-arg NAP_MODULES=waf \ + --build-arg NGINX_AGENT=$(NGINX_AGENT) \ + --build-arg WAF_VERSION=v5 + .PHONY: ubi-image-dos-plus ubi-image-dos-plus: build ## Create Docker image for Ingress Controller (UBI with NGINX Plus and NGINX App Protect DoS) $(DOCKER_CMD) $(PLUS_ARGS) --secret id=rhel_license,src=rhel_license --build-arg BUILD_OS=ubi-8-plus-nap --build-arg NAP_MODULES=dos @@ -177,6 +200,14 @@ ubi-image-dos-plus: build ## Create Docker image for Ingress Controller (UBI wit ubi-image-nap-dos-plus: build ## Create Docker image for Ingress Controller (UBI with NGINX Plus, NGINX App Protect WAF and DoS) $(DOCKER_CMD) $(PLUS_ARGS) --secret id=rhel_license,src=rhel_license --build-arg BUILD_OS=ubi-8-plus-nap --build-arg NAP_MODULES=waf,dos --build-arg NGINX_AGENT=$(NGINX_AGENT) +.PHONY: ubi-image-nap-dos-v5-plus +ubi-image-nap-dos-v5-plus: build ## Create Docker image for Ingress Controller (UBI with NGINX Plus, NGINX App Protect WAFv5 and DoS) + $(DOCKER_CMD) $(PLUS_ARGS) --secret id=rhel_license,src=rhel_license \ + --build-arg BUILD_OS=ubi-8-plus-nap-v5 \ + --build-arg NAP_MODULES=waf,dos \ + --build-arg NGINX_AGENT=$(NGINX_AGENT) \ + --build-arg WAF_VERSION=v5 + .PHONY: all-images ## Create all the Docker images for Ingress Controller all-images: alpine-image alpine-image-plus alpine-image-plus-fips alpine-image-nap-plus-fips debian-image debian-image-plus debian-image-nap-plus debian-image-dos-plus debian-image-nap-dos-plus ubi-image ubi-image-plus ubi-image-nap-plus ubi-image-dos-plus ubi-image-nap-dos-plus diff --git a/build/Dockerfile b/build/Dockerfile index 7fbbdd2590..935e53dde8 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -6,6 +6,7 @@ ARG DEBIAN_FRONTEND=noninteractive ARG PREBUILT_BASE_IMG=nginx/nginx-ingress:${DOWNLOAD_TAG} ARG NGINX_AGENT=false ARG IMAGE_NAME=nginx/nginx-ingress +ARG WAF_VERSION=v4 ############################################# Base images containing libs for Opentracing and FIPS ############################################# @@ -13,7 +14,7 @@ FROM ghcr.io/nginxinc/k8s-common:nginx-opentracing-1.27.0@sha256:d9f6f930b7bfcc0 FROM ghcr.io/nginxinc/k8s-common:nginx-opentracing-1.27.0-alpine@sha256:5dc5c76384a775316c541995b145d4cef86d529934951319fd127f4d4fdb9ef7 as alpine-opentracing-lib FROM ghcr.io/nginxinc/alpine-fips:0.1.0-alpine3.17@sha256:f00b3f266422feaaac7b733b46903bd19eb1cd1caa6991131576f5f767db76f8 as alpine-fips-3.17 FROM ghcr.io/nginxinc/alpine-fips:0.2.0-alpine3.19@sha256:1744ae3a8e795daf771f3f7df33b83160981545abb1f1597338e2769d06aa1cc as alpine-fips-3.19 -FROM redhat/ubi9-minimal@sha256:0d6b09f233745d2fcf892cebcf1c18bbfed497f116bc8357e9db4b724d76c5a9 AS ubi-minimal +FROM redhat/ubi9-minimal@sha256:2636170dc55a0931d013014a72ae26c0c2521d4b61a28354b3e2e5369fa335a3 AS ubi-minimal FROM golang:1.22-alpine@sha256:9bdd5692d39acc3f8d0ea6f81327f87ac6b473dd29a2b6006df362bff48dd1f8 as golang-builder @@ -71,17 +72,21 @@ ADD --link --chown=101:0 https://cs.nginx.com/static/files/nginx-plus-8.repo ngi ADD --link --chown=101:0 https://cs.nginx.com/static/files/plus-9.repo nginx-plus-9.repo ADD --link --chown=101:0 https://cs.nginx.com/static/files/app-protect-8.repo app-protect-8.repo ADD --link --chown=101:0 https://cs.nginx.com/static/files/app-protect-9.repo app-protect-9.repo +ADD --link --chown=101:0 https://raw.githubusercontent.com/nginxinc/k8s-common/main/files/nap-waf-v5-ubi-8.repo app-protect-v5-8.repo +ADD --link --chown=101:0 https://raw.githubusercontent.com/nginxinc/k8s-common/main/files/nap-waf-v5-ubi-9.repo app-protect-v5-9.repo ADD --link --chown=101:0 https://cs.nginx.com/static/files/app-protect-dos-8.repo app-protect-dos-8.repo ADD --link --chown=101:0 https://raw.githubusercontent.com/nginxinc/k8s-common/main/files/plus-debian-11.repo debian-plus-11.sources ADD --link --chown=101:0 https://raw.githubusercontent.com/nginxinc/k8s-common/main/files/plus-debian-12.repo debian-plus-12.sources ADD --link --chown=101:0 https://raw.githubusercontent.com/nginxinc/k8s-common/main/files/nap-waf-debian-11.repo nap-waf-11.sources ADD --link --chown=101:0 https://raw.githubusercontent.com/nginxinc/k8s-common/main/files/nap-dos-debian-11.repo nap-dos-11.sources +ADD --link --chown=101:0 https://raw.githubusercontent.com/nginxinc/k8s-common/main/files/nap-waf-v5-debian-12.repo nap-waf-v5-12.sources ADD --link --chown=101:0 https://raw.githubusercontent.com/nginxinc/k8s-common/main/files/agent-debian-11.repo debian-agent-11.sources RUN --mount=from=busybox:musl,src=/bin/,dst=/bin/ printf "%s\n" "Acquire::https::pkgs.nginx.com::User-Agent k8s-ic-$IC_VERSION${BUILD_OS##debian-plus}-apt;" >> 90pkgs-nginx \ && printf "%s\n" "user_agent=k8s-ic-$IC_VERSION${BUILD_OS##ubi*plus}-dnf" | tee -a nginx-plus-*.repo \ && sed -i -e "s;%VERSION%;${NGINX_PLUS_VERSION};g" *.sources \ - && sed -i -e "y/0/1/" -e "1,8s;/centos;/${NGINX_PLUS_VERSION}/centos;" *.repo \ + && sed -i -e "y/0/1/" app-protect-v5-*.repo \ + && sed -i -e "y/0/1/" -e "1,8s;/centos;/${NGINX_PLUS_VERSION}/centos;" nginx-plus-*.repo app-protect-?.repo app-protect-dos-8.repo \ && echo HTTP_USER_AGENT="k8s-ic-$IC_VERSION${BUILD_OS##alpine-plus}-apk" > user_agent ADD --link --chown=101:0 https://cs.nginx.com/static/files/nginx-agent.repo nginx-agent.repo @@ -106,6 +111,7 @@ RUN --mount=type=bind,from=nginx-files,src=patch-os.sh,target=/usr/local/bin/pat && patch-os.sh USER 101 + ############################################# Base image for Alpine with NGINX Plus ############################################# FROM alpine:3.19@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b as alpine-plus ARG NGINX_PLUS_VERSION @@ -136,6 +142,7 @@ RUN --mount=type=bind,from=alpine-fips-3.19,target=/tmp/fips/ \ ############################################# Base image for Alpine with NGINX Plus, App Protect WAF and FIPS ############################################# FROM alpine:3.17@sha256:53cf9478b76f4c8fae126acbdfb79bed6e69e628faff572ebe4a029d3d247d98 as alpine-plus-nap-fips ARG NGINX_PLUS_VERSION +ARG NGINX_AGENT RUN --mount=type=bind,from=alpine-fips-3.17,target=/tmp/fips/ \ --mount=type=secret,id=nginx-repo.crt,dst=/etc/apk/cert.pem,mode=0644 \ @@ -150,7 +157,7 @@ RUN --mount=type=bind,from=alpine-fips-3.17,target=/tmp/fips/ \ && printf "%s\n" "https://pkgs.nginx.com/app-protect-security-updates/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \ && printf "%s\n" "https://pkgs.nginx.com/nginx-agent/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \ && apk add --no-cache libcap-utils libcurl nginx-plus nginx-plus-module-njs nginx-plus-module-opentracing nginx-plus-module-fips-check \ - && if [ -z "${NGINX_AGENT##true}" ]; then apk add --no-cache nginx-agent; fi \ + && if [ "${NGINX_AGENT}" = "true" ]; then apk add --no-cache nginx-agent; fi \ && mkdir -p /usr/ssl \ && cp -av /tmp/fips/usr/lib/ossl-modules/fips.so /usr/lib/ossl-modules/fips.so \ && cp -av /tmp/fips/usr/ssl/fipsmodule.cnf /usr/ssl/fipsmodule.cnf \ @@ -160,11 +167,41 @@ RUN --mount=type=bind,from=alpine-fips-3.17,target=/tmp/fips/ \ && apk add --no-cache app-protect app-protect-attack-signatures app-protect-threat-campaigns \ && sed -i -e '/nginx.com/d' /etc/apk/repositories \ && nap-waf.sh \ - && if [ -z "${NGINX_AGENT##true}" ]; then \ + && if [ "${NGINX_AGENT}" = "true" ]; then \ agent.sh \ ; fi +############################################# Base image for Alpine with NGINX Plus, App Protect WAFv5 and FIPS ############################################# +FROM alpine:3.17@sha256:53cf9478b76f4c8fae126acbdfb79bed6e69e628faff572ebe4a029d3d247d98 as alpine-plus-nap-v5-fips +ARG NGINX_PLUS_VERSION +ARG NGINX_AGENT + +RUN --mount=type=bind,from=alpine-fips-3.17,target=/tmp/fips/ \ + --mount=type=secret,id=nginx-repo.crt,dst=/etc/apk/cert.pem,mode=0644 \ + --mount=type=secret,id=nginx-repo.key,dst=/etc/apk/cert.key,mode=0644 \ + --mount=type=bind,from=alpine-opentracing-lib,target=/tmp/ot/ \ + --mount=type=bind,from=nginx-files,src=nginx_signing.rsa.pub,target=/etc/apk/keys/nginx_signing.rsa.pub \ + --mount=type=bind,from=nginx-files,src=agent.sh,target=/usr/local/bin/agent.sh \ + --mount=type=bind,from=nginx-files,src=nap-waf.sh,target=/usr/local/bin/nap-waf.sh \ + printf "%s\n" "https://pkgs.nginx.com/plus/${NGINX_PLUS_VERSION}/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \ + && printf "%s\n" "https://pkgs.nginx.com/app-protect-x-plus/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \ + && printf "%s\n" "https://pkgs.nginx.com/nginx-agent/alpine/v$(grep -E -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \ + && apk add --no-cache libcap-utils libcurl nginx-plus nginx-plus-module-njs nginx-plus-module-opentracing nginx-plus-module-fips-check \ + && if [ "${NGINX_AGENT}" = "true" ]; then apk add --no-cache nginx-agent; fi \ + && mkdir -p /usr/ssl \ + && cp -av /tmp/fips/usr/lib/ossl-modules/fips.so /usr/lib/ossl-modules/fips.so \ + && cp -av /tmp/fips/usr/ssl/fipsmodule.cnf /usr/ssl/fipsmodule.cnf \ + && cp -av /tmp/fips/etc/ssl/openssl.cnf /etc/ssl/openssl.cnf \ + && cp -av /tmp/ot/usr/local/lib/libjaegertracing*so* /tmp/ot/usr/local/lib/libzipkin*so* /tmp/ot/usr/local/lib/libdd*so* /tmp/ot/usr/local/lib/libyaml*so* /usr/local/lib/ \ + && ldconfig /usr/local/lib/ \ + && apk add --no-cache app-protect-module-plus \ + && sed -i -e '/nginx.com/d' /etc/apk/repositories \ + && nap-waf.sh \ + && if [ "${NGINX_AGENT}" = "true" ]; then \ + agent.sh \ + ; fi + ############################################# Base image for Debian with NGINX Plus ############################################# FROM debian:12-slim@sha256:804194b909ef23fb995d9412c9378fb3505fe2427b70f3cc425339e48a828fca AS debian-plus @@ -192,6 +229,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode ############################################# Base image for Debian with NGINX Plus and App Protect WAF/DoS ############################################# FROM debian:11-slim@sha256:0e75382930ceb533e2f438071307708e79dc86d9b8e433cc6dd1a96872f2651d as debian-plus-nap ARG NAP_MODULES +ARG NGINX_AGENT RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-repo.key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ @@ -222,7 +260,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode && apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y nginx-plus nginx-plus-module-njs nginx-plus-module-opentracing nginx-plus-module-fips-check libcap2-bin libcurl4 \ ## end of duplicated code - && if [ -z "${NGINX_AGENT##true}" ]; then apt-get install --no-install-recommends --no-install-suggests -y nginx-agent; fi \ + && if [ "${NGINX_AGENT}" = "true" ]; then apt-get install --no-install-recommends --no-install-suggests -y nginx-agent; fi \ && if [ -z "${NAP_MODULES##*waf*}" ]; then \ apt-get install --no-install-recommends --no-install-suggests -y app-protect app-protect-attack-signatures app-protect-threat-campaigns; \ fi \ @@ -243,7 +281,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode && rm -rf /var/lib/apt/lists/* \ && if [ -z "${NAP_MODULES##*waf*}" ]; then \ nap-waf.sh \ - && if [ -z "${NGINX_AGENT##true}" ]; then \ + && if [ "${NGINX_AGENT}" = "true" ]; then \ agent.sh \ ; fi \ ; fi \ @@ -251,9 +289,32 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode nap-dos.sh \ ; fi -# Uncomment the lines below if you want to install a custom CA certificate -# COPY build/*.crt /usr/local/share/ca-certificates/ -# RUN update-ca-certificates +############################################# Base image for Debian with NGINX Plus and App Protect WAFv5/DoS ############################################# +FROM debian-plus as debian-plus-nap-v5 +ARG NAP_MODULES +ARG NGINX_AGENT + +RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ + --mount=type=secret,id=nginx-repo.key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ + --mount=type=bind,from=nginx-files,src=90pkgs-nginx,target=/etc/apt/apt.conf.d/90pkgs-nginx \ + --mount=type=bind,from=nginx-files,src=nap-waf-v5-12.sources,target=/tmp/app-protect.sources \ + --mount=type=bind,from=nginx-files,src=agent.sh,target=/usr/local/bin/agent.sh \ + --mount=type=bind,from=nginx-files,src=nap-waf.sh,target=/usr/local/bin/nap-waf.sh \ + --mount=type=bind,from=nginx-files,src=debian-agent-11.sources,target=/etc/apt/sources.list.d/nginx-agent.sources \ + if [ -z "${NAP_MODULES##*waf*}" ]; then \ + cp /tmp/app-protect.sources /etc/apt/sources.list.d/app-protect.sources; \ + fi \ + && apt-get update \ + && if [ "${NGINX_AGENT}" = "true" ]; then apt-get install --no-install-recommends --no-install-suggests -y nginx-agent; fi \ + && if [ -z "${NAP_MODULES##*waf*}" ]; then \ + apt-get install --no-install-recommends --no-install-suggests -y app-protect-module-plus; \ + rm -f /etc/apt/sources.list.d/app-protect.sources; \ + nap-waf.sh; \ + fi \ + && apt-get purge --auto-remove -y gpg \ + && if [ "${NGINX_AGENT}" = "true" ]; then \ + agent.sh; \ + fi ############################################# Base image for UBI with NGINX Plus ############################################# @@ -277,6 +338,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode ############################################# Base image for UBI with NGINX Plus and App Protect WAF ############################################# FROM ubi-minimal as ubi-9-plus-nap ARG NAP_MODULES +ARG NGINX_AGENT RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-repo.key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ @@ -295,7 +357,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode && useradd --system --gid nginx --no-create-home --home-dir /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx \ && rpm --import /tmp/nginx_signing.key \ && microdnf --nodocs install -y nginx-plus nginx-plus-module-njs nginx-plus-module-fips-check \ - && if [ -z "${NGINX_AGENT##true}" ]; then microdnf --nodocs install -y nginx-agent; fi \ + && if [ "${NGINX_AGENT}" = "true" ]; then microdnf --nodocs install -y nginx-agent; fi \ && subscription-manager register --org=${RHEL_ORGANIZATION} --activationkey=${RHEL_ACTIVATION_KEY} || true \ && subscription-manager attach \ && rpm --import /tmp/app-protect-security-updates.key \ @@ -309,13 +371,57 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode && subscription-manager unregister \ && microdnf remove -y shadow-utils subscription-manager \ && microdnf clean all && rm -rf /var/cache/dnf \ - && if [ -z "${NGINX_AGENT##true}" ]; then \ + && if [ "${NGINX_AGENT}" = "true" ]; then \ agent.sh \ ; fi + +############################################# Base image for UBI with NGINX Plus and App Protect WAFv5 ############################################# +FROM ubi-minimal as ubi-9-plus-nap-v5 +ARG NAP_MODULES +ARG NGINX_AGENT + +RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ + --mount=type=secret,id=nginx-repo.key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ + --mount=type=secret,id=rhel_license,dst=/tmp/rhel_license,mode=0644 \ + --mount=type=bind,from=nginx-files,src=nginx_signing.key,target=/tmp/nginx_signing.key \ + --mount=type=bind,from=nginx-files,src=nginx-plus-9.repo,target=/etc/yum.repos.d/nginx-plus.repo,rw \ + --mount=type=bind,from=nginx-files,src=nginx-agent.repo,target=/etc/yum.repos.d/nginx-agent.repo,rw \ + --mount=type=bind,from=nginx-files,src=app-protect-v5-9.repo,target=/tmp/app-protect-9.repo \ + --mount=type=bind,from=nginx-files,src=agent.sh,target=/usr/local/bin/agent.sh \ + --mount=type=bind,from=nginx-files,src=nap-waf.sh,target=/usr/local/bin/nap-waf.sh \ + source /tmp/rhel_license \ + && rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm \ + && microdnf --nodocs install -y shadow-utils ca-certificates subscription-manager \ + && groupadd --system --gid 101 nginx \ + && useradd --system --gid nginx --no-create-home --home-dir /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx \ + && rpm --import /tmp/nginx_signing.key \ + && microdnf --nodocs install -y nginx-plus nginx-plus-module-njs nginx-plus-module-fips-check \ + && if [ "${NGINX_AGENT}" = "true" ]; then microdnf --nodocs install -y nginx-agent; fi \ + && subscription-manager register --org=${RHEL_ORGANIZATION} --activationkey=${RHEL_ACTIVATION_KEY} || true \ + && subscription-manager attach \ + && if [ -z "${NAP_MODULES##*waf*}" ]; then \ + cp /tmp/app-protect-9.repo /etc/yum.repos.d/app-protect-9.repo; \ + fi \ + && if [ -z "${NAP_MODULES##*waf*}" ]; then \ + cp /tmp/app-protect-9.repo /etc/yum.repos.d/app-protect-9.repo \ + && microdnf --enablerepo=codeready-builder-for-rhel-9-x86_64-rpms --nodocs install -y app-protect-module-plus \ + && rm -f /etc/yum.repos.d/app-protect-9.repo \ + && nap-waf.sh \ + && rm -f /etc/yum.repos.d/app-protect-9.repo; \ + fi \ + && subscription-manager unregister \ + && microdnf remove -y shadow-utils subscription-manager \ + && microdnf clean all && rm -rf /var/cache/dnf \ + && if [ "${NGINX_AGENT}" = "true" ]; then \ + agent.sh; \ + fi + + ############################################# Base image for UBI with NGINX Plus and App Protect WAF & DoS ############################################# FROM redhat/ubi8@sha256:143123d85045df426c5bbafc6863659880ebe276eb02c77ee868b88d08dbd05d as ubi-8-plus-nap ARG NAP_MODULES +ARG NGINX_AGENT RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ --mount=type=secret,id=nginx-repo.key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ @@ -328,6 +434,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode --mount=type=bind,from=nginx-files,src=app-protect-dos-8.repo,target=/tmp/app-protect-dos-8.repo \ --mount=type=bind,from=nginx-files,src=nap-waf.sh,target=/usr/local/bin/nap-waf.sh \ --mount=type=bind,from=nginx-files,src=nap-dos.sh,target=/usr/local/bin/nap-dos.sh \ + --mount=type=bind,from=nginx-files,src=agent.sh,target=/usr/local/bin/agent.sh \ source /tmp/rhel_license \ && if [ -z "${NAP_MODULES##*waf*}" ]; then \ cp /tmp/app-protect-8.repo /etc/yum.repos.d/app-protect-8.repo; \ @@ -340,7 +447,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode && useradd --system --gid nginx --no-create-home --home-dir /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx \ && rpm --import /tmp/nginx_signing.key \ && dnf --nodocs install -y nginx-plus nginx-plus-module-njs nginx-plus-module-fips-check \ - && if [ -z "${NGINX_AGENT##true}" ]; then dnf --nodocs install -y nginx-agent; fi \ + && if [ "${NGINX_AGENT}" = "true" ]; then dnf --nodocs install -y nginx-agent; fi \ ## end of duplicated code ## fix for CVEs && sed -i 's/\(def in_container():\)/\1\n return False/g' /usr/lib64/python*/*-packages/rhsm/config.py \ @@ -366,11 +473,55 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode rm -f /etc/yum.repos.d/app-protect-dos-8.repo \ && nap-dos.sh; \ fi \ + && if [ "${NGINX_AGENT}" = "true" ]; then \ + agent.sh; \ + fi \ && dnf clean all -# Uncomment the lines below if you want to install a custom CA certificate -# COPY build/*.crt /etc/pki/ca-trust/source/anchors/ -# RUN update-ca-trust extract + +############################################# Base image for UBI with NGINX Plus and App Protect WAFv5 ############################################# +FROM redhat/ubi8@sha256:f4292f415f60632a0ff9c0646c4fa859d8b2e1e88a16faa90c6decd1951aea88 as ubi-8-plus-nap-v5 +ARG NAP_MODULES +ARG NGINX_AGENT + +RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ + --mount=type=secret,id=nginx-repo.key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ + --mount=type=secret,id=rhel_license,dst=/tmp/rhel_license,mode=0644 \ + --mount=type=bind,from=nginx-files,src=nginx_signing.key,target=/tmp/nginx_signing.key \ + --mount=type=bind,from=nginx-files,src=nginx-plus-8.repo,target=/etc/yum.repos.d/nginx-plus.repo,rw \ + --mount=type=bind,from=nginx-files,src=nginx-agent.repo,target=/etc/yum.repos.d/nginx-agent.repo,rw \ + --mount=type=bind,from=nginx-files,src=app-protect-v5-8.repo,target=/tmp/app-protect-8.repo \ + --mount=type=bind,from=nginx-files,src=app-protect-dos-8.repo,target=/tmp/app-protect-dos-8.repo \ + --mount=type=bind,from=nginx-files,src=nap-waf.sh,target=/usr/local/bin/nap-waf.sh \ + --mount=type=bind,from=nginx-files,src=agent.sh,target=/usr/local/bin/agent.sh \ + source /tmp/rhel_license \ + && if [ -z "${NAP_MODULES##*waf*}" ]; then \ + cp /tmp/app-protect-8.repo /etc/yum.repos.d/app-protect-8.repo; \ + fi \ + ## the code below is duplicated from the ubi-plus image because NAP DOS doesn't support UBI 9 and minimal versions + && groupadd --system --gid 101 nginx \ + && useradd --system --gid nginx --no-create-home --home-dir /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx \ + && rpm --import /tmp/nginx_signing.key \ + && dnf --nodocs install -y nginx-plus nginx-plus-module-njs nginx-plus-module-fips-check \ + && if [ "${NGINX_AGENT}" = "true" ]; then dnf --nodocs install -y nginx-agent; fi \ + ## end of duplicated code + && sed -i 's/\(def in_container():\)/\1\n return False/g' /usr/lib64/python*/*-packages/rhsm/config.py \ + && subscription-manager register --org=${RHEL_ORGANIZATION} --activationkey=${RHEL_ACTIVATION_KEY} || true \ + && subscription-manager attach \ + && dnf config-manager --set-enabled codeready-builder-for-rhel-8-x86_64-rpms \ + && dnf --nodocs install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm \ + && if [ -z "${NAP_MODULES##*waf*}" ]; then \ + dnf --nodocs install -y app-protect-module-plus; \ + fi \ + && subscription-manager unregister \ + && if [ -z "${NAP_MODULES##*waf*}" ]; then \ + rm -f /etc/yum.repos.d/app-protect-8.repo \ + && nap-waf.sh; \ + fi \ + && if [ "${NGINX_AGENT}" = "true" ]; then \ + agent.sh; \ + fi \ + && dnf clean all ############################################# Create common files, permissions and setcap ############################################# @@ -387,10 +538,6 @@ RUN --mount=type=bind,target=/tmp \ patch-os.sh \ && common.sh -# Uncomment the line below if you would like to add the default.pem to the image -# and use it as a certificate and key for the default server -# ADD default.pem /etc/nginx/secrets/default - EXPOSE 80 443 STOPSIGNAL SIGTERM @@ -420,6 +567,7 @@ RUN --mount=type=bind,target=/go/src/github.com/nginxinc/kubernetes-ingress/ --m -o /nginx-ingress github.com/nginxinc/kubernetes-ingress/cmd/nginx-ingress \ && setcap 'cap_net_bind_service=+ep' /nginx-ingress && setcap -v 'cap_net_bind_service=+ep' /nginx-ingress + ############################################# Download delve ############################################# FROM golang-builder AS debug-builder ARG TARGETARCH @@ -560,6 +708,7 @@ COPY --link --chown=101:0 dist/aws*${NAP_MODULES_AWS}_linux_${TARGETARCH}*/nginx USER 0 RUN setcap 'cap_net_bind_service=+ep' /nginx-ingress && setcap -v 'cap_net_bind_service=+ep' /nginx-ingress + ############################################# Create image with nginx-ingress built by GoReleaser for AWS Marketplace ############################################# FROM common AS aws ARG TARGETARCH diff --git a/build/scripts/agent.sh b/build/scripts/agent.sh index b304b0c7c7..0cb6a07ffd 100755 --- a/build/scripts/agent.sh +++ b/build/scripts/agent.sh @@ -2,9 +2,13 @@ set -e -NAP_VERSION=$(cat /opt/app_protect/VERSION) -mkdir -p /etc/ssl/nms /opt/nms-nap-compiler -chown -R 101:0 /etc/ssl/nms /opt/nms-nap-compiler -chmod -R g=u /etc/ssl/nms /opt/nms-nap-compiler -ln -s /opt/app_protect "/opt/nms-nap-compiler/app_protect-${NAP_VERSION}" +if [ -z "${WAF_VERSION##*v4*}" ]; then + NAP_VERSION=$(cat /opt/app_protect/VERSION) + + mkdir -p /etc/ssl/nms /opt/nms-nap-compiler + chown -R 101:0 /etc/ssl/nms /opt/nms-nap-compiler + chmod -R g=u /etc/ssl/nms /opt/nms-nap-compiler + + ln -s /opt/app_protect "/opt/nms-nap-compiler/app_protect-${NAP_VERSION}" +fi diff --git a/build/scripts/nap-waf.sh b/build/scripts/nap-waf.sh index 5d295ea500..cf736732d7 100755 --- a/build/scripts/nap-waf.sh +++ b/build/scripts/nap-waf.sh @@ -2,7 +2,12 @@ set -e -mkdir -p /etc/nginx/waf/nac-policies /etc/nginx/waf/nac-logconfs /etc/nginx/waf/nac-usersigs /var/log/app_protect /opt/app_protect -chown -R 101:0 /etc/app_protect /usr/share/ts /var/log/app_protect/ /opt/app_protect/ -chmod -R g=u /etc/app_protect /usr/share/ts /var/log/app_protect/ /opt/app_protect/ +for i in /etc/nginx/waf/nac-policies /etc/nginx/waf/nac-logconfs /etc/nginx/waf/nac-usersigs /etc/app_protect /usr/share/ts /var/log/app_protect/ /opt/app_protect/; do + if [ ! -d ${i} ]; then + mkdir -p ${i} + fi + chown -R 101:0 ${i} + chmod -R g=u ${i} +done + touch /etc/nginx/waf/nac-usersigs/index.conf diff --git a/charts/nginx-ingress/README.md b/charts/nginx-ingress/README.md index 239ed97490..7e44b0933c 100644 --- a/charts/nginx-ingress/README.md +++ b/charts/nginx-ingress/README.md @@ -443,6 +443,20 @@ The following tables lists the configurable parameters of the NGINX Ingress Cont |`controller.pod.annotations` | The annotations of the Ingress Controller pod. | {} | |`controller.pod.extraLabels` | The additional extra labels of the Ingress Controller pod. | {} | |`controller.appprotect.enable` | Enables the App Protect WAF module in the Ingress Controller. | false | +|`controller.appprotect.v5` | Enables App Protect WAF v5. | false | +|`controller.appprotect.volumes` | Volumes for App Protect WAF v5. | [{"name": "app-protect-bd-config", "emptyDir": {}},{"name": "app-protect-config", "emptyDir": {}},{"name": "app-protect-bundles", "emptyDir": {}}] | +|`controller.appprotect.enforcer.host` | Host that the App Protect WAF v5 Enforcer runs on. | "127.0.0.1" | +|`controller.appprotect.enforcer.port` | Port that the App Protect WAF v5 Enforcer runs on. | 50000 | +|`controller.appprotect.enforcer.image` | The image repository of the App Protect WAF v5 Enforcer. | private-registry.nginx.com/nap/waf-enforcer | +|`controller.appprotect.enforcer.tag` | The tag of the App Protect WAF v5 Enforcer. | "5.2.0" | +|`controller.appprotect.enforcer.digest` | The digest of the App Protect WAF v5 Enforcer. Takes precedence over tag if set. | "5.2.0" | +|`controller.appprotect.enforcer.pullPolicy` | The pull policy for the App Protect WAF v5 Enforcer image. | "5.2.0" | +|`controller.appprotect.enforcer.securityContext` | The security context for App Protect WAF v5 Enforcer container. | {} | +|`controller.appprotect.configManager.image` | The image repository of the App Protect WAF v5 Configuration Manager. | private-registry.nginx.com/nap/waf-config-mgr | +|`controller.appprotect.configManager.tag` | The tag of the App Protect WAF v5 Configuration Manager. | "5.2.0" | +|`controller.appprotect.configManager.digest` | The digest of the App Protect WAF v5 Configuration Manager. Takes precedence over tag if set. | "5.2.0" | +|`controller.appprotect.configManager.pullPolicy` | The pull policy for the App Protect WAF v5 Configuration Manager image. | "5.2.0" | +|`controller.appprotect.configManager.securityContext` | The security context for App Protect WAF v5 Configuration Manager container. | {"allowPrivilegeEscalation":false,"runAsUser":101,"runAsNonRoot":true,"capabilities":{"drop":["all"]}} | |`controller.appprotectdos.enable` | Enables the App Protect DoS module in the Ingress Controller. | false | |`controller.appprotectdos.debug` | Enable debugging for App Protect DoS. | false | |`controller.appprotectdos.maxDaemons` | Max number of ADMD instances. | 1 | diff --git a/charts/nginx-ingress/templates/_helpers.tpl b/charts/nginx-ingress/templates/_helpers.tpl index 497e1f6cdb..051cd17b0d 100644 --- a/charts/nginx-ingress/templates/_helpers.tpl +++ b/charts/nginx-ingress/templates/_helpers.tpl @@ -152,10 +152,27 @@ Expand wildcard TLS name. Expand image name. */}} {{- define "nginx-ingress.image" -}} -{{- if .Values.controller.image.digest -}} -{{- printf "%s@%s" .Values.controller.image.repository .Values.controller.image.digest -}} +{{ include "nginx-ingress.image-digest-or-tag" (dict "image" .Values.controller.image "default" .Chart.AppVersion ) }} +{{- end -}} + +{{- define "nap-enforcer.image" -}} +{{ include "nginx-ingress.image-digest-or-tag" (dict "image" .Values.controller.appprotect.enforcer.image "default" .Chart.AppVersion ) }} +{{- end -}} + +{{- define "nap-config-manager.image" -}} +{{ include "nginx-ingress.image-digest-or-tag" (dict "image" .Values.controller.appprotect.configManager.image "default" .Chart.AppVersion ) }} +{{- end -}} + +{{/* +Accepts an image struct like .Values.controller.image along with a default value to use +if the digest or tag is not set. Can be called like: +include "nginx-ingress.image-digest-or-tag" (dict "image" .Values.controller.image "default" .Chart.AppVersion +*/}} +{{- define "nginx-ingress.image-digest-or-tag" -}} +{{- if .image.digest -}} +{{- printf "%s@%s" .image.repository .image.digest -}} {{- else -}} -{{- printf "%s:%s" .Values.controller.image.repository (include "nginx-ingress.tag" .) -}} +{{- printf "%s:%s" .image.repository (default .default .image.tag) -}} {{- end -}} {{- end -}} @@ -198,6 +215,9 @@ Build the args for the service binary. {{- if and .Values.controller.appprotect.enable .Values.controller.appprotect.logLevel }} - -app-protect-log-level={{ .Values.controller.appprotect.logLevel }} {{ end }} +{{- if and .Values.controller.appprotect.enable .Values.controller.appprotect.v5 }} +- -app-protect-enforcer-address="{{ .Values.controller.appprotect.enforcer.host | default "127.0.0.1" }}:{{ .Values.controller.appprotect.enforcer.port | default 50000 }}" +{{- end }} - -enable-app-protect-dos={{ .Values.controller.appprotectdos.enable }} {{- if .Values.controller.appprotectdos.enable }} - -app-protect-dos-debug={{ .Values.controller.appprotectdos.debug }} @@ -312,6 +332,9 @@ List of volumes for controller. - name: nginx-log emptyDir: {} {{- end }} +{{- if .Values.controller.appprotect.v5 }} +{{- toYaml .Values.controller.appprotect.volumes }} +{{- end }} {{- if .Values.controller.volumes }} {{ toYaml .Values.controller.volumes }} {{- end }} @@ -361,6 +384,16 @@ volumeMounts: - mountPath: /var/log/nginx name: nginx-log {{- end }} +{{- if .Values.controller.appprotect.v5 }} +- name: app-protect-bd-config + mountPath: /opt/app_protect/bd_config +- name: app-protect-config + mountPath: /opt/app_protect/config + # app-protect-bundles is mounted so that Ingress Controller + # can verify that referenced bundles are present +- name: app-protect-bundles + mountPath: /etc/app_protect/bundles +{{- end }} {{- if .Values.controller.volumeMounts }} {{ toYaml .Values.controller.volumeMounts }} {{- end }} @@ -378,6 +411,38 @@ volumeMounts: {{- end -}} {{- end -}} +{{- define "nginx-ingress.appprotect.v5" -}} +{{- if .Values.controller.appprotect.v5}} +- name: waf-enforcer + image: {{ include "nap-enforcer.image" . }} + imagePullPolicy: "{{ .Values.controller.appprotect.enforcer.image.pullPolicy }}" +{{- if .Values.controller.appprotect.enforcer.securityContext }} + securityContext: +{{ toYaml .Values.controller.appprotect.enforcer.securityContext | nindent 6 }} +{{- end }} + env: + - name: ENFORCER_PORT + value: "{{ .Values.controller.appprotect.enforcer.port | default 50000 }}" + volumeMounts: + - name: app-protect-bd-config + mountPath: /opt/app_protect/bd_config +- name: waf-config-mgr + image: {{ include "nap-config-manager.image" . }} + imagePullPolicy: "{{ .Values.controller.appprotect.configManager.image.pullPolicy }}" +{{- if .Values.controller.appprotect.configManager.securityContext }} + securityContext: +{{ toYaml .Values.controller.appprotect.configManager.securityContext | nindent 6 }} +{{- end }} + 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 +{{- end}} +{{- end -}} + {{- define "nginx-ingress.agentConfiguration" -}} log: level: {{ .Values.nginxAgent.logLevel }} diff --git a/charts/nginx-ingress/templates/controller-daemonset.yaml b/charts/nginx-ingress/templates/controller-daemonset.yaml index 8da65c4683..268f127f85 100644 --- a/charts/nginx-ingress/templates/controller-daemonset.yaml +++ b/charts/nginx-ingress/templates/controller-daemonset.yaml @@ -134,6 +134,9 @@ spec: {{- if .Values.controller.extraContainers }} {{ toYaml .Values.controller.extraContainers | nindent 6 }} {{- end }} + +{{- include "nginx-ingress.appprotect.v5" . | nindent 6 }} + {{- if or (eq (include "nginx-ingress.readOnlyRootFilesystem" .) "true" ) .Values.controller.initContainers }} initContainers: {{- end }} diff --git a/charts/nginx-ingress/templates/controller-deployment.yaml b/charts/nginx-ingress/templates/controller-deployment.yaml index c8bc8f833c..95bf3bb165 100644 --- a/charts/nginx-ingress/templates/controller-deployment.yaml +++ b/charts/nginx-ingress/templates/controller-deployment.yaml @@ -141,6 +141,9 @@ spec: {{- if .Values.controller.extraContainers }} {{ toYaml .Values.controller.extraContainers | nindent 6 }} {{- end }} + +{{- include "nginx-ingress.appprotect.v5" . | nindent 6 }} + {{- if or ( eq (include "nginx-ingress.readOnlyRootFilesystem" .) "true" ) .Values.controller.initContainers }} initContainers: {{- end }} diff --git a/charts/nginx-ingress/values.schema.json b/charts/nginx-ingress/values.schema.json index 4d8f0400c7..d73c968af7 100644 --- a/charts/nginx-ingress/values.schema.json +++ b/charts/nginx-ingress/values.schema.json @@ -119,6 +119,15 @@ true ] }, + "v5": { + "type": "boolean", + "default": false, + "title": "Enables App Protect WAF v5.", + "examples": [ + false, + true + ] + }, "logLevel": { "type": "string", "default": "", @@ -139,6 +148,201 @@ "debug", "trace" ] + }, + "volumes": { + "type": "array", + "default": [ + { + "name": "app-protect-bd-config", + "emptyDir": {} + }, + { + "name": "app-protect-config", + "emptyDir": {} + }, + { + "name": "app-protect-bundles", + "emptyDir": {} + } + ], + "title": "Volumes for App Protect WAF v5", + "items": { + "type": "object", + "$ref": "https://raw.githubusercontent.com/nginxinc/kubernetes-json-schema/master/v1.29.0/_definitions.json#/definitions/io.k8s.api.core.v1.Volume" + } + }, + "enforcer": { + "type": "object", + "properties": { + "host": { + "type": "string", + "default": "127.0.0.1", + "title": "Port which the App Protect WAF v5 Enforcer process runs on", + "examples": [ + "127.0.0.1" + ] + }, + "port": { + "type": "integer", + "default": 50000, + "title": "Port which the App Protect WAF v5 Enforcer process runs on", + "examples": [ + 50000 + ] + }, + "image": { + "type": "object", + "default": {}, + "title": "The image Schema", + "required": [ + "repository" + ], + "properties": { + "repository": { + "type": "string", + "default": "private-registry.nginx.com/nap/waf-enforcer", + "title": "The repository of the App Protect WAF v5 Enforcer image", + "examples": [ + "private-registry.nginx.com/nap/waf-enforcer" + ] + }, + "tag": { + "type": "string", + "default": "5.2.0", + "title": "The tag of the App Protect WAF v5 Enforcer image", + "examples": [ + "5.2.0" + ] + }, + "digest": { + "type": "string", + "default": "", + "title": "The digest of the App Protect WAF v5 Enforcer image", + "examples": [ + "sha256:2710c264e8eaeb663cee63db37b75a1ac1709f63a130fb091c843a6c3a4dc572" + ] + }, + "pullPolicy": { + "type": "string", + "default": "IfNotPresent", + "title": "The pullPolicy for the App Protect WAF v5 Enforcer image", + "allOf": [ + { + "$ref": "https://raw.githubusercontent.com/nginxinc/kubernetes-json-schema/master/v1.29.0/_definitions.json#/definitions/io.k8s.api.core.v1.Container/properties/imagePullPolicy" + }, + { + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + ], + "examples": [ + "Always", + "IfNotPresent", + "Never" + ] + } + }, + "examples": [ + { + "repository": "private-registry.nginx.com/nap/waf-enforcer", + "tag": "5.2.0", + "pullPolicy": "IfNotPresent" + } + ] + }, + "securityContext": { + "type": "object", + "default": {}, + "title": "The securityContext Schema", + "$ref": "https://raw.githubusercontent.com/nginxinc/kubernetes-json-schema/master/v1.29.0/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext" + } + } + }, + "configManager": { + "type": "object", + "properties": { + "image": { + "type": "object", + "default": {}, + "title": "The image Schema", + "required": [ + "repository" + ], + "properties": { + "repository": { + "type": "string", + "default": "private-registry.nginx.com/nap/waf-config-mgr", + "title": "The repository of the App Protect WAF v5 Config Manager image", + "examples": [ + "private-registry.nginx.com/nap/waf-config-mgr" + ] + }, + "tag": { + "type": "string", + "default": "5.2.0", + "title": "The tag of the App Protect WAF v5 Config Manager image", + "examples": [ + "5.2.0" + ] + }, + "digest": { + "type": "string", + "default": "", + "title": "The digest of the App Protect WAF v5 Config Manager image", + "examples": [ + "sha256:2710c264e8eaeb663cee63db37b75a1ac1709f63a130fb091c843a6c3a4dc572" + ] + }, + "pullPolicy": { + "type": "string", + "default": "IfNotPresent", + "title": "The pullPolicy for the App Protect WAF v5 Config Manager image", + "allOf": [ + { + "$ref": "https://raw.githubusercontent.com/nginxinc/kubernetes-json-schema/master/v1.29.0/_definitions.json#/definitions/io.k8s.api.core.v1.Container/properties/imagePullPolicy" + }, + { + "enum": [ + "Always", + "IfNotPresent", + "Never" + ] + } + ], + "examples": [ + "Always", + "IfNotPresent", + "Never" + ] + } + }, + "examples": [ + { + "repository": "private-registry.nginx.com/nap/waf-config-mgr", + "tag": "5.2.0", + "pullPolicy": "IfNotPresent" + } + ] + }, + "securityContext": { + "type": "object", + "default": { + "allowPrivilegeEscalation": false, + "runAsUser": 101, + "runAsNonRoot": true, + "capabilities": { + "drop": [ + "all" + ] + } + }, + "title": "The securityContext Schema", + "$ref": "https://raw.githubusercontent.com/nginxinc/kubernetes-json-schema/master/v1.29.0/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext" + } + } } }, "examples": [ diff --git a/charts/nginx-ingress/values.yaml b/charts/nginx-ingress/values.yaml index 3e10e200c7..ea91a10a12 100644 --- a/charts/nginx-ingress/values.yaml +++ b/charts/nginx-ingress/values.yaml @@ -21,9 +21,65 @@ controller: appprotect: ## Enable the App Protect WAF module in the Ingress Controller. enable: false + ## Enables App Protect WAF v5. + v5: false ## Sets log level for App Protect WAF. Allowed values: fatal, error, warn, info, debug, trace # logLevel: fatal + # Volumes for App Protect WAF v5 + # Required volumes are: app-protect-bd-config, app-protect-config, and app-protect-bundles + volumes: + - name: app-protect-bd-config + emptyDir: {} + - name: app-protect-config + emptyDir: {} + - name: app-protect-bundles + emptyDir: {} + + ## Configuration for App Protect WAF v5 Enforcer + enforcer: + # Host that the App Protect WAF v5 Enforcer runs on. + # This will normally be "127.0.0.1" as the Enforcer container + # will run in the same pod as the Ingress Controller container. + host: "127.0.0.1" + # Port that the App Protect WAF v5 Enforcer runs on. + port: 50000 + image: + ## The image repository of the App Protect WAF v5 Enforcer. + repository: private-registry.nginx.com/nap/waf-enforcer + + ## The tag of the App Protect WAF v5 Enforcer image. + tag: "5.2.0" + ## The digest of the App Protect WAF v5 Enforcer image. + ## If digest is specified it has precedence over tag and will be used instead + # digest: "sha256:CHANGEME" + + ## The pull policy for the App Protect WAF v5 Enforcer image. + pullPolicy: IfNotPresent + securityContext: {} + + ## Configuration for App Protect WAF v5 Configuration Manager + configManager: + image: + ## The image repository of the App Protect WAF v5 Configuration Manager. + repository: private-registry.nginx.com/nap/waf-config-mgr + + ## The tag of the App Protect WAF v5 Configuration Manager image. + tag: "5.2.0" + ## The digest of the App Protect WAF v5 Configuration Manager image. + ## If digest is specified it has precedence over tag and will be used instead + # digest: "sha256:CHANGEME" + + ## The pull policy for the App Protect WAF v5 Configuration Manager image. + pullPolicy: IfNotPresent + securityContext: + allowPrivilegeEscalation: false + runAsUser: 101 #nginx + runAsNonRoot: true + capabilities: + drop: + - all + ## Support for App Protect DoS appprotectdos: ## Enable the App Protect DoS module in the Ingress Controller. @@ -173,7 +229,8 @@ controller: type: RuntimeDefault ## The security context for the Ingress Controller containers. - securityContext: {} # Remove curly brackets before adding values + securityContext: + {} # Remove curly brackets before adding values # allowPrivilegeEscalation: true # readOnlyRootFilesystem: true # runAsUser: 101 #nginx diff --git a/cmd/nginx-ingress/flags.go b/cmd/nginx-ingress/flags.go index 3d02c86b23..d36381974e 100644 --- a/cmd/nginx-ingress/flags.go +++ b/cmd/nginx-ingress/flags.go @@ -16,8 +16,10 @@ import ( ) const ( - dynamicSSLReloadParam = "ssl-dynamic-reload" - dynamicWeightChangesParam = "weight-changes-dynamic-reload" + dynamicSSLReloadParam = "ssl-dynamic-reload" + dynamicWeightChangesParam = "weight-changes-dynamic-reload" + appProtectLogLevelDefault = "fatal" + appProtectEnforcerAddrDefault = "127.0.0.1:50000" ) var ( @@ -65,6 +67,9 @@ var ( appProtectDosMaxWorkers = flag.Int("app-protect-dos-max-workers", 0, "Max number of nginx processes to support. Requires -nginx-plus and -enable-app-protect-dos.") appProtectDosMemory = flag.Int("app-protect-dos-memory", 0, "RAM memory size to consume in MB. Requires -nginx-plus and -enable-app-protect-dos.") + appProtectEnforcerAddress = flag.String("app-protect-enforcer-address", appProtectEnforcerAddrDefault, + `Sets address for App Protect v5 Enforcer. Requires -nginx-plus and -enable-app-protect.`) + agent = flag.Bool("agent", false, "Enable NGINX Agent") agentInstanceGroup = flag.String("agent-instance-group", "nginx-ingress-controller", "Grouping used to associate NGINX Ingress Controller instances") @@ -440,8 +445,6 @@ func validatePort(port int) error { return nil } -const appProtectLogLevelDefault = "fatal" - // validateAppProtectLogLevel makes sure a given logLevel is one of the allowed values func validateAppProtectLogLevel(logLevel string) error { switch strings.ToLower(logLevel) { diff --git a/cmd/nginx-ingress/main.go b/cmd/nginx-ingress/main.go index db38de9bd5..d911d2f818 100644 --- a/cmd/nginx-ingress/main.go +++ b/cmd/nginx-ingress/main.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "os/signal" + "regexp" "runtime" "strings" "syscall" @@ -47,11 +48,13 @@ var ( ) const ( - nginxVersionLabel = "app.nginx.org/version" - versionLabel = "app.kubernetes.io/version" - appProtectVersionLabel = "appprotect.f5.com/version" - agentVersionLabel = "app.nginx.org/agent-version" - appProtectVersionPath = "/opt/app_protect/RELEASE" + nginxVersionLabel = "app.nginx.org/version" + versionLabel = "app.kubernetes.io/version" + appProtectVersionLabel = "appprotect.f5.com/version" + agentVersionLabel = "app.nginx.org/agent-version" + appProtectVersionPath = "/opt/app_protect/RELEASE" + appProtectv4BundleFolder = "/etc/nginx/waf/bundles/" + appProtectv5BundleFolder = "/etc/app_protect/bundles/" ) func main() { @@ -80,8 +83,16 @@ func main() { nginxVersion := getNginxVersionInfo(nginxManager) var appProtectVersion string + var appProtectV5 bool + appProtectBundlePath := appProtectv4BundleFolder if *appProtect { appProtectVersion = getAppProtectVersionInfo() + + r := regexp.MustCompile("^5.*") + if r.MatchString(appProtectVersion) { + appProtectV5 = true + appProtectBundlePath = appProtectv5BundleFolder + } } var agentVersion string @@ -119,7 +130,9 @@ func main() { EnableSnippets: *enableSnippets, NginxServiceMesh: *spireAgentAddress != "", MainAppProtectLoadModule: *appProtect, + MainAppProtectV5LoadModule: appProtectV5, MainAppProtectDosLoadModule: *appProtectDos, + MainAppProtectV5EnforcerAddr: *appProtectEnforcerAddress, EnableLatencyMetrics: *enableLatencyMetrics, EnableOIDC: *enableOIDC, SSLRejectHandshake: sslRejectHandshake, @@ -128,6 +141,7 @@ func main() { DynamicWeightChangesReload: *enableDynamicWeightChangesReload, StaticSSLPath: nginxManager.GetSecretsDir(), NginxVersion: nginxVersion, + AppProtectBundlePath: appProtectBundlePath, } processNginxConfig(staticCfgParams, cfgParams, templateExecutor, nginxManager) @@ -137,7 +151,7 @@ func main() { nginxManager.CreateTLSPassthroughHostsConfig(emptyFile) } - process := startChildProcesses(nginxManager) + process := startChildProcesses(nginxManager, appProtectV5) plusClient := createPlusClient(*nginxPlus, useFakeNginxManager, nginxManager) @@ -456,10 +470,11 @@ type childProcesses struct { // newChildProcesses starts the several child processes based on flags set. // AppProtect. AppProtectDos, Agent. -func startChildProcesses(nginxManager nginx.Manager) childProcesses { +func startChildProcesses(nginxManager nginx.Manager, appProtectV5 bool) childProcesses { var aPPluginDone chan error - if *appProtect { + // Do not start AppProtect Plugins when using v5. + if *appProtect && !appProtectV5 { aPPluginDone = make(chan error, 1) nginxManager.AppProtectPluginStart(aPPluginDone, *appProtectLogLevel) } diff --git a/internal/configs/config_params.go b/internal/configs/config_params.go index ce011400bc..be86ae4eb9 100644 --- a/internal/configs/config_params.go +++ b/internal/configs/config_params.go @@ -145,7 +145,9 @@ type StaticConfigParams struct { NginxServiceMesh bool EnableInternalRoutes bool MainAppProtectLoadModule bool + MainAppProtectV5LoadModule bool MainAppProtectDosLoadModule bool + MainAppProtectV5EnforcerAddr string InternalRouteServerName string EnableLatencyMetrics bool EnableOIDC bool @@ -155,6 +157,7 @@ type StaticConfigParams struct { StaticSSLPath string DynamicWeightChangesReload bool NginxVersion nginx.Version + AppProtectBundlePath string } // GlobalConfigParams holds global configuration parameters. For now, it only holds listeners. diff --git a/internal/configs/configmaps.go b/internal/configs/configmaps.go index fbcd63b68d..c4041336da 100644 --- a/internal/configs/configmaps.go +++ b/internal/configs/configmaps.go @@ -565,7 +565,9 @@ func GenerateNginxMainConfig(staticCfgParams *StaticConfigParams, config *Config VariablesHashBucketSize: config.VariablesHashBucketSize, VariablesHashMaxSize: config.VariablesHashMaxSize, AppProtectLoadModule: staticCfgParams.MainAppProtectLoadModule, + AppProtectV5LoadModule: staticCfgParams.MainAppProtectV5LoadModule, AppProtectDosLoadModule: staticCfgParams.MainAppProtectDosLoadModule, + AppProtectV5EnforcerAddr: staticCfgParams.MainAppProtectV5EnforcerAddr, AppProtectFailureModeAction: config.MainAppProtectFailureModeAction, AppProtectCompressedRequestsAction: config.MainAppProtectCompressedRequestsAction, AppProtectCookieSeed: config.MainAppProtectCookieSeed, diff --git a/internal/configs/configurator.go b/internal/configs/configurator.go index 080f597ceb..d8412b8bba 100644 --- a/internal/configs/configurator.go +++ b/internal/configs/configurator.go @@ -31,7 +31,6 @@ import ( const ( pemFileNameForWildcardTLSSecret = "/etc/nginx/secrets/wildcard" // #nosec G101 - appProtectBundleFolder = "/etc/nginx/waf/bundles/" appProtectPolicyFolder = "/etc/nginx/waf/nac-policies/" appProtectLogConfFolder = "/etc/nginx/waf/nac-logconfs/" appProtectUserSigFolder = "/etc/nginx/waf/nac-usersigs/" diff --git a/internal/configs/version1/config.go b/internal/configs/version1/config.go index c05edceb55..85d8c2006a 100644 --- a/internal/configs/version1/config.go +++ b/internal/configs/version1/config.go @@ -245,6 +245,8 @@ type MainConfig struct { WorkerRlimitNofile string WorkerShutdownTimeout string AppProtectLoadModule bool + AppProtectV5LoadModule bool + AppProtectV5EnforcerAddr string AppProtectFailureModeAction string AppProtectCompressedRequestsAction string AppProtectCookieSeed string diff --git a/internal/configs/version1/nginx-plus.tmpl b/internal/configs/version1/nginx-plus.tmpl index e525a533c6..e13589d5b3 100644 --- a/internal/configs/version1/nginx-plus.tmpl +++ b/internal/configs/version1/nginx-plus.tmpl @@ -85,6 +85,10 @@ http { {{- end}} {{- end}} + {{- if .AppProtectV5LoadModule}} + app_protect_enforcer_address {{ .AppProtectV5EnforcerAddr }}; + {{- end}} + {{- if .AccessLogOff}} access_log off; {{- else}} diff --git a/internal/configs/version2/templates_test.go b/internal/configs/version2/templates_test.go index 83e75cade0..28ea24e599 100644 --- a/internal/configs/version2/templates_test.go +++ b/internal/configs/version2/templates_test.go @@ -2705,7 +2705,7 @@ var ( VerifyDepth: 2, }, WAF: &WAF{ - ApBundle: "/etc/nginx/waf/bundles/NginxDefaultPolicy.tgz", + ApBundle: "/fake/bundle/path/NginxDefaultPolicy.tgz", ApSecurityLogEnable: true, ApLogConf: []string{"/etc/nginx/waf/nac-logconfs/default-logconf"}, }, diff --git a/internal/configs/virtualserver.go b/internal/configs/virtualserver.go index aa6c12fcdf..64e819bfda 100644 --- a/internal/configs/virtualserver.go +++ b/internal/configs/virtualserver.go @@ -315,7 +315,7 @@ func newVirtualServerConfigurator( bundleValidator bundleValidator, ) *virtualServerConfigurator { if bundleValidator == nil { - bundleValidator = newInternalBundleValidator(appProtectBundleFolder) + bundleValidator = newInternalBundleValidator(staticParams.AppProtectBundlePath) } return &virtualServerConfigurator{ cfgParams: cfgParams, @@ -1325,7 +1325,6 @@ func (p *policiesCfg) addWAFConfig( } if waf.ApBundle != "" { - p.WAF.ApBundle = appProtectBundleFolder + waf.ApBundle bundlePath, err := p.BundleValidator.validate(waf.ApBundle) if err != nil { res.addWarningf("WAF policy %s references an invalid or non-existing App Protect bundle %s", polKey, bundlePath) diff --git a/internal/configs/virtualserver_test.go b/internal/configs/virtualserver_test.go index a7f89270db..22cc242b48 100644 --- a/internal/configs/virtualserver_test.go +++ b/internal/configs/virtualserver_test.go @@ -6378,7 +6378,7 @@ func TestGeneratePolicies_GeneratesWAFPolicyOnValidApBundle(t *testing.T) { want: policiesCfg{ WAF: &version2.WAF{ Enable: "on", - ApBundle: "/etc/nginx/waf/bundles/testWAFPolicyBundle.tgz", + ApBundle: "/fake/bundle/path/testWAFPolicyBundle.tgz", }, }, }, @@ -6410,9 +6410,9 @@ func TestGeneratePolicies_GeneratesWAFPolicyOnValidApBundle(t *testing.T) { want: policiesCfg{ WAF: &version2.WAF{ Enable: "on", - ApBundle: "/etc/nginx/waf/bundles/testWAFPolicyBundle.tgz", + ApBundle: "/fake/bundle/path/testWAFPolicyBundle.tgz", ApSecurityLogEnable: true, - ApLogConf: []string{"/etc/nginx/waf/bundles/secops_dashboard.tgz syslog:server=localhost:514"}, + ApLogConf: []string{"/fake/bundle/path/secops_dashboard.tgz syslog:server=localhost:514"}, }, }, }, @@ -14663,7 +14663,7 @@ var ( type fakeBundleValidator struct{} func (*fakeBundleValidator) validate(bundle string) (string, error) { - bundle = fmt.Sprintf("/etc/nginx/waf/bundles/%s", bundle) + bundle = fmt.Sprintf("/fake/bundle/path/%s", bundle) if strings.Contains(bundle, "invalid") { return bundle, fmt.Errorf("invalid bundle %s", bundle) }