Clair on AWS User Guide
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, so you can gate images in CI, audit a registry, or answer what is vulnerable in what you are about to ship. The image is delivered as a ready-to-use appliance: postgresql.service and clair.service are enabled and start on boot, so the moment an engineer connects over SSH the container vulnerability scanning API is already answering.
Clair runs 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 is served on port 6060 and the bundled clairctl command line tool drives it. No container runtime or Docker daemon is required on the instance to scan an image, because clairctl pulls the image manifest itself.
This is a headless service. There is 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. The health and Prometheus metrics endpoint is bound to the loopback interface (127.0.0.1:8089). A strong, unique PostgreSQL password is generated automatically on the first boot of every instance and written to a root-only credentials file, so no shared secret is ever baked into the image.
The PostgreSQL data directory is placed 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 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 allowing inbound port 22 from your management network
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
Step 1: 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 cloudimg 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 either 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 initialisation 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.
Step 2: Launch the Instance from the AWS CLI
The following block launches an instance from the cloudimg 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.
Step 3: 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
| OS variant | SSH login user |
|---|---|
| Ubuntu 24.04 | ubuntu |
ssh -i /path/to/<key-name>.pem ubuntu@<public-ip>
Step 4: 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>
The PostgreSQL password is used internally by Clair over the loopback interface. PostgreSQL is not exposed on the network.
Step 5: Confirm the Services Are Running
Confirm 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))

Step 6: 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_state
healthz: 200
readyz: 200
index_state: 200
Step 7: Scan 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. The first scan after launch is best run once the matcher has finished importing its vulnerability data.
clairctl report --host http://127.0.0.1:6060/ mirror.gcr.io/library/debian:11
The 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'
96
A representative sample of the findings for that image, showing the CVE identifier, the affected package and the normalised 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=Unknown

Step 8: Expose the REST API Safely
The Clair REST API is unauthenticated by Clair's own default and is closed to the network by the shipped security group. 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>

Step 9: The Vulnerability Database and the Data Volume
Clair stores its indexer, matcher and notifier state in the local PostgreSQL database clair, whose 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/postgresql
Support
This image is supported 24/7 by cloudimg. 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, contact cloudimg support. 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.