diff --git a/docs/areas/hosting.md b/docs/areas/hosting.md index ed6b548..f4042c2 100644 --- a/docs/areas/hosting.md +++ b/docs/areas/hosting.md @@ -135,8 +135,16 @@ registry never delays or prevents startup. - The process runs as UID `64000` in the root group (GID `0`), never as UID `0`. `/app` is owned by `64000:0` with group permissions equal to owner permissions, so the application also works when started with another UID in group `0`. Membership in group `0` keeps a `root:root` Docker socket readable where the socket grants group access. -- The Trivy CLI is bundled at `/usr/local/bin/trivy` (taken from `aquasec/trivy:0.58.1` by default) with its cache in - `/tmp/trivy`, so Trivy client mode works without extra installation (see [Vulnerabilities](vulnerabilities.md)). +- The Trivy CLI is bundled at `/usr/local/bin/trivy` (taken from the digest-pinned `aquasec/trivy` image of v0.76.1, + by default) with its cache in `/tmp/trivy`, so Trivy client mode works without extra installation (see + [Vulnerabilities](vulnerabilities.md)). The deployment tiers of the documented compose files run the Trivy server + of the same version. +- The image sets `TRIVY_SKIP_VERSION_CHECK=true` and `TRIVY_DISABLE_TELEMETRY=true`, so Trivy sends no update check + or usage data to `check.trivy.dev` and contacts only the Trivy server, the Docker Engine at `/var/run/docker.sock` + when it is mounted there, and the registries, including Trivy's Java DB repository when an image contains Java + archives. Setting either to `false` brings the request back, and a Trivy run + outside the image needs both set by the operator + ([0016](../decisions/0016-the-bundled-trivy-skips-its-update-check-and-telemetry.md)). - The image sets `DockerUpdateGuard__DisplayVersion` to the version it was built with. - CA certificates are installed so outbound TLS connections can be verified. - Before the application starts, the entrypoint: @@ -218,6 +226,8 @@ These properties hold today and must be provided for by the deployment: through a private directory appended to `SSL_CERT_DIR`, so no write access to the system trust store is needed. - [0012](../decisions/0012-configured-urls-are-rejected-when-an-at-sign-is-not-their-user-info-separator.md): configured URLs are rejected when an `@` is not their user-info separator. +- [0016](../decisions/0016-the-bundled-trivy-skips-its-update-check-and-telemetry.md): the bundled Trivy skips its + update check and telemetry through the image's environment. ## Not here diff --git a/docs/areas/vulnerabilities.md b/docs/areas/vulnerabilities.md index 6f4bb67..37b420e 100644 --- a/docs/areas/vulnerabilities.md +++ b/docs/areas/vulnerabilities.md @@ -98,6 +98,10 @@ scan run: process environment, added to the environment inherited from the application (an inherited `TRIVY_SERVER` is replaced), so it does not stand on the command line, where every user who can see the process could read the user info. +- Besides the Trivy server, the Trivy process contacts only the Docker Engine at `/var/run/docker.sock` (Trivy reads + the image from it first when the socket is mounted there) and the registries, including Trivy's Java DB repository + when an image contains Java archives; the container image switches off Trivy's update check and telemetry + ([Hosting](hosting.md#container-image)). - The target is `:` for `docker.io` images and `/:` otherwise, followed by `@` when the digest is known. - The process gets `RequestTimeoutSeconds` plus 10 seconds. When that passes, the process and its children are killed @@ -196,6 +200,8 @@ The dashboard shows at most one hint about the vulnerability configuration: environment. - [0015](../decisions/0015-the-trivy-scan-target-follows-an-end-of-options-marker.md): the Trivy scan target follows an end-of-options marker (`--`). +- [0016](../decisions/0016-the-bundled-trivy-skips-its-update-check-and-telemetry.md): the bundled Trivy skips its + update check and telemetry through the image's environment. ## Not here diff --git a/docs/decisions/0005-urls-are-output-with-user-info-masked.md b/docs/decisions/0005-urls-are-output-with-user-info-masked.md index 9543ccd..012c23f 100644 --- a/docs/decisions/0005-urls-are-output-with-user-info-masked.md +++ b/docs/decisions/0005-urls-are-output-with-user-info-masked.md @@ -115,7 +115,7 @@ added to the environment it inherits from the application, and no `--server` arg environment by the application's own user and by root, as the configuration it comes from already is. Trivy still repeats it in its error output, so the withholding above stays. - A Trivy executable that does not read `TRIVY_SERVER` (a custom `TrivyExecutablePath`) would scan without a server, - downloading the vulnerability database itself; the bundled Trivy v0.58.1 reads it. A token setting of our own is + downloading the vulnerability database itself; the bundled Trivy v0.76.1 reads it. A token setting of our own is not added: `TRIVY_TOKEN` in the application's environment reaches Trivy already. - The Trivy process inherits the application's whole environment, other secrets supplied as environment variables included. It is not reduced to an allow-list: the process runs as the application's user, which can read the diff --git a/docs/decisions/0015-the-trivy-scan-target-follows-an-end-of-options-marker.md b/docs/decisions/0015-the-trivy-scan-target-follows-an-end-of-options-marker.md index bd5b29d..e50f45b 100644 --- a/docs/decisions/0015-the-trivy-scan-target-follows-an-end-of-options-marker.md +++ b/docs/decisions/0015-the-trivy-scan-target-follows-an-end-of-options-marker.md @@ -40,8 +40,8 @@ ever read as a Trivy option. The argument list is described in [Vulnerabilities] - A registered reference that begins with `-` is scanned as an image name; when Trivy cannot pull it, its scan ends with a non-zero exit code and is reported like any other image Trivy cannot find. -- The protection rests on Trivy honoring `--`. It was measured on Trivy v0.76.1: without `--`, `--config=x.y/z:latest` - is read as the configuration file option; after `--`, `--config=…`, `--input=…` and `-a/b` targets are taken as image - names and fail, and a normal target scans as before. The bundled v0.58.1 could not be measured (its release archive - is no longer published); moving the bundled version to a measured one is tracked as a follow-up, and any later Trivy - update is measured again with the same cases. \ No newline at end of file +- The protection rests on Trivy honoring `--`. It was measured on Trivy v0.76.1, the version the image bundles + (pinned by digest, the digest of the v0.76.1 image index, so the build copies the measured binary): without + `--`, `--config=x.y/z:latest` is read as the configuration file option; after `--`, `--config=…`, `--input=…` and `-a/b` targets are taken as image names + and fail without opening the file they name, and a normal target takes the normal scan path. Any later Trivy update + is measured again with the same cases. \ No newline at end of file diff --git a/docs/decisions/0016-the-bundled-trivy-skips-its-update-check-and-telemetry.md b/docs/decisions/0016-the-bundled-trivy-skips-its-update-check-and-telemetry.md new file mode 100644 index 0000000..0ae31cf --- /dev/null +++ b/docs/decisions/0016-the-bundled-trivy-skips-its-update-check-and-telemetry.md @@ -0,0 +1,46 @@ +# 0016: The bundled Trivy skips its update check and telemetry + +- **Status:** Accepted +- **Date:** 2026-10-29 +- **Area:** Hosting and configuration +- **Source:** Issue #372 +- **Supersedes:** — + +## Context + +The image bundles the Trivy CLI, which the Trivy provider starts for every scan in client mode against the operator's +Trivy server ([Vulnerabilities](../areas/vulnerabilities.md#trivy)). Trivy v0.76.1, the version issue #372 bundles, +sends on every `trivy image` run a background request to `https://check.trivy.dev/updates` with a stable host +identifier (a SHA-256 of the host name and the first MAC address), the command, the flag names, the OS and the +architecture. `--quiet`, which the provider passes, only hides the printed notice; the request stops only when both +the version check and telemetry are switched off. v0.58.1, the version bundled before, makes no such call. A +deployment with restricted egress would gain an outbound destination it never allowed, and every scan would report +a host fingerprint to a third party, without anything in DockerUpdateGuard asking for it. + +## Options considered + +1. **Set `TRIVY_SKIP_VERSION_CHECK=true` and `TRIVY_DISABLE_TELEMETRY=true` in the image's environment** — no code + change; every Trivy the application starts inside the image inherits them, a custom `TrivyExecutablePath` + included, and an older Trivy ignores environment variables it does not know. Outside the image the operator + sets them. Chosen. +2. **Add `--skip-version-check --disable-telemetry` to the provider's argument list** — also covers a Trivy run + outside the image, but changes production code, its tests and the argument list of + [0015](0015-the-trivy-scan-target-follows-an-end-of-options-marker.md), and an older custom Trivy without these + flags fails every scan with `unknown flag`. +3. **Leave it to the operator** (document the call, block it by network policy) — every default deployment would + send the fingerprint until someone notices. + +## Decision + +The container image sets `TRIVY_SKIP_VERSION_CHECK=true` and `TRIVY_DISABLE_TELEMETRY=true`, so the bundled Trivy +sends nothing to `check.trivy.dev`; the provider's arguments stay unchanged. The behavior is +described in [Hosting](../areas/hosting.md#container-image). + +## Consequences + +- An operator who sets either variable to `false` in the container gets Trivy's update notice request back; that is + the operator's choice. +- A Trivy started outside the image (the application run without the container) gets the suppression only from the + operator's environment. +- Measured on the bundled v0.76.1 with a control run (issue #372); a later Trivy update is measured again, since a + new release may add another outbound call or rename the variables. \ No newline at end of file diff --git a/docs/decisions/README.md b/docs/decisions/README.md index 226af35..2bc9802 100644 --- a/docs/decisions/README.md +++ b/docs/decisions/README.md @@ -68,4 +68,5 @@ once in the [area document](../areas/README.md) of the record's area, and the re | [0013](0013-docker-instance-keys-are-named-relative-to-the-instance.md) | Validation messages name Docker instance keys relative to the instance | Accepted | 2026-10-27 | | [0014](0014-registry-tag-names-and-digests-are-validated-where-they-are-read.md) | Remote tag names, digests, image references and names are validated or bounded where they are read | Accepted | 2026-10-28 | | [0015](0015-the-trivy-scan-target-follows-an-end-of-options-marker.md) | The Trivy scan target follows an end-of-options marker | Accepted | 2026-10-29 | +| [0016](0016-the-bundled-trivy-skips-its-update-check-and-telemetry.md) | The bundled Trivy skips its update check and telemetry | Accepted | 2026-10-29 | diff --git a/docs/docker-compose.full.yml b/docs/docker-compose.full.yml index 7f45879..c2604ab 100644 --- a/docs/docker-compose.full.yml +++ b/docs/docker-compose.full.yml @@ -27,7 +27,7 @@ services: retries: 5 trivy: - image: aquasec/trivy:0.58.1 + image: aquasec/trivy:0.76.1 container_name: dockerupdateguard-trivy restart: unless-stopped command: ["server", "--listen", "0.0.0.0:4954"] diff --git a/docs/docker-compose.trivy.yml b/docs/docker-compose.trivy.yml index ab0d54f..fb3e60b 100644 --- a/docs/docker-compose.trivy.yml +++ b/docs/docker-compose.trivy.yml @@ -25,7 +25,7 @@ services: retries: 5 trivy: - image: aquasec/trivy:0.58.1 + image: aquasec/trivy:0.76.1 container_name: dockerupdateguard-trivy restart: unless-stopped command: ["server", "--listen", "0.0.0.0:4954"] diff --git a/src/DockerUpdateGuard/Dockerfile b/src/DockerUpdateGuard/Dockerfile index d7f277b..5eb6e5e 100644 --- a/src/DockerUpdateGuard/Dockerfile +++ b/src/DockerUpdateGuard/Dockerfile @@ -1,7 +1,8 @@ ARG BASE_SDK="mcr.microsoft.com/dotnet/sdk:10.0-alpine" ARG BASE_RUNTIME="mcr.microsoft.com/dotnet/aspnet:10.0-alpine" ARG BASE_RUNTIME_DIGEST -ARG TRIVY_IMAGE="aquasec/trivy:0.58.1" +# Trivy v0.76.1 (digest of the multi-arch image index) +ARG TRIVY_IMAGE="aquasec/trivy@sha256:790fd66d1697395d8693d1acaa1ea702406a20f109b6fc7bac8db623eca6c06c" ARG APP_VERSION=1.0.0 # --------------------------- @@ -56,6 +57,10 @@ RUN apk add --no-cache ca-certificates # The cache directory lives under /tmp so any runtime UID can write it. COPY --from=trivy /usr/local/bin/trivy /usr/local/bin/trivy ENV TRIVY_CACHE_DIR=/tmp/trivy +# Trivy's update check and telemetry would send a host identifier to check.trivy.dev on every scan; +# both are off so Trivy sends nothing to check.trivy.dev. +ENV TRIVY_SKIP_VERSION_CHECK=true +ENV TRIVY_DISABLE_TELEMETRY=true COPY --from=build /app/publish .