Repository navigation
Add Trivy vulnerability scanning for Docker images - #181
Conversation
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
maximthomas
left a comment
There was a problem hiding this comment.
praise: The scan is wired the way the description says, and the details that usually go wrong are right.
limit-severities-for-sarif: true(build.yml:133,docker-scan.yml:50) keeps theCRITICAL,HIGHfilter in effect for SARIF output.aquasecurity/trivy-actionis pinned by SHA (ed142fd…, v0.36.0), and.github/dependabot.ymlkeeps that pin moving.- The fork-PR claim holds: this PR's own
build-dockerrun (fork, tokenSecurityEvents: read) logged "Successfully uploaded results" fortrivy-build-default.
question (non-blocking): Should a Trivy outage (DB download, setup-trivy fetch) fail build-docker and the Build workflow?
.github/workflows/build.yml:123-136
exit-code is unset, so findings exit 0. But with cache: false every run downloads trivy-db (114 MiB) and trivy-java-db (923 MiB) from mirror.gcr.io. If both registries in trivy's fallback fail, or setup-trivy cannot fetch the binary, trivy exits non-zero, and the step has no continue-on-error. build-docker then goes red with no code change. On a push to master, deploy.yml:14 (workflow_run of Build, conclusion == 'success') also skips the snapshot deploy for that commit. This is rare (trivy falls back from mirror.gcr.io to ghcr.io on 408/429/5xx) and a re-run fixes it, so it is minor as written. If "findings do not fail the build" was meant as "the scan never fails the build", it is a bug worth fixing here. If failing on an outage is intended, one line in the step comment saying so is enough.
- name: Scan image for vulnerabilities (Trivy)
# trivy resolves the image from the local Docker daemon, so only the runner's
# linux/amd64 manifest is scanned; cache: false keeps the ~1GB trivy DBs from
# evicting the m2-repository caches out of the repo's 10GB actions-cache quota
# a scanner outage must not fail the build either; the upload step skips a missing report
continue-on-error: true
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0suggestion (non-blocking): docker-scan.yml is never executed before merge.
.github/workflows/docker-scan.yml:19-22, :44-59
The workflow triggers only on schedule and workflow_dispatch, and workflow_dispatch returns 404 until the file is on the default branch, so this PR's checks have no Docker Scan run. The green build-docker run covers only the build.yml copy, which uses a literal filename and a local-registry image. It does not exercise hashFiles(format('trivy-{0}.sarif', matrix.tag)), the remote Docker Hub pull or the job-level fork guard. A typo in any of them would only show up on the first Monday after merge. As written, they look right.
on:
schedule:
- cron: '30 5 * * 1'
workflow_dispatch:
pull_request:
paths:
- '.github/workflows/docker-scan.yml'Pin: with this trigger, this PR's checks include a Docker Scan run that uploads a trivy-image-latest analysis, and a broken format() guard shows up as a skipped upload step. Or: run gh workflow run docker-scan.yml once, right after merge.
suggestion (non-blocking): The docker-scan.yml scan job has no timeout-minutes.
.github/workflows/docker-scan.yml:28-38
Trivy's default 5-minute --timeout bounds the vuln DB download and the image pull. It does not bound the Java DB update (trivy v0.70.0 javadb/client.go:49 uses context.Background()) or the setup-trivy binary download. A stalled fetch therefore holds the weekly run until GitHub's 360-minute default. In this PR's run, build-docker's scan took about 35 s including both DB downloads.
scan:
# Do not run the scheduled scan in forks; manual runs are always allowed.
if: github.event_name == 'workflow_dispatch' || github.repository == 'OpenIdentityPlatform/OpenIG'
runs-on: ubuntu-latest
timeout-minutes: 30suggestion (non-blocking): The upload steps use always() where their comment asks only for "even if a preceding step failed".
.github/workflows/build.yml:140, .github/workflows/docker-scan.yml:56
Under build.yml's concurrency block (cancel-in-progress: true), always() keeps the upload running on a run that was superseded after its SARIF was written. Nothing wrong is uploaded, because the newer run's analysis arrives minutes later and wins. The gain is a condition that matches the comment and a slightly faster cancel.
if: ${{ !cancelled() && hashFiles('trivy-results.sarif') != '' }}suggestion (non-blocking): The new checkouts keep the default persist-credentials, though neither job runs a git command.
.github/workflows/build.yml:77, .github/workflows/docker-scan.yml:40
Nothing leaks today: checkout v7 keeps the token under $RUNNER_TEMP, not in .git/config, and the docker/* and trivy actions get github.token through their own inputs anyway. In a job with security-events: write, persist-credentials: false is free hardening, and zizmor-style linters ask for it.
- uses: actions/checkout@v7
with:
persist-credentials: falsesuggestion (non-blocking): The new code leaves actions/checkout@v7 and github/codeql-action/upload-sarif@v4 on mutable tags, while trivy-action is SHA-pinned.
.github/workflows/docker-scan.yml:40, :54, .github/workflows/build.yml:77, :138
#170 pins the uses: lines of build.yml, codeql.yml, deploy.yml and release.yml as they stand on master. Whichever of #170 and #181 lands second therefore leaves these four lines as the only mutable tags in jobs with security-events: write. Exposure does not change today, since codeql.yml already runs the same tags with the same permission. It is a follow-up for whichever PR lands second to name.
note (non-blocking): The description doesn't match the checks.
- The description says PRs get a "Code scanning results / trivy-build-default" check. This PR's check list shows it as
Trivy;trivy-build-defaultis only the SARIF category.
build.yml: scan the freshly built image in build-docker right after the docker tests and upload the SARIF report to code scanning (category trivy-build-default). Only fixable CRITICAL/HIGH CVEs are reported and findings do not fail the build. docker-scan.yml (new): weekly scan of the published openidentityplatform/openig:latest image, unfixed CVEs included, so that new CVEs in the released image surface without a change in this repo. Same setup as OpenIdentityPlatform/OpenDJ#854: severity filter kept for SARIF via limit-severities-for-sarif, trivy DB cache disabled to keep the ~1GB DBs from evicting the m2-repository caches, action pinned by SHA.
Same file as in OpenIdentityPlatform#170; whichever PR lands first brings it in.
- build.yml: continue-on-error on the Install and Scan steps, so a Trivy or trivy-db outage no longer turns build-docker red and skips the snapshot deploy; a 15-minute step timeout bounds the Java DB download, which trivy's own --timeout does not. - Install Trivy v0.70.0 with its own setup-trivy step (cache: true) and run trivy-action with skip-setup-trivy: true: its cache: false also skipped the binary cache and left an anonymous github.com lookup in every run. - docker-scan.yml: timeout-minutes: 30; document the neutral "1 configuration not found" PR check and the linux/amd64-only scan; "gate" -> "scan". - Both: persist-credentials: false on checkout; upload on !cancelled() instead of always().
957ea20 to
793334e
Compare
|
@maximthomas addressed in 793334e. Before that I rebased the branch onto current Trivy outage fails
No
Mutable tags on Description vs. checks (note). Rewritten. It now names the Also taken over from the sibling rounds, though not raised here:
The description is also corrected on the actions cache: it is at 2.4 GiB today, not at the quota. |
maximthomas
left a comment
There was a problem hiding this comment.
praise: The new commit makes the scan genuinely non-fatal on the outage it targets, and the comments explaining it are accurate.
continue-on-error+timeout-minutes: 15on the Scan step (.github/workflows/build.yml:141-142): actions/runner v2.338.0, the version this job ran, records a composite step's timeout as Failed and continue-on-error converts it, so a stalled Java DB fetch costs at most 15 minutes and leaves build-docker green.- The
hashFiles('trivy-results.sarif') != ''guard (build.yml:157) holds on that path: trivy v0.70.0 creates--outputonly after a successful scan (pkg/report/writer.go:35viarunner.Report), so a DB outage skips the upload instead of failing it on an empty SARIF. - "trivy's own --timeout does not bound the Java DB download" is right (
pkg/javadb/client.go:49runs it undercontext.Background()). So is "linux/amd64 only", on both the daemon path in build.yml and the remote path in docker-scan.yml (go-containerregistry's default platform).
Adds Docker image vulnerability scanning with Trivy, the same setup as OpenIdentityPlatform/OpenDJ#854 in its final, reviewed form, plus what the later sibling PRs settled (OpenIdentityPlatform/OpenICF#135, OpenIdentityPlatform/OpenIDM#216): a separately cached Trivy install and a scan that cannot fail the build.
build.yml—build-dockernow scans the freshly built image (resolved from the local Docker daemon, so the runner'slinux/amd64manifest only) right after the docker test. The image is built from this commit'sOpenIG-*.war(theubuntu-latest-11artifact; the Dockerfile downloads the release war only when none was copied in), so the scan covers this commit's dependencies plus thetomcatbase image. The SARIF report is uploaded viacodeql-action/upload-sarifand the full list lives in the Security tab. Only fixable CRITICAL/HIGH CVEs are reported (ignore-unfixed: truepluslimit-severities-for-sarif: true— without the latter the severity filter is silently dropped for SARIF output), and only the vulnerability scanner runs (scanners: vuln).exit-code), and the Install and Scan steps arecontinue-on-error, so a Trivy or trivy-db registry outage cannot turnbuild-dockerred — a red Build would also skip the snapshot deploy indeploy.yml. The scan step hastimeout-minutes: 15: trivy's own--timeoutdoes not bound the Java DB download. The upload runs on!cancelled()and only when a report exists.cache: false): it saves the ~1 GB trivy DBs per branch scope and day, which would fill the repo's 10 GB actions-cache quota within days and LRU-evict them2-repositorycaches (350–480 MiB each) thebuild-mavenmatrix depends on. The cache stood at 10.12 GiB when this PR was opened.cache: falsewould also skip setup-trivy's binary cache and leave an anonymous github.com release lookup in every run (it lost a scan in OpenICF#135), so Trivyv0.70.0(trivy-action v0.36.0's default) is installed by its ownaquasecurity/setup-trivystep withcache: true, and trivy-action runs withskip-setup-trivy: true.Trivycheck-run per SARIF tool, next toCodeQL;trivy-build-defaultis only the SARIF category. That check is diff-scoped: image-path alerts never fall inside a PR diff, so it reports "No new alerts in code changed by this pull request" whatever the scan found. The findings for a PR are in the Security tab underpr:<N> tool:Trivy.contents: read+security-events: write; SARIF upload also works for fork PRs on public repositories.actions/checkout@v7(withpersist-credentials: false) is added as the first step of the job, as in OpenDJ, soupload-sarifhas a git checkout to work from (beforedownload-artifact, since checkout cleans the workspace).docker-scan.yml(new) — weekly cron (30 5 * * 1, no overlap with CodeQL's27 3 * * 1) +workflow_dispatchscan of the publishedopenidentityplatform/openig:latestimage: new CVEs surface in the already-released image (mostly via thetomcatbase image) without any change in this repository. Unlike the build-time scan, unfixed CVEs are reported too — surfacing them in a released image is the point. Report categorytrivy-image-latest, distinct fromtrivy-build-default. The scheduled run is skipped in forks; manual runs are always allowed. OpenIG publishes a single image variant, so the matrix has one tag.linux/amd64manifest is scanned (no--platformis passed); the other published platforms (arm64, ppc64le, s390x) are not.continue-on-errorhere: a failed weekly scan is the signal. The job hastimeout-minutes: 30, for the same reason as the build-time step.trivy-image-latestexists only on master, so every PR'sTrivycheck concludes neutral with "1 configuration not found" (as on OpenAM PRs today). This is documented in the workflow header.gh workflow run docker-scan.yml) right after merge and report the run here.aquasecurity/trivy-action(ed142fd…, v0.36.0 — the current latest) andaquasecurity/setup-trivy(81e5143…, v0.3.1) are pinned by commit SHA;actions/*andgithub/codeql-actionstay on major tags, the policy of #170..github/dependabot.yml(new, second commit) enables thegithub-actionsecosystem so the pinned SHAs keep getting updated: weekly, one grouped PR for all actions, labelsci+dependencies. It is byte-identical to the file added in #170, so whichever PR lands first brings it in without a conflict. Not used:TRIVY_INSECURE(global TLS off, and not needed — the image is read from the daemon, the registry is never contacted).Overlap with #170: both touch
build.yml, in different hunks (#170: workflow-levelpermissionsand theuses:pins; here: thebuild-dockerjob header, its first step and its tail). The added license header is the identical block, so it should merge cleanly either way.This PR's own
build-dockerrun exercises the new build-time steps.