Skip to main content

Overview

CPLN Trivy scans the images in your Control Plane image registry for known vulnerabilities. A scheduled daemon finds images that have not been scanned yet (or whose last scan is older than rescanAfter), runs Trivy against each one, and hands the HTML report to a small web server that stores it in your own S3 bucket or Azure file share. The daemon then tags the image with a direct link to its report, so the result is one click away in the Control Plane console.
This template does not create a GVC. It deploys into an existing GVC that you already have, passed with --gvc GVC_NAME at install time.
A scan run covers 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 one report per image to your storage. Before pointing it at a production organization, decide on a schedule and set rescanAfter to "" if you want each image scanned only once.
After each scan the image carries two tags:

What Gets Created

The workload names daemon and web-server do not include the release name, so install this template only once per GVC. The template creates no secrets of its own.

Prerequisites

Two opaque secrets, a service account and report storage must exist before you install. Secrets are org-level, so no GVC flag is involved. This template uses two secrets, so the commands below call them POST_TOKEN_SECRET_NAME and REGISTRY_SECRET_NAME.
1

Create the report post token secret

The daemon presents this bearer token when it uploads a report to the web server. The upload endpoint is reachable from the public internet, and this token is the only thing guarding it. Create an opaque secret holding a random token:
Set postToken.secretName to this name.
2

Create a registry service account and key

Trivy pulls images from your registry as a service account. Create a service account (or pick an existing one), add a key to it, and copy the key value, which cannot be retrieved later. The template grants this service account pull and view on images.Set serviceAccountName to the service account name.
3

Store the service account key in an opaque secret

Set trivyAuth.secretName to this name.
4

Prepare report storage

Set storage.type to s3 or azureFileshare and complete the matching steps.
  1. Create an S3 bucket. Set storage.s3.bucket to its name and storage.s3.region to its region.
  2. Create an AWS cloud account in Control Plane if you do not have one. Set storage.s3.cloudAccountName to its name.
  3. Create an IAM policy scoped to the bucket (replace YOUR_BUCKET_NAME) and set storage.s3.policyName to the policy name. Access is keyless: the identity receives temporary credentials, so no AWS keys are stored.
Create both secrets before installing, or the deployment wedges silently. A name that points at a secret which does not exist installs successfully and then never starts. The container never runs, so cpln logs returns no lines at all. The one place the reason appears is status.versions[].message:
Use get-deployments; plain cpln workload get has no versions key. Once you create the missing secret the workload recovers on its own after several minutes, or immediately with a forced redeployment:

Installation

Install with the values for your storage, secrets and service account. This example uses S3:
For Azure, set storage.type=azureFileshare and the four storage.azureFileshare.* values instead of the storage.s3.* values. You can also install from the UI, Terraform or Pulumi:

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

Storage

Configure only the block that matches storage.type.

Authentication

Both secret names must point at secrets that already exist (see Prerequisites).

Scanning

rescanAfter must be a number followed by d (days) or h (hours), such as 7d or 24h. With an empty value each image is scanned once; see Forcing a Rescan to scan it again.

Workloads

Narrowing webServer.firewall.inboundAllowCIDR also blocks the daemon. The daemon delivers reports to the web server through its public endpoint, so if you restrict inbound access to keep reports private, include the address range your daemon’s traffic leaves from, or uploads stop.

Connecting

The template has no login screen. Each scan result is an HTML report served by the web-server workload at the URL stored in the image’s cpln/trivy-scan tag. Report reads are not authenticated: anyone who has a report URL can open it. Upload requests must carry Authorization: Bearer followed by the token.

Reading Scan Results

List every image that has been scanned:
Print the report link and scan time for one image, then open the link in a browser:
Images with no cpln/trivy-scan tag have not been scanned yet. The daemon picks them up on its next scheduled run.

Operations

Upgrading from 1.1.0

Version 1.2.0 moved the report post token out of Helm values. Through 1.1.0 it was the plain value postToken; it is now an opaque secret you create, named by postToken.secretName. An upgrade that still sets postToken as a string fails at render and leaves the running release untouched:
1

Create the post token secret with your current token

Put the same token your install already uses into a new opaque secret. A different token also works for this release, but anything outside it that used the old token stops working.
2

Replace the removed key in your values

Delete the postToken: string and set postToken.secretName to the secret name. Leave trivyAuth.secretName and serviceAccountName as they are.
3

Upgrade the release

Pass your other existing values (storage, trivyAuth.secretName, serviceAccountName) the same way you did at install. Reports already stored keep their URLs.

Rotating Secrets

Both prerequisite secrets are opaque, so rotate one by applying the whole secret with the new value. Save this as rotate.yaml:
A running workload keeps the old value until it is redeployed, so force a redeployment afterwards.
  • Post token: the daemon and the web server must use the same token, so redeploy both together. If only one picks up the new token, uploads are refused with 401 while both workloads still look healthy.
  • Service account key: add a new key to the service account, put it in the trivyAuth.secretName secret, redeploy daemon, then delete the old key. No reinstall is needed.

Forcing a Rescan

With rescanAfter set, images are rescanned automatically once their last scan is older than that window, and the report is replaced at the same URL. To rescan an image sooner, remove its scan tags so the next run treats it as unscanned:
This command shape is taken from cpln image tag --help and has not been run against a live install.

Troubleshooting

Cause: a secret named by postToken.secretName or trivyAuth.secretName does not exist. status.versions[].message from cpln workload get-deployments web-server --gvc GVC_NAME -o yaml names it, for example The secret my-cpln-trivy-post-token no longer exists.Fix: create the secret as in Prerequisites, then wait for recovery or run cpln workload force-redeployment web-server --gvc GVC_NAME.
Cause: your values still set postToken as a string from 1.1.0 or earlier.Fix: follow Upgrading from 1.1.0.
Cause: rescanAfter is not in the form 7d or 24h. The full error reads rescanAfter must be a number followed by 'd' (days) or 'h' (hours), e.g. '7d' or '24h'.Fix: use a whole number followed by d or h, or "" to scan each image only once.
Cause: the web server refuses the daemon’s uploads. This happens when the two workloads hold different post tokens after a rotation, or when webServer.firewall.inboundAllowCIDR no longer admits the daemon’s traffic.Fix: redeploy both workloads together after a token change, and widen the inbound CIDR list if you narrowed it. Check the daemon’s output:
Cause: an image was deleted while a run was in progress.Fix: none needed. The run continues with the remaining images.

Important Notes

  • Create both prerequisite secrets before installing. A missing one wedges the deployment with no log output.
  • Every image in the organization is scanned and tagged, not only images this install created.
  • Report URLs are readable without authentication. Narrow webServer.firewall.inboundAllowCIDR to keep them private, and keep the daemon’s traffic allowed when you do.
  • Redeploy daemon and web-server together after changing the post token. They must agree or uploads fail with 401.
  • Runs never overlap. A long run on a large registry delays the next scheduled run rather than starting a second one.
  • Install once per GVC. The workloads are always named daemon and web-server.

External References