Skip to main content

Overview

CPLN Trivy automates vulnerability scanning for every image in your Control Plane image registry. A scheduled daemon queries the registry for unscanned images, runs Trivy against each one, and stores an HTML report in S3 or an Azure File Share. After each scan, the image is tagged with a direct link to its report — visible in the Control Plane console.
Upgrading an install created with 1.1.0 or earlier is a breaking change. postToken is no longer a plain value; the bearer token now lives in an opaque secret you create, named by postToken.secretName. Put the same token your install already uses into that secret — a different one makes report uploads start failing with 401 while every status surface still reads healthy. See Upgrading From 1.1.0.
Running a scan tags and reports on every image in the organization, not only images this install created. The daemon enumerates the whole registry, writes two tags to each image it scans, and uploads a report per image to your bucket. Before pointing this at a production organization, understand that it mutates images it did not create. Narrow the blast radius by setting schedule to a time you choose and rescanAfter to "" for a first run.

Architecture

  • daemon (cron workload) — Runs on a configurable schedule, queries the registry for images that do not yet have a cpln/trivy-scan tag, and orchestrates scanning. Includes a trivy-api sidecar that wraps the Trivy CLI and returns HTML vulnerability reports.
  • web-server (serverless workload) — Receives scan reports from the daemon, stores them in the configured storage backend, and serves them publicly via URL.
After each scan, the daemon writes two tags to the image: Each run scans images that do not yet have a cpln/trivy-scan tag. When rescanAfter is set (default 7d), images whose last scan is older than that window are scanned again and their report is refreshed in place at the same URL. Setting rescanAfter to "" disables rescanning — then re-scanning an image requires removing its cpln/trivy-scan tag first.

How the Two Workloads Talk

The daemon reaches the web-server over the public internet, not over the GVC network. The two workloads have no in-GVC path to each other, so the daemon posts each report to the web-server’s public endpoint — and that endpoint gates writes on the bearer token alone. That is why the token is a prerequisite secret rather than internal plumbing. Through 1.1.0 it shipped as the value postToken: changeme, which meant an internet-facing write endpoint guarded by a string published in a public repository: anyone could upload content into the user’s own bucket and have it served back as HTML from their report URLs. Nothing about that credential is unreachable from outside the GVC, which is exactly the condition the bundled-credential exception depends on.

What Gets Created

  • Cron Daemon Workload — Trivy daemon with trivy-api sidecar, runs on a cron schedule.
  • Serverless Web-Server Workload — Report storage and serving, autoscales from 1–3 replicas.
  • Identity & Policies — An identity carrying the AWS or Azure cloud-account binding for report storage, plus least-privilege policies: reveal on exactly the two prerequisite secrets, manage on images so scan tags can be written, and pull/view for the scanning service account.
  • No credential secrets — The template creates no secrets of its own. Both the post token and the registry service account key live in secrets you create.
This template does not create a GVC. You must deploy it into an existing GVC.

Prerequisites

Two secrets must exist before you install. Secrets are org-level, so no GVC flag is involved.

Report Post Token

The bearer token the daemon presents when uploading a report. It guards a publicly reachable write endpoint, so treat it like any other internet-facing credential.
1

Create the post token secret

An opaque secret with encoding plain whose payload is the token:
Set postToken.secretName to the name you used. Use printf, not echoecho appends a newline that becomes part of the token.
2

Read it back later

-o yaml is required; without it the command prints the secret’s metadata table rather than its payload:
The token is enforced, and only in the Bearer form. Verified against the live public endpoint: a POST with no Authorization header, one with a wrong token, and one carrying the correct token without the Bearer prefix were all refused with 401; only Authorization: Bearer <token> was accepted. Report reads remain deliberately unauthenticated — the URL’s SHA-256 hash is the only thing protecting a report.

Registry Service Account

Trivy authenticates against the Control Plane image registry using a service account key stored in an opaque secret.
1

Create or select a service account

Create a Control Plane service account (or use an existing one). Set serviceAccountName in values.yaml to its name — the template grants it image pull and view permissions automatically.
2

Generate a key

Generate a key for the service account and copy the key value. It cannot be retrieved later.
3

Store the key in an opaque secret

4

Reference the secret in values.yaml

The template grants the workload identity reveal access automatically:
A missing prerequisite secret wedges the install rather than failing it. cpln helm install still exits 0 and reports success, the resources are created, and the workload then never starts. Because the container never ran, cpln logs returns zero lines, which reads as a broken platform rather than a missing prerequisite.The only diagnostic is status.versions[].message, which names the missing secret:
It is get-deployments — plain cpln workload get has no versions key at all. Creating the missing secret clears the wedge on its own, but slowly: recovery here was measured at 9 minutes 15 seconds, inside the 5.5–10.5 minute range seen across the catalog, so poll rather than time-boxing it. A forced redeployment shortcuts it to roughly 90 seconds. The previously deployed revision keeps serving reports throughout.

