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/
clairsource 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
clairctlcommand line client for one-line scans and for retrieving reports - The REST API on port
6060and a loopback-only introspection server (health checks and Prometheus metrics) on127.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). Port6060is 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 StandardStep 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.serviceclairctl version v4.9.0 (claircore v1.5.48) active activeConfirm 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/readyzhealthz: 200 readyz: 200The 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.14alpine:3.14 okclairctl 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
6060closed 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
6060to 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.pskin/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, runsudo systemctl restart clair.service. - Password: the
clairrole password is generated per VM on first boot. Rotate it withsudo -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 -ffollows 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
Overview
This image runs Clair, the open-source project for the static analysis of vulnerabilities in application containers. Clair indexes the package contents of a container image's layers and reports the known CVEs that affect them. You can use it to gate images in CI, audit a registry, or find out what is vulnerable in what you are about to ship.
What you get:
- A ready-to-use appliance:
postgresql.serviceandclair.serviceare enabled and start on boot, so the container vulnerability scanning API is already answering when you connect over SSH - Clair in combo mode, which runs the indexer, matcher and notifier in a single process backed by a locally installed PostgreSQL database on the same instance
- The REST API on port 6060, driven by the bundled
clairctlcommand line tool. No container runtime or Docker daemon is required on the instance to scan an image, becauseclairctlpulls the image manifest itself. - A headless service with no web interface. The Clair REST API is unauthenticated by Clair's own default, and the shipped security group opens port 22 only, so the API is never exposed to the network until you deliberately open port 6060 behind your own access controls.
- A health and Prometheus metrics endpoint bound to the loopback interface (
127.0.0.1:8089) - A strong, unique PostgreSQL password generated automatically on the first boot of every instance and written to a root-only credentials file, so no shared secret is baked into the image
- A PostgreSQL data directory on a dedicated, independently resizable EBS data volume mounted at
/var/lib/postgresql, so the vulnerability database and indexed image data grow on durable storage that you can expand without touching the boot volume
Prerequisites
Before you deploy this image, you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group that allows inbound port 22 from your management network
- The AWS CLI (version 2) installed locally, if you plan to deploy from the command line
Launch the instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for Clair. Select the SecureAnyCloud listing and choose Select, then Continue on the subscription summary.
Pick an instance type of m5.large or larger. Clair's matcher downloads and imports a large body of vulnerability data on first start, so allow at least 8 GB of memory. Choose your EC2 key pair under Key pair (login). Under Network settings, select your VPC and subnet, and create or select a security group that opens port 22 from your management network. Leave the root volume at the default size or larger.
Select Launch instance. First-boot initialization takes a short time after the instance state becomes Running and the status checks pass. The image generates the per-instance database password, rotates the PostgreSQL role and starts Clair against it.
Launch the instance from the AWS CLI
The following block launches an instance from the SecureAnyCloud Clair Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens port 22 from your management network.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--metadata-options "HttpTokens=required" \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=clair}]'When the instance state is Running and both status checks pass, note its public or private IP address for the SSH step.
Connect over SSH
Connect to the instance with your key pair. The login user depends on the operating system variant you launched.
Connecting to your instance
For the Ubuntu 24.04 variant, the SSH login user is ubuntu.
ssh -i /path/to/<key-name>.pem ubuntu@<public-ip>Read the per-instance credentials
On first boot, the image generates a unique PostgreSQL password for the clair role and records it, together with the API address, in a root-only credentials file. Read it with sudo:
sudo cat /root/clair-credentials.txt# Clair 4.9.0 - generated on first boot. Unique to this instance.
# Keep this file safe. The Clair REST API is UNAUTHENTICATED by default;
# port 6060 is NOT opened on the instance security group by default - open it
# only behind your own network controls. CLAIR_API_URL=http://<instance-public-ip>:6060/ CLAIR_HEALTH_URL=http://127.0.0.1:8089/healthz CLAIR_DB_NAME=clair CLAIR_DB_USER=clair CLAIR_DB_PASSWORD=<generated-per-instance>Clair uses the PostgreSQL password internally over the loopback interface. PostgreSQL is not exposed on the network.
Confirm the services are running
Confirm that both services are active and that Clair is listening. The REST API binds 0.0.0.0:6060 and the health and metrics endpoint binds loopback 127.0.0.1:8089. PostgreSQL listens on loopback only.
systemctl is-active clair postgresql
sudo ss -tlnp | grep -E '6060|8089|5432'active active LISTEN 0 4096 127.0.0.1:8089 0.0.0.0:* users:(("clair",pid=1213,fd=3)) LISTEN 0 200 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=740,fd=6)) LISTEN 0 4096 *:6060 *:* users:(("clair",pid=1213,fd=13))Check health and readiness
The introspection server on loopback port 8089 serves liveness and readiness endpoints. Both return HTTP 200 when Clair is healthy and its database migrations have completed.
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
curl -s -o /dev/null -w 'index_state: %{http_code}\n' http://127.0.0.1:6060/indexer/api/v1/index_statehealthz: 200 readyz: 200 index_state: 200Scan a container image
Use the bundled clairctl to scan an image. Point it at the local REST API with --host. clairctl pulls the image manifest, submits it to the indexer, waits for the vulnerability report from the matcher and prints the result. No Docker daemon is needed. Run the first scan after launch once the matcher has finished importing its vulnerability data.
clairctl report --host http://127.0.0.1:6060/ mirror.gcr.io/library/debian:11The matcher matches every installed package against its continuously updated vulnerability data and returns the CVEs affecting the image. For JSON output suitable for CI, add --out json:
clairctl report --host http://127.0.0.1:6060/ --out json mirror.gcr.io/library/debian:11 \
| jq '[.vulnerabilities | to_entries[]] | length'96A representative sample of the findings for that image, showing the CVE identifier, the affected package and the normalized severity:
CVE-2016-2781 pkg=coreutils severity=Medium CVE-2025-27587 pkg=openssl severity=Low CVE-2024-26458 pkg=krb5 severity=Low CVE-2011-3374 pkg=apt severity=Low CVE-2023-50495 pkg=ncurses severity=UnknownExpose the REST API safely
The Clair REST API is unauthenticated by Clair's own default, and the shipped security group closes it to the network. To let registries, CI runners or clairctl on other hosts reach it, open port 6060 in the instance security group to your trusted CIDR only, and front it with your own access controls and TLS.
Clair itself supports PSK/JWT authentication on the API. Consult the upstream documentation to enable it. Never expose port 6060 to the public internet without authentication in front of it.
# Example: allow port 6060 from your CI subnet only aws ec2 authorize-security-group-ingress \
--group-id <security-group-id> \
--protocol tcp --port 6060 --cidr <your-mgmt-cidr>The vulnerability database and the data volume
Clair stores its indexer, matcher and notifier state in the local PostgreSQL database clair. Its data directory lives on the dedicated EBS data volume mounted at /var/lib/postgresql. The matcher's updaters refresh vulnerability data from distribution security trackers and public feeds in the background. The first full import runs after the initial boot, and subsequent refreshes are incremental.
You can grow the data volume with the standard EBS resize workflow without touching the boot volume.
findmnt /var/lib/postgresql df -h /var/lib/postgresqlSupport
SecureAnyCloud supports this image 24/7. Contact SecureAnyCloud support for help with the REST API and clairctl, indexing and matching, the vulnerability updaters, the PostgreSQL backend, integrating Clair with registries and CI, backups, capacity planning and upgrade planning. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
Deploy on AWS
Launch Clair on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com