diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5b6613b6b3..6951ad45ea 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,25 @@ 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: Download Syft + uses: anchore/sbom-action/download-syft@cee1b8e05ae5b2593a75e197229729eabaa9f8ec # v0.20.2 + if: ${{ inputs.image == 'plus-waf' }} + - name: Inspect SBOM and output manifest run: | + if [[ "${{ inputs.image }}" == "plus-waf" ]]; then + # For plus-waf, use syft directly + syft localhost:5000/nginx-gateway-fabric/${{ inputs.image }}:${{ steps.meta.outputs.version }} -o spdx-json > sbom-${{ inputs.image }}.json + 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 +190,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 b417e3ca7f..98ef994aea 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/README.md b/README.md index 1d2b92da1d..69a35a5272 100644 --- a/README.md +++ b/README.md @@ -66,22 +66,22 @@ the [Issue Lifecycle](ISSUE_LIFECYCLE.md) document for information on issue crea The following table lists the software versions NGINX Gateway Fabric supports. -| NGINX Gateway Fabric | Gateway API | Kubernetes | NGINX OSS | NGINX Plus | NGINX Agent | -|----------------------|-------------|------------|-----------|------------|-------------| -| Edge | 1.3.0 | 1.25+ | 1.28.0 | R34 | v3.0.3 | -| 2.0.2 | 1.3.0 | 1.25+ | 1.28.0 | R34 | v3.0.1 | -| 2.0.1 | 1.3.0 | 1.25+ | 1.28.0 | R34 | v3.0.1 | -| 2.0.0 | 1.3.0 | 1.25+ | 1.28.0 | R34 | v3.0.0 | -| 1.6.2 | 1.2.1 | 1.25+ | 1.27.4 | R33 | --- | -| 1.6.1 | 1.2.1 | 1.25+ | 1.27.4 | R33 | --- | -| 1.6.0 | 1.2.1 | 1.25+ | 1.27.3 | R33 | --- | -| 1.5.1 | 1.2.0 | 1.25+ | 1.27.2 | R33 | --- | -| 1.5.0 | 1.2.0 | 1.25+ | 1.27.2 | R33 | --- | -| 1.4.0 | 1.1.0 | 1.25+ | 1.27.1 | R32 | --- | -| 1.3.0 | 1.1.0 | 1.25+ | 1.27.0 | R32 | --- | -| 1.2.0 | 1.0.0 | 1.23+ | 1.25.4 | R31 | --- | -| 1.1.0 | 1.0.0 | 1.23+ | 1.25.3 | n/a | --- | -| 1.0.0 | 0.8.1 | 1.23+ | 1.25.2 | n/a | --- | +| NGINX Gateway Fabric | Gateway API | Kubernetes | NGINX OSS | NGINX Plus | NGINX Agent | NGINX NAP WAF | +|----------------------|-------------|------------|-----------|------------|-------------|---------------| +| Edge | 1.3.0 | 1.25+ | 1.28.0 | R34 | v3.0.3 | 5.7.0 | +| 2.0.2 | 1.3.0 | 1.25+ | 1.28.0 | R34 | v3.0.1 | --- | +| 2.0.1 | 1.3.0 | 1.25+ | 1.28.0 | R34 | v3.0.1 | --- | +| 2.0.0 | 1.3.0 | 1.25+ | 1.28.0 | R34 | v3.0.0 | --- | +| 1.6.2 | 1.2.1 | 1.25+ | 1.27.4 | R33 | --- | --- | +| 1.6.1 | 1.2.1 | 1.25+ | 1.27.4 | R33 | --- | --- | +| 1.6.0 | 1.2.1 | 1.25+ | 1.27.3 | R33 | --- | --- | +| 1.5.1 | 1.2.0 | 1.25+ | 1.27.2 | R33 | --- | --- | +| 1.5.0 | 1.2.0 | 1.25+ | 1.27.2 | R33 | --- | --- | +| 1.4.0 | 1.1.0 | 1.25+ | 1.27.1 | R32 | --- | --- | +| 1.3.0 | 1.1.0 | 1.25+ | 1.27.0 | R32 | --- | --- | +| 1.2.0 | 1.0.0 | 1.23+ | 1.25.4 | R31 | --- | --- | +| 1.1.0 | 1.0.0 | 1.23+ | 1.25.3 | n/a | --- | --- | +| 1.0.0 | 0.8.1 | 1.23+ | 1.25.2 | n/a | --- | --- | ## SBOM (Software Bill of Materials) diff --git a/internal/controller/provisioner/objects.go b/internal/controller/provisioner/objects.go index 6aa140a37a..905b492744 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" @@ -1005,6 +1006,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 { diff --git a/internal/controller/provisioner/objects_test.go b/internal/controller/provisioner/objects_test.go index d48b9afea0..fb056a27e8 100644 --- a/internal/controller/provisioner/objects_test.go +++ b/internal/controller/provisioner/objects_test.go @@ -1126,7 +1126,7 @@ func TestBuildNginxResourceObjects_WAF(t *testing.T) { // Validate NGINX container (first container) nginxContainer := template.Spec.Containers[0] g.Expect(nginxContainer.Name).To(Equal("nginx")) - g.Expect(nginxContainer.Image).To(Equal(fmt.Sprintf("%s:1.0.0", defaultNginxImagePath))) + g.Expect(nginxContainer.Image).To(Equal(fmt.Sprintf("%s:1.0.0", defaultNginxPlusWafImagePath))) // Check NGINX container has WAF volume mounts wafVolumeMountNames := []string{