How to Use Chainguard Security Advisories
Article outlining how one can explore and use the Security Advisories found on the Chainguard Container Directory.
Renovate can be used to alert on updates to Chainguard Containers. This can be an effective way to keep your images up-to-date and free of CVEs. This article explains how to configure Renovate to support Chainguard Containers.
*NOTE: This article describes using Renovate to alert on new versions of Chainguard Containers. It is not about alerts for Wolfi packages (which is unsupported at the time of writing).
This guide assumes you have successfully installed and configured Renovate. If you haven’t already set this up, please refer to the installation instructions.
Additionally, several examples in this guide assume you have chainctl
— Chainguard’s command-line interface — installed on your local machine. Follow our guide on How to Install chainctl
to set this up.
In order to support versioned images from a private repository, you must provide Renovate with credentials to access the Chainguard registry at cgr.dev
. You can do this by creating a token with chainctl
, as in this example:
chainctl auth configure-docker --pull-token
This command responds with output such as:
To use this pull token in another environment, run this command:
docker login "cgr.dev" --username "<USERNAME>" --password "<PASSWORD>"
By default, this credential is good for 30 days.
You can now configure hostRules
in Renovate to support the Chainguard registry. Depending on how Renovate was set up, you can add this to your Renovate configuration with a setting such as:
{
...
"hostRules": [
{
"hostType": "docker",
"matchHost": "cgr.dev",
"username": "<USERNAME>",
"password": "<PASSWORD>"
}]
}
Be aware that you SHOULD NOT check this file into source control with the exposed secret. Instead, you can use environment variables which you pass in at runtime if you use a config.js
file:
module.exports = {
...
"hostRules": [
{
"hostType": "docker",
"matchHost": "cgr.dev",
"username": process.env.CGR_USERNAME,
"password": process.env.CGR_PASSWORD,
}]
};
But an even more secure solution would be to create a script which automatically updates the configuration with the correct values by calling chainctl
. If you do this, you should also set the credential lifetime to a much shorter period with the --ttl
flag:
chainctl auth configure-docker --pull-token --ttl 10m
This sets the pull token’s lifetime to 10 minutes, which limits the risk posed if the token should leak. You can also set the lifetime to a longer period for more manual configurations.
By default, Renovate will now open PRs for any out-of-date versions of images it finds. For example, you can run Renovate by pushing the following Dockerfile to a repository overseen by Renovate:
FROM cgr.dev/chainguard.edu/python:3.11-dev AS builder
...
FROM cgr.dev/chainguard.edu/python:3.11
...
At the time of writing, version 3.12 was the current version of the Python image, so the following PR was opened by Renovate:
Not all images use semantic versioning. Refer to the Renovate documentation for details on how to support different schemes.
Ideally, image references should also be pinned to a digest, as shown in the following section.
:latest
Container Images
Renovate also supports updating image references that are pinned to digests. This allows you to keep floating tags such as :latest
in sync with the most up-to-date version.
As an example, the following Dockerfile prompts Renovate to open two similar pull requests:
FROM cgr.dev/chainguard/go:latest-dev@sha256:ff187ecd4bb5b45b65d680550eed302545e69ec4ed45f276f385e1b4ff0c6231 AS builder
WORKDIR /work
COPY go.mod /work/
COPY cmd /work/cmd
COPY internal /work/internal
RUN CGO_ENABLED=0 go build -o hello ./cmd/server
FROM cgr.dev/chainguard/static:latest@sha256:5e9c88174a28c259c349f308dd661a6ec61ed5f8c72ecfaefb46cceb811b55a1
COPY --from=builder /work/hello /hello
ENTRYPOINT ["/hello"]
The following screenshot shows the PR to update the static image:
The pinDigests
option configures Renovate to add digests to image references that don’t contain them.
The following example Renovate configuration includes this option:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
],
"packageRules": [
{
"matchDatasources": ["docker"],
"pinDigests": true
}
]
}
This configures Renovate to open PRs that will pin a reference like cgr.dev/chainguard/python:3.12
to a digest like the following:
cgr.dev/chainguard/python:3.12@sha256:e3b524a97c37c32ba590aae0ebcebe3a983c1f69a5093b670fdba980f97a09b3
You can also use the matchUpdateTypes
option to disable updates for any types other than digest
.
Here is an example Renovate configuration that does this:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
],
"packageRules": [
{
"matchDatasources": ["docker"],
"matchUpdateTypes": [
"major",
"minor",
"patch"
],
"enabled": false
}
]
}
This configures Renovate to update the digest for a reference but not the tag.
The benefit of this approach is that it allows you to define your update strategy for each image reference by the use of a mutable tag, rather than having separate rules for different images in your Renovate configuration, similar to Chainguard’s Digestabot Github Action.
You can use renovatebot/github-action
to run Renovate from a GitHub Actions workflow. This can be combined with an assumable identity to authenticate to cgr.dev
and update references to Chainguard container images in your repository.
Note: This section assumes you have permissions to create identities in your Chainguard organization.
First, create a Renovate configuration file at the root of your GitHub repository. Refer to the official documentation for all the supported options.
This is an example of a minimal configuration:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}
Push this file to the main
branch of your repository.
Next, create an assumable identity for your GitHub repository:
chainctl iam identities create github <identity-name> \
--github-repo=<github-org>/<github-repo-name> \
--github-ref=refs/heads/main \
--role=registry.pull
Create a workflow file named .github/workflows/renovate.yaml
with the following content. Replace <identity-id>
with the ID returned by the previous command.
name: Renovate
on:
workflow_dispatch:
schedule:
- cron: "0 3 * * *"
permissions:
contents: read
jobs:
renovate:
name: Renovate
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
steps:
- uses: chainguard-dev/setup-chainctl@be0acd273acf04bfdf91f51198327e719f6af978 # v0.4.0
with:
identity: "<identity-id>"
- shell: bash
run: |
RENOVATE_DOCKER_CGR_DEV_PASSWORD=$(chainctl auth token --audience=cgr.dev)
echo "::add-mask::$RENOVATE_DOCKER_CGR_DEV_PASSWORD"
echo "RENOVATE_DOCKER_CGR_DEV_PASSWORD=$RENOVATE_DOCKER_CGR_DEV_PASSWORD" >> $GITHUB_ENV
- name: Run Renovate
uses: renovatebot/github-action@6927a58a017ee9ac468a34a5b0d2a9a9bd45cac3 # v43.0.11
env:
RENOVATE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RENOVATE_REPOSITORIES: ${{ github.repository }}
RENOVATE_DETECT_HOST_RULES_FROM_ENV: "true"
RENOVATE_DOCKER_CGR_DEV_USERNAME: "_token"
This workflow performs the following steps:
RENOVATE_DOCKER_CGR_DEV_PASSWORD
.RENOVATE_DETECT_HOST_RULES_FROM_ENV=true
so that it uses the password exported by the previous step.Push this file to your repository’s main
branch.
This workflow is scheduled to run at 3:00 a.m. every morning. You can trigger it manually by navigating to Actions > Renovate and selecting Run workflow.
Once the workflow has ran successfully, you will find pull requests in your repository for any image references that need to be updated.
Chainguard provide an image for Renovate. This is an example of how you can run this image to keep references to Chainguard images up to date in a GitHub repository.
Note: To follow along with this section, you must have access to Chainguard’s
renovate
container image.
To begin, generate a Personal Access Token for your GitHub user as described in Renovate’s official documentation.
Export the token as an environment variable named RENOVATE_TOKEN
:
export RENOVATE_TOKEN=ghp_XXXXXXXXXXXXXXXXXX
Next, create a Renovate configuration file at the root of any GitHub repositories you want to target with Renovate. Refer to the official documentation for all the supported options.
This is an example of the most minimal configuration:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}
Then, log in with chainctl
:
chainctl auth login
Finally, run Renovate. Substitute <org-name>
with the name of your Chainguard organization and provide any GitHub repositories that you want to target as arguments in the form <github-org>/<github-repo-name>
:
docker run \
-it \
--rm \
-e RENOVATE_TOKEN="${RENOVATE_TOKEN}" \
-e RENOVATE_DETECT_HOST_RULES_FROM_ENV=true \
-e RENOVATE_DOCKER_CGR_DEV_USERNAME=_token \
-e RENOVATE_DOCKER_CGR_DEV_PASSWORD=$(chainctl auth token --audience cgr.dev) \
cgr.dev/<org-name>/renovate \
<github-org>/<github-repo-name>
This example passes a short-lived token for cgr.dev
using the RENOVATE_DOCKER_CGR_DEV_PASSWORD
environment variable.
If Renovate isn’t working as expected, try running it in debug mode and/or dumping the resolved configuration.
For example:
LOG_LEVEL=debug renovate --print-config
...
"hostRules": [
{
"hostType": "docker",
"matchHost": "cgr.dev",
"username": "<Organizations ID>/<pull token ID>",
"password": "***********",
"resolvedHost": "cgr.dev"
},
{"matchHost": null, "hostType": "local"}
]
...
DEBUG: hostRules: basic auth for https://cgr.dev (repository=local)
DEBUG: getLabels(https://cgr.dev, ORGANIZATION/static, latest) (repository=local)
DEBUG: getManifestResponse(https://cgr.dev, ORGANIZATION/static, latest, get) (repository=local)
DEBUG: getManifestResponse(https://cgr.dev, ORGANIZATION/static, sha256:76d71eb53b1b44ec955529ece91c6da222a54fed660ca6b25124935bdd96e133, get) (repository=local)
DEBUG: found labels in manifest (repository=local)
"labels": {
"dev.chainguard.package.main": "static",
"org.opencontainers.image.authors": "Chainguard Team https://www.chainguard.dev/",
"org.opencontainers.image.created": "2024-12-04T19:55:37Z",
"org.opencontainers.image.source": "https://github.com/chainguard-images/images-private/tree/main/images/static",
"org.opencontainers.image.url": "https://images.chainguard.dev/directory/image/static/overview?utm_source=cg-academy&utm_medium=referral&utm_campaign=dev-enablement&utm_content=edu-content-chainguard-chainguard-images-working-with-images-renovate",
"org.opencontainers.image.vendor": "Chainguard"
}
If you have problems getting Renovate to monitor cgr.dev
, please double check the connection details. Make sure the token is still valid (you can verify with chainctl iam identities list
) and it has access to the repository you are referring to. You can test these credentials by running a docker login
and docker pull
in a clean environment.
You may encounter errors such as the following:
DEBUG: getReleaseList error (repository=chainguard-images/images-private, branch=renovate/cgr.dev-chainguard.edu-python-3.x)
"type": "github",
"apiBaseUrl": "https://api.github.com/",
"err": {
"message": "`chainguard-images` forbids access via a personal access token (classic). Please use a GitHub App, OAuth App, or a personal access token with fine-grained permissions.",
"stack": "Error: `chainguard-images` forbids access via a personal access token (classic). Please use a GitHub App, OAuth App, or a personal access token with fine-grained permissions.\n at
…
These can be safely ignored. They are caused by Renovate using the org.opencontainers.image.source
label on our images to look for a changelog. As this source is set to the private images-private
GitHub repository, this request fails.
Last updated: 2025-09-18 11:07