Storage

Choose a storage backend — either AWS S3 or Azure File Share. Set storage.type to the appropriate value and configure only that section.
1

Create an S3 bucket

Create an S3 bucket in your AWS account to store scan reports. Set storage.s3.bucket and storage.s3.region.
2

Register a Cloud Account

If you do not have one, create an AWS Cloud Account in Control Plane. Set storage.s3.cloudAccountName to its name.
3

Create an IAM policy

Create an IAM policy scoped to your bucket (replace YOUR_BUCKET_NAME) and set storage.s3.policyName to its name:
Once both secrets exist and your storage backend is ready, install the template using your preferred method:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations

Pulumi

Declare templates in your Pulumi programs

Configuration

The default values.yaml for this template:

Configuration Reference

Report URLs are publicly accessible by default — they contain an unguessable SHA-256 hash, but no authentication on reads. Restrict webServer.firewall.inboundAllowCIDR if reports must stay private. Narrowing it also blocks the daemon, which reaches the web-server by that same public path, so add the daemon’s egress range when you do.
webServer.firewall.inboundAllowCIDR defaults to 0.0.0.0/0 by design — that is how the daemon delivers reports. The token is what keeps that endpoint from accepting anyone’s uploads; see How the Two Workloads Talk.

Upgrading From 1.1.0

Version 1.2.0 moved the report post token out of Helm values. Through 1.1.0 it shipped as postToken: changeme — a working, publicly documented token guarding an internet-facing write endpoint.
Reuse the token your install already has. The daemon and the web-server compare the same string, so a rotation that reaches only one of them fails every upload with 401 while both workloads still report healthy. If you generate a fresh token during the upgrade, both workloads pick it up together on the same rollout — but any token you had recorded elsewhere is then dead.
A helm upgrade that still sets postToken as a string is rejected before anything is applied. A real cpln helm upgrade carrying the old shape failed at render, created no Helm revision, and left the running release healthy and untouched:
Leaving postToken.secretName empty is refused the same way.
To upgrade an existing install:
1

Create the post token secret

Follow Prerequisites, putting your current token into it.
2

Drop the removed key from your values

Remove the postToken: string and set postToken.secretName instead. Leave trivyAuth.secretName and serviceAccountName exactly as they are.
3

Upgrade

Both workloads pick the token up on the rollout. Reports already stored keep their URLs.

Rotating the Token Later

Edit the secret, then restart both workloads together. They must agree; a rotation reaching only one leaves uploads failing 401 with nothing else looking wrong.

Viewing Reports

Once the daemon has run, navigate to any scanned image in the Control Plane console. The cpln/trivy-scan tag on the image contains a direct URL to the HTML vulnerability report. Opening that URL serves the report from the web-server. To list all scanned images via CLI:

Maintenance

Periodic Re-Scans

With rescanAfter set (default 7d), re-scans happen automatically: any image whose last scan is older than the window is scanned again on the next daemon run, and its report is refreshed at the same URL. Adjust the window (e.g. 24h for daily) or set it to "" to scan each image only once.

Force an Immediate Re-Scan

To re-scan an image before its rescanAfter window elapses, remove its scan tags:
To reset all scan tags and trigger a full re-scan on the next daemon run:
The daemon will pick the images up on its next scheduled run.

Important Notes

  • Create both prerequisite secrets before installing. A missing one wedges the deployment with no log output at all; Prerequisites gives the one command that diagnoses it.
  • A scan touches every image in the organization, not just images this install created — see the warning in Overview.
  • Rotating the post token requires restarting both workloads together — see Rotating the Token Later.
  • Report reads are unauthenticated. Anyone with the URL can open a report.
  • Scans take roughly 15–20 seconds per image — about 30 minutes for 100 images on a first run. Overlapping runs are prevented, so a long run simply delays the next scheduled one.
  • Rescans overwrite in place — the report keeps its URL and cpln/trivy-scan-time is refreshed, so links saved from the console stay valid.
  • Rotate the service account key by adding a new key, updating the opaque secret’s payload, then deleting the old key. No reinstall needed.
  • The workloads are named daemon and web-server regardless of release name — install this template only once per GVC.

External References

Trivy Documentation

Official Trivy vulnerability scanner documentation

Create a Cloud Account

Set up AWS or Azure cloud accounts for storage access