Deployment guide

Clair

Overview

Clair is an Apache-2.0 licensed, open-source static analysis service for containers, maintained by the Quay project. It pulls the layers of an OCI or Docker image, indexes the operating system and language packages inside them, matches those packages against a continuously updated set of vulnerability databases, and reports the known CVEs that affect the image. Clair has no web interface. It is an HTTP API service that registries, CI pipelines and security tooling call to submit images and read back a vulnerability report.

What you get:

  • Clair 4.9.0 (built from the official quay/clair source release) running in combo mode, with the indexer, matcher and notifier in a single process, as a dedicated clair system user
  • A local PostgreSQL back end on the same VM, shared by all three Clair components, so the appliance is entirely self-contained
  • The clairctl command line client for one-line scans and for retrieving reports
  • The REST API on port 6060 and a loopback-only introspection server (health checks and Prometheus metrics) on 127.0.0.1:8089
  • A unique PostgreSQL password generated on each VM's first boot and written to a root-only file, so no credential is baked into the image
  • A REST API that is unauthenticated by default, which is Clair's own default. The appliance is still secure by default, because the Azure network security group opens only SSH (22). Port 6060 is not reachable from the network until you deliberately open it and apply your own access controls.
  • 24/7 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet and subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point. Scale up for larger images and higher scan throughput.

In the network security group (NSG), allow inbound 22/tcp from your management network. Open 6060/tcp only when you intend to expose the scanning API, and only behind your own controls.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, select Create a resource, search the Marketplace for Clair by SecureAnyCloud, and select Create. On Basics, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) only. Then select Review + create and Create.

Step 2 - Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:clair-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name clair \
  --image sac1647283583153:clair-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm Clair and PostgreSQL are running

Clair runs as clair.service in combo mode, backed by the local PostgreSQL service. Check that both are active and confirm the client version:

clairctl --version sudo systemctl is-active clair.service postgresql.service
clairctl version v4.9.0 (claircore v1.5.48) active active

Confirm the listening ports: the REST API on 6060, the introspection (health and metrics) server on loopback 8089, and PostgreSQL on loopback 5432:

ss -tln | grep -E ':6060|:8089|:5432'
LISTEN 0 200 127.0.0.1:5432 0.0.0.0:* LISTEN 0 4096 127.0.0.1:8089 0.0.0.0:* LISTEN 0 4096 *:6060 *:*

Step 5 - Check the health and readiness endpoints

Clair exposes /healthz (liveness) and /readyz (readiness) on the loopback-only introspection server. Both return 200 when Clair is healthy:

curl -s -o /dev/null -w 'healthz: %{http_code}\n' http://127.0.0.1:8089/healthz
curl -s -o /dev/null -w 'readyz: %{http_code}\n' http://127.0.0.1:8089/readyz
healthz: 200 readyz: 200

The introspection server also serves Prometheus metrics at http://127.0.0.1:8089/metrics.

Step 6 - Retrieve your per-VM database password

Each VM generates its own unique PostgreSQL password on first boot for the clair role and writes it to a root-only credentials file:

sudo cat /root/clair-credentials.txt
# Clair 4.9.0 - generated on first boot. Unique to this VM. CLAIR_API_URL=http://<vm-ip>:6060/ CLAIR_HEALTH_URL=http://127.0.0.1:8089/healthz CLAIR_DB_NAME=clair CLAIR_DB_USER=clair CLAIR_DB_PASSWORD=<CLAIR_DB_PASSWORD>

Clair uses the PostgreSQL password internally over loopback, and PostgreSQL is not exposed on the network. In the commands below, <CLAIR_DB_PASSWORD> stands for the value of CLAIR_DB_PASSWORD. Store it in your secrets manager.

Step 7 - Scan a container image with clairctl

clairctl report runs the full round-trip: it fetches the image manifest and layers, submits them to Clair's indexer, then retrieves the vulnerability report from the matcher. No Docker daemon is required, because clairctl pulls the image itself. Scan any public image by reference:

clairctl report --host http://127.0.0.1:6060/ mirror.gcr.io/library/alpine:3.14
alpine:3.14 ok

clairctl prints the image reference followed by the result; ok means the round-trip completed and the report was retrieved. When vulnerabilities are found, they are listed with their CVE identifiers, affected package and severity.

The first scan after boot can take a few minutes while Clair downloads the upstream vulnerability data for the first time. Subsequent scans are fast. Point clairctl at any image in any registry you can reach. Use -o json for machine-readable output to feed into your pipeline.

Step 8 - Query the REST API directly

Registries and CI systems call Clair's REST API directly. The indexer state endpoint confirms the API is serving:

curl -s http://127.0.0.1:6060/indexer/api/v1/index_state
{"state":"cb31df8269833698891b35a63251a81a"}

The per-VM database password authenticates the clair role over loopback. A wrong password is rejected, so the database is never reachable without the per-VM credential:

PGPASSWORD=<CLAIR_DB_PASSWORD> psql -h 127.0.0.1 -U clair -d clair -c "SELECT current_user, current_database();"
current_user | current_database --------------+------------------ clair | clair (1 row)

Step 9 - Expose and secure the scanning API

The REST API binds 0.0.0.0:6060, but the Azure NSG opens only 22 by default, so the API is not reachable from the network until you open 6060. Clair's API is unauthenticated by default, so put it behind your own controls before you expose it. Recommended options:

  • Keep 6060 closed and reach Clair over an SSH tunnel from the machine that scans:
ssh -L 6060:127.0.0.1:6060 azureuser@<vm-public-ip>
# then, locally: clairctl report --host http://127.0.0.1:6060/ <image:tag>
  • Restrict the NSG rule for 6060 to the source IP ranges of your registry or CI runners only.
  • Front Clair with a reverse proxy that terminates TLS and enforces authentication, and enable Clair's own pre-shared-key JWT auth (auth.psk in /etc/clair/config.yaml) for API callers.

Never expose 6060 to the internet without transport encryption and access control.

Maintenance

  • Vulnerability data: Clair's matcher refreshes its vulnerability databases automatically in the background on a schedule, so reports stay current with no action from you.
  • Configuration: the combo config lives at /etc/clair/config.yaml. After changing it, run sudo systemctl restart clair.service.
  • Password: the clair role password is generated per VM on first boot. Rotate it with sudo -u postgres psql -c "ALTER ROLE clair WITH PASSWORD '<new-password>';" and update the connstrings in /etc/clair/config.yaml.
  • Logs: sudo journalctl -u clair.service -f follows the scanner logs.
  • Security patches: unattended-upgrades remains enabled, so the OS continues to receive security updates automatically.
  • Scaling: for high-volume scanning, Clair also supports a distributed deployment (separate indexer, matcher and notifier). This image ships the self-contained combo configuration.

Support

SecureAnyCloud provides 24/7 expert support for this image. Contact sales@secureanycloud.com.

Clair is a trademark of Red Hat, Inc. This image is provided by SecureAnyCloud and is not affiliated with or endorsed by the Quay project or Red Hat. PostgreSQL is a trademark of the PostgreSQL Community Association.

Deploy on Azure

Launch Clair on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure