Harbor Image Registry Security Hardening: Image Scanning and Access Control
Complete Harbor hardening for teams managing container images: HTTPS, least-privilege RBAC, Trivy scanning, image signing, and Robot-account pulls. Prevents image supply-chain poisoning and unauthorized access.
Scope
This guide is for enterprise teams using Harbor to manage Docker and Kubernetes images. A registry exposed to the internet, shared admin accounts, no vuln scan after push, or K8s pulling with personal accounts all create image supply-chain poisoning, unauthorized access, and malicious-image ingest risk. Hardening below applies to Harbor 2.x and later.
Prerequisites
- Harbor 2.x deployed (docker-compose or Helm), admin access
- Can edit `harbor.yml` and re-run the install script
- Kubernetes cluster can reach the registry; permission to create Secrets
How It Works
Harbor security is four layers: transport (HTTPS against traffic sniffing), auth (RBAC roles and least-privilege Robot accounts), detection (built-in Trivy scanning and CVE allowlist), integrity (cosign/Notation signature verification). Typical supply-chain path: attacker cracks a weak-password registry → uploads a backdoored image → cluster pulls and runs it. Forced scanning blocks malicious ingest, signature verification stops tampering, Robot accounts isolate pull credentials. Together they systematically shrink the risk.
Procedure
Step 1: Enable HTTPS
Edit `harbor.yml`. Configure certificate and private key:
hostname: harbor.example.com
https:
port: 443
certificate: /data/cert/harbor.crt
private_key: /data/cert/harbor.key
http:
port: 80
# Disable HTTP when used only on the intranet
# enabled: false
Run `./install.sh` to apply. Production certs should use Lets Encrypt or an enterprise CA to avoid client trust issues.
Step 2: Enable Trivy Scanning and Block Policy
In Harbor UI: Project → Configuration → Security. Check:
- Automatically scan images on push: scan immediately after push
- Prevent images with vulnerabilities: block untrusted images by severity threshold
- Set CVE allowlist: allow only historical CVEs confirmed as no-risk
Step 3: Configure Robot Accounts for K8s Pulls
Do not use personal accounts in the cluster. Create a Robot account per namespace. Grant pull only on the matching project:
# In Harbor UI: Project → Robot Accounts → New Robot Account
# Check only push / pull permissions; copy the generated token after saving
# Create the pull-credential Secret on the cluster
kubectl create secret docker-registry harbor-pull \
--docker-server=harbor.example.com \
--docker-username='robot$prod' \
--docker-password='' \
--namespace=prod
# Reference it in the Deployment
kubectl patch deployment app -n prod -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"harbor-pull"}]}}}}'
Step 4: Enable Image Signature Verification
Sign images with cosign. Enable signature verification in the Harbor project config:
# Generate a key pair and sign
cosign generate-key-pair
cosign sign --key cosign.key harbor.example.com/prod/app:1.0.0
# Project → Configuration → Security → Enable 'Verify image signatures with cosign/Notation'
# Unsigned images cannot be pulled and deployed
Step 5: Configure Retention Policy and Audit
Purge unused images. Keep audit logs:
# Project → Configuration → Retention Policy
# Example rule: retain images from the last 30 days and the most recent 10 tags; clean up the rest
# Audit: check unauthorized access attempts
grep -i "401\|unauthorized" /var/log/harbor/core/*.log | tail -50
Verification
# 1. Verify HTTPS access
curl -k -u admin: https://harbor.example.com/api/v2.0/projects
# 2. Verify scan blocking: pushing an image with high-risk vulnerabilities should be rejected or flagged
docker push harbor.example.com/prod/bad-image:1.0
# 3. Verify Robot account: pull-only permission, push should return 403
docker login harbor.example.com -u 'robot$prod' -p ''
docker push harbor.example.com/prod/app:test # expected 403
FAQ
Q1: Scan found a high/critical vulnerability but the business must ship. What then?
Temporarily allow it in the project CVE allowlist. Record approver, reason, and time. Fix and re-push after the business window. Allowlisting must leave an audit trail. Close the loop with a ticket system.
Q2: Robot accounts vs personal accounts?
Robot accounts can only access a specified project, permissions down to push/pull, cannot log into the Web UI, tokens can be rotated anytime, small blast radius. Personal accounts have broad privileges and are bound to people. They must not appear in cluster Secrets.
Q3: Air-gapped intranet cannot update the Trivy vuln DB?
Pre-download the offline vuln-DB pack on a connected host. Update via `trivy image --offline-scan` or Harbor's vuln-DB import. Or configure an internal proxy to the official vuln-DB mirror.
Summary
Harbor hardening core: HTTPS transport + least-privilege RBAC + mandatory vuln scanning + image signing. Put the image registry in the supply-chain security program. Run scan and sign in CI/CD at build time so malicious images never reach production. That builds a complete container-image trust chain.