From 868a6a7584f5fd901a33f618893d720e7f00a83f Mon Sep 17 00:00:00 2001 From: Michael Briley Date: Thu, 5 Jun 2025 10:36:23 -0600 Subject: [PATCH] Harden Container Runtime with Non-Root User (#3941) * Update Dockerfile Signed-off-by: Michael Briley * Update Dockerfile Signed-off-by: Michael Briley * Update validations.yaml Signed-off-by: Michael Briley * Update validations.yaml Signed-off-by: Michael Briley * Update Dockerfile Signed-off-by: Michael Briley * Update validations.yaml Signed-off-by: Michael Briley * Update Dockerfile Signed-off-by: Michael Briley * Update .goreleaser.yaml Signed-off-by: Michael Briley * Update .goreleaser.yaml Signed-off-by: Michael Briley * use distroless/static-debian12:nonroot directly Signed-off-by: Alex Goodman * keep manual manifest curation Signed-off-by: Alex Goodman * remove qemu usage Signed-off-by: Alex Goodman * add smoke test for snapshot Signed-off-by: Alex Goodman * split up manifests section with comments Signed-off-by: Alex Goodman * correct ci step name Signed-off-by: Alex Goodman * fix arch condition Signed-off-by: Alex Goodman * keep path prefix Signed-off-by: Alex Goodman --------- Signed-off-by: Michael Briley Signed-off-by: Alex Goodman Co-authored-by: Alex Goodman --- .github/workflows/validations.yaml | 3 + .goreleaser.yaml | 211 ++++++++++++++--------------- Dockerfile | 8 +- Dockerfile.debug | 4 +- Taskfile.yaml | 21 ++- 5 files changed, 124 insertions(+), 123 deletions(-) diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index a8a82e184..7b19f5064 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -76,6 +76,9 @@ jobs: - name: Build snapshot artifacts run: make snapshot + - name: Smoke test snapshot build + run: make snapshot-smoke-test + # why not use actions/upload-artifact? It is very slow (3 minutes to upload ~600MB of data, vs 10 seconds with this approach). # see https://github.com/actions/upload-artifact/issues/199 for more info - name: Upload snapshot artifacts diff --git a/.goreleaser.yaml b/.goreleaser.yaml index a8fc7711f..03da7e4dc 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -1,11 +1,11 @@ version: 2 +project_name: syft release: prerelease: auto draft: false env: - # required to support multi architecture docker builds - DOCKER_CLI_EXPERIMENTAL=enabled - CGO_ENABLED=0 @@ -13,14 +13,8 @@ builds: - id: linux-build dir: ./cmd/syft binary: syft - goos: - - linux - goarch: - - amd64 - - arm64 - - ppc64le - - s390x - # set the modified timestamp on the output binary to the git timestamp to ensure a reproducible build + goos: [linux] + goarch: [amd64, arm64, ppc64le, s390x] mod_timestamp: &build-timestamp '{{ .CommitTimestamp }}' ldflags: &build-ldflags | -w @@ -34,11 +28,8 @@ builds: - id: darwin-build dir: ./cmd/syft binary: syft - goos: - - darwin - goarch: - - amd64 - - arm64 + goos: [darwin] + goarch: [amd64, arm64] mod_timestamp: *build-timestamp ldflags: *build-ldflags hooks: @@ -50,115 +41,42 @@ builds: - id: windows-build dir: ./cmd/syft binary: syft - goos: - - windows - goarch: - - amd64 + goos: [windows] + goarch: [amd64] mod_timestamp: *build-timestamp ldflags: *build-ldflags archives: - id: linux-archives - builds: - - linux-build - - # note: the signing process is depending on tar.gz archives. If this format changes then .github/scripts/apple-signing/*.sh will need to be adjusted + builds: [linux-build] - id: darwin-archives - builds: - - darwin-build - + builds: [darwin-build] - id: windows-archives format: zip - builds: - - windows-build + builds: [windows-build] nfpms: - license: "Apache 2.0" maintainer: "Anchore, Inc" homepage: &website "https://github.com/anchore/syft" description: &description "A tool that generates a Software Bill Of Materials (SBOM) from container images and filesystems" - formats: - - rpm - - deb + formats: [rpm, deb] brews: - repository: owner: anchore name: homebrew-syft token: "{{.Env.GITHUB_BREW_TOKEN}}" - ids: - - darwin-archives - - linux-archives + ids: [darwin-archives, linux-archives] homepage: *website description: *description license: "Apache License 2.0" dockers: + # production images... - image_templates: - - anchore/syft:debug - - anchore/syft:{{.Tag}}-debug - - ghcr.io/anchore/syft:debug - - ghcr.io/anchore/syft:{{.Tag}}-debug - goarch: amd64 - dockerfile: Dockerfile.debug - use: buildx - build_flag_templates: - - "--platform=linux/amd64" - - "--build-arg=BUILD_DATE={{.Date}}" - - "--build-arg=BUILD_VERSION={{.Version}}" - - "--build-arg=VCS_REF={{.FullCommit}}" - - "--build-arg=VCS_URL={{.GitURL}}" - - - image_templates: - - anchore/syft:debug-arm64v8 - - anchore/syft:{{.Tag}}-debug-arm64v8 - - ghcr.io/anchore/syft:debug-arm64v8 - - ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8 - goarch: arm64 - dockerfile: Dockerfile.debug - use: buildx - build_flag_templates: - - "--platform=linux/arm64/v8" - - "--build-arg=BUILD_DATE={{.Date}}" - - "--build-arg=BUILD_VERSION={{.Version}}" - - "--build-arg=VCS_REF={{.FullCommit}}" - - "--build-arg=VCS_URL={{.GitURL}}" - - - image_templates: - - anchore/syft:debug-ppc64le - - anchore/syft:{{.Tag}}-debug-ppc64le - - ghcr.io/anchore/syft:debug-ppc64le - - ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le - goarch: ppc64le - dockerfile: Dockerfile.debug - use: buildx - build_flag_templates: - - "--platform=linux/ppc64le" - - "--build-arg=BUILD_DATE={{.Date}}" - - "--build-arg=BUILD_VERSION={{.Version}}" - - "--build-arg=VCS_REF={{.FullCommit}}" - - "--build-arg=VCS_URL={{.GitURL}}" - - - image_templates: - - anchore/syft:debug-s390x - - anchore/syft:{{.Tag}}-debug-s390x - - ghcr.io/anchore/syft:debug-s390x - - ghcr.io/anchore/syft:{{.Tag}}-debug-s390x - goarch: s390x - dockerfile: Dockerfile.debug - use: buildx - build_flag_templates: - - "--platform=linux/s390x" - - "--build-arg=BUILD_DATE={{.Date}}" - - "--build-arg=BUILD_VERSION={{.Version}}" - - "--build-arg=VCS_REF={{.FullCommit}}" - - "--build-arg=VCS_URL={{.GitURL}}" - - - image_templates: - - anchore/syft:latest - - anchore/syft:{{.Tag}} - - ghcr.io/anchore/syft:latest - - ghcr.io/anchore/syft:{{.Tag}} + - anchore/syft:{{.Tag}}-amd64 + - ghcr.io/anchore/syft:{{.Tag}}-amd64 goarch: amd64 dockerfile: Dockerfile use: buildx @@ -208,51 +126,120 @@ dockers: - "--build-arg=VCS_REF={{.FullCommit}}" - "--build-arg=VCS_URL={{.GitURL}}" + # debug images... + - image_templates: + - anchore/syft:{{.Tag}}-debug-amd64 + - ghcr.io/anchore/syft:{{.Tag}}-debug-amd64 + goarch: amd64 + dockerfile: Dockerfile.debug + use: buildx + build_flag_templates: + - "--platform=linux/amd64" + - "--build-arg=BUILD_DATE={{.Date}}" + - "--build-arg=BUILD_VERSION={{.Version}}" + - "--build-arg=VCS_REF={{.FullCommit}}" + - "--build-arg=VCS_URL={{.GitURL}}" + + - image_templates: + - anchore/syft:{{.Tag}}-debug-arm64v8 + - ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8 + goarch: arm64 + dockerfile: Dockerfile.debug + use: buildx + build_flag_templates: + - "--platform=linux/arm64/v8" + - "--build-arg=BUILD_DATE={{.Date}}" + - "--build-arg=BUILD_VERSION={{.Version}}" + - "--build-arg=VCS_REF={{.FullCommit}}" + - "--build-arg=VCS_URL={{.GitURL}}" + + - image_templates: + - anchore/syft:{{.Tag}}-debug-ppc64le + - ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le + goarch: ppc64le + dockerfile: Dockerfile.debug + use: buildx + build_flag_templates: + - "--platform=linux/ppc64le" + - "--build-arg=BUILD_DATE={{.Date}}" + - "--build-arg=BUILD_VERSION={{.Version}}" + - "--build-arg=VCS_REF={{.FullCommit}}" + - "--build-arg=VCS_URL={{.GitURL}}" + + - image_templates: + - anchore/syft:{{.Tag}}-debug-s390x + - ghcr.io/anchore/syft:{{.Tag}}-debug-s390x + goarch: s390x + dockerfile: Dockerfile.debug + use: buildx + build_flag_templates: + - "--platform=linux/s390x" + - "--build-arg=BUILD_DATE={{.Date}}" + - "--build-arg=BUILD_VERSION={{.Version}}" + - "--build-arg=VCS_REF={{.FullCommit}}" + - "--build-arg=VCS_URL={{.GitURL}}" + docker_manifests: + # anchore/syft manifests... - name_template: anchore/syft:latest image_templates: - - anchore/syft:{{.Tag}} + - anchore/syft:{{.Tag}}-amd64 + - anchore/syft:{{.Tag}}-arm64v8 + - anchore/syft:{{.Tag}}-ppc64le + - anchore/syft:{{.Tag}}-s390x + + - name_template: anchore/syft:{{.Tag}} + image_templates: + - anchore/syft:{{.Tag}}-amd64 - anchore/syft:{{.Tag}}-arm64v8 - anchore/syft:{{.Tag}}-ppc64le - anchore/syft:{{.Tag}}-s390x - name_template: anchore/syft:debug - - anchore/syft:{{.Tag}}-debug + image_templates: + - anchore/syft:{{.Tag}}-debug-amd64 - anchore/syft:{{.Tag}}-debug-arm64v8 - anchore/syft:{{.Tag}}-debug-ppc64le - anchore/syft:{{.Tag}}-debug-s390x - - name_template: anchore/syft:{{.Tag}} + - name_template: anchore/syft:{{.Tag}}-debug image_templates: - - anchore/syft:{{.Tag}} - - anchore/syft:{{.Tag}}-arm64v8 - - anchore/syft:{{.Tag}}-ppc64le - - anchore/syft:{{.Tag}}-s390x + - anchore/syft:{{.Tag}}-debug-amd64 + - anchore/syft:{{.Tag}}-debug-arm64v8 + - anchore/syft:{{.Tag}}-debug-ppc64le + - anchore/syft:{{.Tag}}-debug-s390x + # ghcr.io/anchore/syft manifests... - name_template: ghcr.io/anchore/syft:latest image_templates: - - ghcr.io/anchore/syft:{{.Tag}} + - ghcr.io/anchore/syft:{{.Tag}}-amd64 + - ghcr.io/anchore/syft:{{.Tag}}-arm64v8 + - ghcr.io/anchore/syft:{{.Tag}}-ppc64le + - ghcr.io/anchore/syft:{{.Tag}}-s390x + + - name_template: ghcr.io/anchore/syft:{{.Tag}} + image_templates: + - ghcr.io/anchore/syft:{{.Tag}}-amd64 - ghcr.io/anchore/syft:{{.Tag}}-arm64v8 - ghcr.io/anchore/syft:{{.Tag}}-ppc64le - ghcr.io/anchore/syft:{{.Tag}}-s390x - name_template: ghcr.io/anchore/syft:debug image_templates: - - ghcr.io/anchore/syft:{{.Tag}}-debug + - ghcr.io/anchore/syft:{{.Tag}}-debug-amd64 - ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8 - ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le - ghcr.io/anchore/syft:{{.Tag}}-debug-s390x - - name_template: ghcr.io/anchore/syft:{{.Tag}} + - name_template: ghcr.io/anchore/syft:{{.Tag}}-debug image_templates: - - ghcr.io/anchore/syft:{{.Tag}} - - ghcr.io/anchore/syft:{{.Tag}}-arm64v8 - - ghcr.io/anchore/syft:{{.Tag}}-ppc64le - - ghcr.io/anchore/syft:{{.Tag}}-s390x + - ghcr.io/anchore/syft:{{.Tag}}-debug-amd64 + - ghcr.io/anchore/syft:{{.Tag}}-debug-arm64v8 + - ghcr.io/anchore/syft:{{.Tag}}-debug-ppc64le + - ghcr.io/anchore/syft:{{.Tag}}-debug-s390x sboms: - artifacts: archive - # this is relative to the snapshot/dist directory, not the root of the repo cmd: ../.tool/syft documents: - "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}.sbom" diff --git a/Dockerfile b/Dockerfile index 9e682b2d6..86b6b643f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,12 @@ -FROM gcr.io/distroless/static-debian12:latest AS build - -FROM scratch -# needed for version check HTTPS request -COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +FROM gcr.io/distroless/static-debian12:nonroot # create the /tmp dir, which is needed for image content cache WORKDIR /tmp COPY syft / +USER nonroot + ARG BUILD_DATE ARG BUILD_VERSION ARG VCS_REF diff --git a/Dockerfile.debug b/Dockerfile.debug index 6559651b6..bfabed8db 100644 --- a/Dockerfile.debug +++ b/Dockerfile.debug @@ -1,10 +1,12 @@ -FROM gcr.io/distroless/static-debian12:debug +FROM gcr.io/distroless/static-debian12:debug-nonroot # create the /tmp dir, which is needed for image content cache WORKDIR /tmp COPY syft / +USER nonroot + ARG BUILD_DATE ARG BUILD_VERSION ARG VCS_REF diff --git a/Taskfile.yaml b/Taskfile.yaml index 88e462128..c4a4236da 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -27,10 +27,12 @@ vars: sh: uname -s | tr '[:upper:]' '[:lower:]' ARCH: sh: | - [ "$(uname -m)" = "x86_64" ] && echo "amd64_v1" || { [ "$(uname -m)" = "aarch64" ] && echo "arm64_v8.0" || echo $(uname -m); } + [ "$(uname -m)" = "x86_64" ] && echo "amd64_v1" || { [ "$(uname -m)" = "aarch64" ] && echo "arm64_v8.0" || [ "$(uname -m)" = "arm64" ] && echo "arm64_v8.0" || echo $(uname -m); } PROJECT_ROOT: sh: echo $PWD + # note: the snapshot dir must be a relative path starting with ./ + # e.g. when installing snapshot debs from a local path, ./ forces the deb to be installed in the current working directory instead of referencing a package name SNAPSHOT_DIR: ./snapshot SNAPSHOT_BIN: "{{ .PROJECT_ROOT }}/{{ .SNAPSHOT_DIR }}/{{ .OS }}-build_{{ .OS }}_{{ .ARCH }}/{{ .PROJECT }}" SNAPSHOT_CMD: "{{ .TOOL_DIR }}/goreleaser release --config {{ .TMP_DIR }}/goreleaser.yaml --clean --snapshot --skip=publish --skip=sign" @@ -230,10 +232,7 @@ tasks: cli: desc: Run CLI tests - # note: we don't want to regenerate the snapshot unless we have to. In CI it's probable - # that the cache being restored with the correct binary will be rebuilt since the timestamps - # and local checksums will not line up. - deps: [tools, snapshot] + deps: [tools] cmds: - cmd: "echo 'testing binary: {{ .SNAPSHOT_BIN }}'" silent: true @@ -573,6 +572,18 @@ tasks: - "{{ .SNAPSHOT_CMD }}" + snapshot-smoke-test: + desc: Run a smoke test on the snapshot builds + docker images + cmds: + - cmd: "echo 'testing snapshot binary: {{ .SNAPSHOT_BIN }}'" + silent: true + - cmd: "test -f {{ .SNAPSHOT_BIN }} || (find {{ .SNAPSHOT_DIR }} && echo '\nno snapshot found for {{ .SNAPSHOT_BIN }}' && false)" + silent: true + - "{{ .SNAPSHOT_BIN }} version" + - "{{ .SNAPSHOT_BIN }} scan alpine:latest" + - docker run --rm anchore/syft:latest version + - docker run --rm anchore/syft:latest scan alpine:latest + changelog: desc: Generate a changelog deps: [tools]