diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d79025472a..647e9f4f40 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,7 +87,7 @@ jobs: token_format: access_token workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY }} service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} - if: ${{ github.event_name != 'pull_request' && contains(inputs.image, 'plus') }} + if: ${{ github.event_name != 'pull_request' && (contains(inputs.image, 'plus') || inputs.image == 'plus-waf') }} - name: Login to GAR uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 @@ -95,7 +95,7 @@ jobs: registry: us-docker.pkg.dev username: oauth2accesstoken password: ${{ steps.auth.outputs.access_token }} - if: ${{ github.event_name != 'pull_request' && contains(inputs.image, 'plus') }} + if: ${{ github.event_name != 'pull_request' && (contains(inputs.image, 'plus') || inputs.image == 'plus-waf') }} - name: Docker meta id: meta @@ -106,7 +106,9 @@ jobs: name=ghcr.io/${{ github.repository_owner }}/nginx-gateway-fabric,enable=${{ inputs.image == 'ngf' && github.event_name != 'pull_request' }} name=ghcr.io/${{ github.repository_owner }}/nginx-gateway-fabric/nginx,enable=${{ inputs.image == 'nginx' && github.event_name != 'pull_request' }} name=docker-mgmt.nginx.com/nginx-gateway-fabric/nginx-plus,enable=${{ inputs.image == 'plus' && github.event_name != 'pull_request' }} + name=docker-mgmt.nginx.com/nginx-gateway-fabric/nginx-plus-nap-waf,enable=${{ inputs.image == 'plus-waf' && github.event_name != 'pull_request' }} name=us-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/nginx-gateway-fabric/nginx-plus,enable=${{ inputs.image == 'plus' && github.event_name != 'pull_request' }} + name=us-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/nginx-gateway-fabric/nginx-plus-nap-waf,enable=${{ inputs.image == 'plus-waf' && github.event_name != 'pull_request' }} name=localhost:5000/nginx-gateway-fabric/${{ inputs.image }} flavor: | latest=${{ (inputs.tag != '' && 'true') || 'auto' }} @@ -134,7 +136,7 @@ jobs: - name: Build Docker Image uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: - file: build/Dockerfile${{ inputs.image == 'nginx' && '.nginx' || '' }}${{ inputs.image == 'plus' && '.nginxplus' || '' }} + file: build/Dockerfile${{ inputs.image == 'nginx' && '.nginx' || '' }}${{ (inputs.image == 'plus' || inputs.image == 'plus-waf') && '.nginxplus' || '' }} context: "." target: ${{ inputs.image == 'ngf' && 'goreleaser' || '' }} tags: ${{ steps.meta.outputs.tags }} @@ -152,13 +154,30 @@ jobs: NJS_DIR=internal/controller/nginx/modules/src NGINX_CONF_DIR=internal/controller/nginx/conf BUILD_AGENT=gha + ${{ inputs.image == 'plus-waf' && 'ALPINE_VERSION=3.19' || '' }} + ${{ inputs.image == 'plus-waf' && 'INCLUDE_NAP_WAF=true' || '' }} secrets: | ${{ contains(inputs.image, 'plus') && format('"nginx-repo.crt={0}"', secrets.NGINX_CRT) || '' }} ${{ contains(inputs.image, 'plus') && format('"nginx-repo.key={0}"', secrets.NGINX_KEY) || '' }} - name: Inspect SBOM and output manifest run: | + if [[ "${{ inputs.image }}" == "plus-waf" ]]; then + # For plus-waf, use syft directly + echo "Generating SBOM for plus-waf using syft..." + + # Install syft if not available + if ! command -v syft >/dev/null 2>&1; then + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + fi + + # Generate SBOM using syft directly for plus-waf (known to work with NAP WAF) + syft localhost:5000/nginx-gateway-fabric/${{ inputs.image }}:${{ steps.meta.outputs.version }} -o spdx-json > sbom-${{ inputs.image }}.json + echo "Generated SBOM using syft for plus-waf" + else + # For other images, use the standard Docker buildx approach docker buildx imagetools inspect localhost:5000/nginx-gateway-fabric/${{ inputs.image }}:${{ steps.meta.outputs.version }} --format '{{ json (index .SBOM "linux/amd64").SPDX }}' > sbom-${{ inputs.image }}.json + fi docker buildx imagetools inspect localhost:5000/nginx-gateway-fabric/${{ inputs.image }}:${{ steps.meta.outputs.version }} --raw - name: Scan SBOM @@ -176,4 +195,4 @@ jobs: with: sarif_file: ${{ steps.scan.outputs.sarif }} category: build-${{ inputs.image }} - if: always() + if: always() && steps.scan.conclusion == 'success' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dfdc580e66..3e195639e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -222,6 +222,20 @@ jobs: id-token: write # for docker/login to login to NGINX registry secrets: inherit + build-plus-waf: + name: Build Plus WAF images + needs: [vars, binary] + uses: ./.github/workflows/build.yml + with: + image: plus-waf + platforms: "linux/amd64" + permissions: + contents: read # for docker/build-push-action to read repo content + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + packages: write # for docker/build-push-action to push to GHCR + id-token: write # for docker/login to login to NGINX registry + secrets: inherit + functional-tests: name: Functional tests needs: [vars, build-oss, build-plus] diff --git a/internal/controller/provisioner/objects.go b/internal/controller/provisioner/objects.go index 9cd5702d32..8590a779b0 100644 --- a/internal/controller/provisioner/objects.go +++ b/internal/controller/provisioner/objects.go @@ -33,9 +33,10 @@ const ( defaultServiceType = corev1.ServiceTypeLoadBalancer defaultServicePolicy = corev1.ServiceExternalTrafficPolicyLocal - defaultNginxImagePath = "ghcr.io/nginx/nginx-gateway-fabric/nginx" - defaultNginxPlusImagePath = "private-registry.nginx.com/nginx-gateway-fabric/nginx-plus" - defaultImagePullPolicy = corev1.PullIfNotPresent + defaultNginxImagePath = "ghcr.io/nginx/nginx-gateway-fabric/nginx" + defaultNginxPlusImagePath = "private-registry.nginx.com/nginx-gateway-fabric/nginx-plus" + defaultNginxPlusWafImagePath = "private-registry.nginx.com/nginx-gateway-fabric/nginx-plus-nap-waf" + defaultImagePullPolicy = corev1.PullIfNotPresent // WAF container defaults. defaultWAFEnforcerImagePath = "private-registry.nginx.com/nap/waf-enforcer" @@ -988,6 +989,10 @@ func (p *NginxProvisioner) buildImage(nProxyCfg *graph.EffectiveNginxProxy) (str image = defaultNginxPlusImagePath } + if graph.WAFEnabledForNginxProxy(nProxyCfg) { + image = defaultNginxPlusWafImagePath + } + getImageAndPullPolicy := func(container ngfAPIv1alpha2.ContainerSpec) (string, string, corev1.PullPolicy) { if container.Image != nil { if container.Image.Repository != nil {