Quick Start (5 min): Bootstrapping a Hardened Harbor Instance
Untracked base images slip into private registries constantly. Pushing raw builds directly to an unmonitored registry turns your cluster into an easy target for known exploits.
Harbor stops this workflow. It wraps standard OCI registry storage with granular access controls, automated Trivy security scans, and native image signing. You can spin up a functional local instance in under five minutes with Docker Compose.
# Download Harbor offline installer
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
tar xzvf harbor-offline-installer-v2.10.0.tgz
cd harbor
# Configure parameters
cp harbor.yml.tmpl harbor.yml
Open harbor.yml and adjust your hostname and initial credentials:
hostname: registry.internal.lan
http:
port: 80
# For production TLS, uncomment the https block and supply your cert paths
harbor_admin_password: "ChangeMe_Complex_Secret!"
Whenever I configure admin passwords or database credentials on new servers, I avoid weak defaults and bash history leaks. A client-side generator like toolcraft.app/en/tools/security/password-generator generates high-entropy strings directly in the browser. No secrets ever leave your workstation. Save your generated secret in your password manager, then run the installer with the Trivy scanner enabled:
sudo ./install.sh --with-trivy
Verify that your containers are running:
docker compose ps
Log in to your registry from the command line:
docker login registry.internal.lan -u admin
Deep Dive: Registry Vulnerabilities and Root Causes
The Problem: Blind Trust in Upstream Base Images
Most registry security issues start with misplaced trust. A developer pulls python:3.11-slim or node:20-alpine, layers on company code, and pushes the build. Three weeks later, an upstream glibc or OpenSSL flaw surfaces, such as CVE-2023-4863 in libwebp. Your cluster is now running compromised binaries, and nobody noticed.
Root Cause: Static Scans and Mutable Artifacts
Two major blind spots allow vulnerable images to reach production:
- Point-in-time pipeline scans: Scanning an image only inside a CI run creates a false sense of safety. If an image sits in storage for 20 days before deployment, it misses every CVE disclosed after build time.
- Mutable tags and unverified provenance: Floating tags like
:latestor:v1.2can be overwritten by anyone with push access. Without signature checks, an attacker or a broken pipeline script can overwrite trusted images with compromised layers.
Solution: Harbor’s Three-Layer Defense
Harbor enforces an automated zero-trust gate through three linked mechanisms:
- Continuous Background Scanning: Trivy scans new pushes immediately. It also rescans resting images on a recurring nightly cron schedule.
- Cryptographic Attestation with Cosign: Sigstore Cosign confirms that images came from authorized CI runners and remained unmodified.
- Pre-Pull Admission Controls: Harbor rejects image pull requests whenever vulnerabilities exceed defined severity limits.
Advanced Usage: Automated Scanning, Cosign Signing, and Pull Blocking
1. Enabling Scan-on-Push and Scheduled Scans
Manual scans depend on human memory. Enforce automatic vulnerability checks at the project level instead:
- Log in to the Harbor console.
- Go to Projects → Select your project (e.g.,
backend-services) → Configuration. - Check Automatically scan images on push.
- Under Vulnerability, check Prevent vulnerable images from running and choose High or Critical as your threshold.
To catch newly disclosed CVEs on existing images, go to Administration → Interrogation Services → Vulnerability. Set the schedule to rescan every night at 2:00 AM UTC:
0 0 2 * * *
2. Signing Images with Cosign
Tags can be overwritten; cryptographic signatures cannot. Cosign signs OCI artifacts directly in Harbor without needing a separate Notary server.
# Install Cosign
curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64"
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
sudo chmod +x /usr/local/bin/cosign
# Generate a keypair for your CI pipeline runner
cosign generate-key-pair
Store cosign.key in your CI secret vault (such as HashiCorp Vault or GitHub Secrets). After pushing your image, sign its digest immediately:
# Build and push
docker build -t registry.internal.lan/backend-services/api:1.0.4 .
docker push registry.internal.lan/backend-services/api:1.0.4
# Sign the image
COSIGN_PASSWORD="your-private-key-password" cosign sign \
--key cosign.key \
registry.internal.lan/backend-services/api:1.0.4
Cosign pushes the signature artifact directly to Harbor. Harbor detects it and displays a green verified badge next to the image digest.
3. Enforcing Content Trust in Harbor
Under your Harbor project settings, open Configuration and check Only allow signed images to be pulled. Any attempt to download an unsigned image fails at the registry boundary:
$ docker pull registry.internal.lan/backend-services/api:unsigned-test
Error response from daemon: unknown: The image is not signed by Cosign or Notary, and cannot be pulled.
4. Enforcing Signatures in Kubernetes via Kyverno
Registry-level blocks protect your endpoints, but admission controllers enforce compliance inside your cluster. You can pair Harbor with Kyverno to reject unsigned pods before they schedule:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
validationFailureAction: Enforce
rules:
- name: verify-cosign
match:
resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "registry.internal.lan/backend-services/*"
key: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7p+YV6bEx...
-----END PUBLIC KEY-----
Field-Tested Tips for Running Harbor in Production
- Lock Down SemVer Tags: Turn on Tag Immutability Rules in your project settings. Apply a regex pattern like
v[0-9]+\.[0-9]+\.[0-9]+to prevent pipeline scripts or human error from overwriting established releases. - Prune Orphaned Blobs Weekly: CI runners generate dozens of untagged layers per sprint. A team of 30 developers can easily create 250 GB of orphaned image layers each month. Schedule garbage collection under Administration → Clean Up, and test with a Dry Run first.
- Isolate Robot Accounts: Never share administrator credentials with CI/CD systems. Generate dedicated Robot Accounts with scoped roles—give
Push/Pullrights to your CI builders, and grant read-onlyPullrights to Kubernetes cluster pull secrets. - Use Scoped CVE Allowlisting: Zero-day advisories like CVE-2023-38545 in curl occasionally lack instant upstream vendor patches. Don’t turn off your deployment prevention gate. Add the specific CVE ID to your project-level CVE Allowlist with a 14-day expiration window to keep releases moving while you wait for patches.
