Introduction
In the world of cloud-native applications, container images are the fundamental building blocks. These images, encapsulating everything an application needs to run, are stored and distributed via container registries. While public registries like Docker Hub serve a general purpose, enterprises often require private, secure, and feature-rich registries to manage their internal images, enforce security policies, and maintain compliance. This is where Harbor, a CNCF graduated project, steps in as a robust solution.
Harbor provides a comprehensive set of features, including vulnerability scanning, image signing, replication, and role-based access control (RBAC), making it an ideal choice for organizations running Kubernetes at scale. Integrating Harbor with your Kubernetes clusters allows for a seamless and secure workflow, ensuring that only trusted and scanned images are deployed. This guide will walk you through the process of setting up Harbor and configuring your Kubernetes cluster to leverage its advanced capabilities, enhancing your supply chain security and operational efficiency.
TL;DR: Kubernetes Container Registry with Harbor
Harbor is a private, secure container registry for Kubernetes, offering vulnerability scanning, image signing, and RBAC. This guide covers its deployment via Helm and integration with Kubernetes using ImagePullSecrets. Key steps include:
- Deploying Harbor using its Helm chart.
- Configuring DNS and SSL for Harbor access.
- Creating a Kubernetes Secret for Harbor credentials.
- Updating Kubernetes deployments to use Harbor images and secrets.
- Enabling vulnerability scanning and content trust.
# Install Harbor with Helm (example)
helm repo add harbor https://goharbor.github.io/helm-charts
helm repo update
helm install harbor harbor/harbor \
--namespace harbor \
--create-namespace \
-f values.yaml # Your custom values for hostname, SSL, etc.
# Create a Kubernetes secret for image pulling
kubectl create secret docker-registry harbor-auth \
--docker-server=your.harbor.domain \
--docker-username=your_harbor_user \
--docker-password=your_harbor_password \
--docker-email=your_email@example.com \
--namespace=default
# Update your Deployment to use the secret
# (See Step 4 for YAML example)
Prerequisites
Before we begin, ensure you have the following:
- A running Kubernetes cluster (v1.19+ recommended). You can use Kind, Minikube, or a cloud-managed service like AWS EKS, GKE, or Azure AKS.
kubectlconfigured to communicate with your cluster.helm(v3.0+) installed for deploying Harbor.- A domain name and SSL certificates (or self-signed for testing) for Harbor.
- Basic understanding of Kubernetes concepts like Deployments, Services, and Secrets.
- Administrative access to your Kubernetes cluster.
Step-by-Step Guide
1. Deploy Harbor using Helm
Harbor can be easily deployed onto a Kubernetes cluster using its official Helm chart. This method simplifies the installation and configuration of all Harbor components, including its core services, database, and object storage. We’ll start by adding the Harbor Helm repository and then customizing the installation with a `values.yaml` file to define our desired hostname, persistence, and SSL settings. For production environments, it’s crucial to enable persistence and configure external storage solutions like S3 or Azure Blob Storage.
First, add the Harbor Helm repository:
helm repo add harbor https://goharbor.github.io/helm-charts
helm repo update
Next, create a `values.yaml` file to customize your Harbor deployment. This example assumes you have a domain `your.harbor.domain` and SSL certificates. Replace placeholders with your actual values. For simplicity, this example uses `NodePort` for ingress, but for production, you’d typically use an Ingress controller like NGINX or Traefik, or a LoadBalancer service provided by your cloud provider. For advanced networking configurations, you might explore solutions like Kubernetes Gateway API.
# values.yaml for Harbor deployment
hostname: your.harbor.domain # Replace with your actual domain
externalURL: https://your.harbor.domain
expose:
type: ingress # Use ingress for production, NodePort for testing
tls:
enabled: true
secretName: harbor-tls # Name of the Kubernetes secret containing your TLS certs
# If using NodePort for testing (not recommended for production)
# expose:
# type: nodePort
# nodePort:
# http: 30000
# https: 30001
# tls:
# enabled: true
# certSource: secret
# secret:
# secretName: harbor-tls
# notarySecretName: harbor-notary-tls
# coreSecretName: harbor-core-tls
# portalSecretName: harbor-portal-tls
# registrySecretName: harbor-registry-tls
# Persistence settings (CRITICAL for production)
persistence:
enabled: true
resourcePolicy: "keep" # Keep PVCs on uninstall
# You might want to use a specific storage class or external volume
# imageChartStorage:
# type: filesystem # or s3, azure, etc.
# filesystem:
# rootDirectory: /var/lib/harbor/chart_storage
# imageChartStorage:
# type: s3
# s3:
# bucket: harbor-charts-bucket
# region: us-east-1
# accesskey: YOUR_S3_ACCESS_KEY
# secretkey: YOUR_S3_SECRET_KEY
# Admin password (change for production!)
harborAdminPassword: "MyHarborPassword123!" # CHANGE THIS!
# Vulnerability scanner (Clair is default)
clair:
enabled: true
# Notary for content trust
notary:
enabled: true
# Database (PostgreSQL) settings
# For production, consider an external PostgreSQL instance
database:
type: internal # or external
internal:
# Use persistence for internal DB
persistence:
enabled: true
size: 10Gi
# Redis settings
# For production, consider an external Redis instance
redis:
type: internal # or external
internal:
# Use persistence for internal Redis
persistence:
enabled: true
size: 5Gi
Before deploying, create the TLS secret. If you’re using `cert-manager`, it can automate this. Otherwise, manually create it:
# Replace with your actual certificate and key paths
kubectl create secret tls harbor-tls \
--cert=./fullchain.pem \
--key=./privkey.pem \
--namespace harbor \
--dry-run=client -o yaml | kubectl apply -f -
Now, deploy Harbor:
helm install harbor harbor/harbor \
--namespace harbor \
--create-namespace \
-f values.yaml
Verify the deployment:
kubectl get pods -n harbor
Expected Output (Harbor components should be running):
NAME READY STATUS RESTARTS AGE
harbor-chartmuseum-6b8d76587-xxxxx 1/1 Running 0 5m
harbor-clair-64c86f77c4-xxxxx 1/1 Running 0 5m
harbor-clair-adapter-7c8585f95c-xxxxx 1/1 Running 0 5m
harbor-core-7b4455888d-xxxxx 1/1 Running 0 5m
harbor-database-0 1/1 Running 0 5m
harbor-jobservice-7f65f7c65c-xxxxx 1/1 Running 0 5m
harbor-notary-server-5847959b86-xxxxx 1/1 Running 0 5m
harbor-notary-signer-77b587b469-xxxxx 1/1 Running 0 5m
harbor-portal-5764878b4-xxxxx 1/1 Running 0 5m
harbor-redis-0 1/1 Running 0 5m
harbor-registry-8488d5757d-xxxxx 2/2 Running 0 5m
harbor-trivy-adapter-697996c568-xxxxx 1/1 Running 0 5m
2. Configure DNS and Access Harbor
Once Harbor is deployed, you need to configure DNS to point your chosen `hostname` (e.g., `your.harbor.domain`) to the IP address of your Kubernetes Ingress controller or the NodePort if you’re using it for testing. If you’re running on a cloud provider, your Ingress controller will typically provision an external Load Balancer with a public IP or hostname.
For an Ingress-based setup:
kubectl get ingress -n harbor
Expected Output (look for the ADDRESS column):
NAME CLASS HOSTS ADDRESS PORTS AGE
harbor-ingress your.harbor.domain 192.0.2.123 80, 443 10m
Take the `ADDRESS` (e.g., `192.0.2.123`) and create an A record in your DNS provider for `your.harbor.domain` pointing to this IP. If you’re using a cloud LoadBalancer, it might provide a CNAME.
If you’re using `NodePort` for testing, you’ll need the IP of one of your cluster nodes and the NodePort value (e.g., `30001` for HTTPS).
kubectl get nodes -o wide
Access Harbor by navigating to `https://your.harbor.domain` in your web browser. Log in with the `admin` username and the `harborAdminPassword` you set in `values.yaml`.
3. Push an Image to Harbor
Now that Harbor is running and accessible, let’s push a sample image to it. First, you need to log in to your Harbor registry from your local machine using the `docker` CLI.
docker login your.harbor.domain
You’ll be prompted for your username (admin) and password.
Next, tag a local Docker image and push it to a project in Harbor. Let’s create a project named `my-project` in Harbor’s UI first. Then, we’ll use a simple Nginx image.
docker pull nginx:latest
docker tag nginx:latest your.harbor.domain/my-project/nginx:v1
docker push your.harbor.domain/my-project/nginx:v1
Expected Output (successful push):
The push refers to repository [your.harbor.domain/my-project/nginx]
...
v1: digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx size: 1475
You can now navigate to your Harbor UI, go to `my-project`, and verify that `nginx:v1` is listed. Harbor will automatically scan the image for vulnerabilities if Clair is enabled.
4. Configure Kubernetes to Pull Images from Harbor
For Kubernetes to pull images from your private Harbor registry, it needs credentials. This is achieved using an ImagePullSecret. This secret stores your Harbor username and password in a base64-encoded format, which Kubernetes then uses when attempting to pull images.
Create an ImagePullSecret in your desired namespace (e.g., `default`):
kubectl create secret docker-registry harbor-auth \
--docker-server=your.harbor.domain \
--docker-username=admin \
--docker-password='MyHarborPassword123!' \
--docker-email=admin@your.harbor.domain \
--namespace=default
Verify the secret:
kubectl get secret harbor-auth -o yaml -n default
Expected Output (redacted for brevity):
apiVersion: v1
data:
.dockerconfigjson: eyJhdXRocyI6eyJ5b3VyLmhhcmJvci5kb21haW4iOnsidXNlcm5hbWUiOiJhZG1pbiIsInBhc3N3b3JkIjoiTXlIYXJib3JQYXNzd29yZDEyMyEiLCJlbWFpbCI6ImFkbWluQHlvdXIuaGFyYm9yLmRvbWFpbiJ9fX0=
kind: Secret
metadata:
name: harbor-auth
namespace: default
type: kubernetes.io/dockerconfigjson
Now, create a Kubernetes Deployment that references the image from Harbor and uses the `harbor-auth` ImagePullSecret.
# harbor-nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-from-harbor
labels:
app: nginx-harbor
spec:
replicas: 2
selector:
matchLabels:
app: nginx-harbor
template:
metadata:
labels:
app: nginx-harbor
spec:
containers:
- name: nginx
image: your.harbor.domain/my-project/nginx:v1 # Your image from Harbor
ports:
- containerPort: 80
imagePullSecrets:
- name: harbor-auth # Reference the secret here
Apply the deployment:
kubectl apply -f harbor-nginx-deployment.yaml
Verify the deployment and pod status:
kubectl get deployment nginx-from-harbor
kubectl get pods -l app=nginx-harbor
Expected Output (pods should be running):
NAME READY STATUS RESTARTS AGE
nginx-from-harbor-xxxxxxxxx-xxxxx 1/1 Running 0 2m
nginx-from-harbor-xxxxxxxxx-xxxxx 1/1 Running 0 2m
If the pods are stuck in `ImagePullBackOff`, double-check your ImagePullSecret name, the image path in the deployment, and your Harbor credentials.
5. Automate ImagePullSecrets with Service Accounts
Manually adding `imagePullSecrets` to every deployment can be tedious and error-prone. A better approach is to associate the secret with a Kubernetes Service Account. Any pod using that Service Account will automatically inherit the `imagePullSecrets`. This is particularly useful for namespaces where all applications should pull from your private registry.
First, let’s link the `harbor-auth` secret to the `default` service account in the `default` namespace:
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "harbor-auth"}]}' -n default
Now, create a new deployment *without* explicitly specifying `imagePullSecrets`. It will automatically use the secret from the `default` service account.
# harbor-nginx-deployment-auto.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-from-harbor-auto
labels:
app: nginx-harbor-auto
spec:
replicas: 1
selector:
matchLabels:
app: nginx-harbor-auto
template:
metadata:
labels:
app: nginx-harbor-auto
spec:
containers:
- name: nginx
image: your.harbor.domain/my-project/nginx:v1 # Your image from Harbor
ports:
- containerPort: 80
# No imagePullSecrets section here!
Apply the deployment:
kubectl apply -f harbor-nginx-deployment-auto.yaml
Verify the deployment and pod status:
kubectl get deployment nginx-from-harbor-auto
kubectl get pods -l app=nginx-harbor-auto
Expected Output (pods should be running without explicit secret definition):
NAME READY STATUS RESTARTS AGE
nginx-from-harbor-auto-xxxxxxxxx-xxxxx 1/1 Running 0 1m
This approach simplifies deployment manifests and is highly recommended for managing image pull secrets across multiple applications in a namespace. For more advanced security policies around image pulling, consider integrating with tools like Kyverno to enforce image provenance and signing.
Production Considerations
Deploying Harbor in a production environment requires careful planning and configuration beyond the basic setup. Here are key aspects to consider:
- High Availability (HA): For production, Harbor should be deployed in a highly available configuration. This involves multiple replicas for stateless components, and external, highly available databases (PostgreSQL) and object storage (S3, Azure Blob, GCS) for persistence. The Helm chart supports external database and object storage configurations.
- Persistence: Never use internal database and Redis for production. Configure external, managed services for PostgreSQL and Redis to ensure data durability and scalability. For artifact storage, use cloud object storage like AWS S3 or compatible storage.
- Security:
- TLS/SSL: Always use valid, trusted SSL certificates from a reputable CA. Integrate with `cert-manager` for automated certificate management.
- Network Policies: Restrict network access to Harbor components using Kubernetes Network Policies. Only allow necessary traffic from your CI/CD systems, Kubernetes nodes, and administrators.
- Vulnerability Scanning: Ensure Clair or Trivy (Harbor’s default scanners) are enabled and configured to regularly scan images. Implement policies to block deployments of images with critical vulnerabilities.
- Content Trust (Notary): Enable Notary to sign images, ensuring only trusted and verified images can be pulled. This is a critical step in securing your software supply chain.
- RBAC: Configure fine-grained Role-Based Access Control within Harbor to manage user and group permissions for different projects. Integrate with enterprise identity providers (LDAP/OIDC).
- Image Pull Secrets: Use Service Accounts to manage `imagePullSecrets` as demonstrated, and ensure these secrets are stored securely. Consider using a secrets management solution like HashiCorp Vault or Kubernetes External Secrets.
- Monitoring and Logging: Integrate Harbor’s logs and metrics with your existing observability stack. Harbor exposes Prometheus metrics, which can be scraped by Prometheus and visualized in Grafana. For advanced eBPF-based observability, tools like Hubble can provide deep insights into network traffic within your cluster, including traffic to and from Harbor.
- Backup and Restore: Implement a robust backup strategy for Harbor’s database and configuration.
- Resource Allocation: Allocate sufficient CPU, memory, and storage resources to Harbor components based on your expected load. Monitor resource utilization and scale components as needed.
- Replication: For geographically distributed teams or disaster recovery, configure Harbor’s replication features to synchronize images between multiple Harbor instances.
- CI/CD Integration: Integrate Harbor into your CI/CD pipelines to automatically push newly built images, trigger vulnerability scans, and sign images.
- Cost Optimization: While Harbor itself is open source, the underlying infrastructure (storage, compute, network) can incur costs. Optimize resource allocation and leverage features like image retention policies to manage storage costs. For overall Kubernetes cost optimization, tools like Karpenter can help manage node costs efficiently.
Troubleshooting
Here are some common issues you might encounter when setting up and using Harbor with Kubernetes, along with their solutions.
-
ImagePullBackOff Error
Problem: Pods are stuck in `ImagePullBackOff` status, indicating Kubernetes cannot pull the image from Harbor.
Solution:
- Check ImagePullSecret: Ensure the `imagePullSecrets` name in your Deployment YAML matches the secret you created, and it’s in the correct namespace.
- Verify Secret Contents: Confirm the `harbor-auth` secret contains correct base64-encoded credentials for your Harbor instance. You can decode the `.dockerconfigjson` field:
kubectl get secret harbor-auth -n default -o jsonpath='{.data.\.dockerconfigjson}' | base64 --decodeThen, verify the `auth` token within the decoded JSON.
- Harbor Accessibility: From a node in your cluster, try to `docker login your.harbor.domain` and `docker pull your.harbor.domain/my-project/nginx:v1`. If this fails, Harbor might not be reachable or its certificates are not trusted by the Docker daemon on the nodes.
- Image Path: Double-check the image name in your Deployment YAML (e.g., `your.harbor.domain/my-project/nginx:v1`) is exact.
- DNS Resolution: Ensure your Kubernetes nodes can resolve `your.harbor.domain`. Check `/etc/resolv.conf` on a node or test with `dig your.harbor.domain`.
-
Harbor UI/API Inaccessible (502 Bad Gateway, Connection Refused)
Problem: You cannot access the Harbor web UI or API.
Solution:
- Check Pod Status: Verify all Harbor pods are running in the `harbor` namespace:
kubectl get pods -n harborLook for any pods in `CrashLoopBackOff` or `Error` states.
- Ingress/Service Configuration: If using Ingress, check the Ingress resource and its associated service:
kubectl get ingress -n harbor kubectl get svc -n harborEnsure the Ingress controller (e.g., NGINX Ingress) is correctly configured and its pods are running.
- DNS Configuration: Confirm your DNS A record or CNAME for `your.harbor.domain` points to the correct IP/hostname of your Ingress controller or LoadBalancer.
- Certificates: If using HTTPS, ensure your SSL certificates are valid and correctly mounted in the `harbor-tls` secret. Expired or invalid certificates can cause connection issues.
- Logs: Check the logs of the `harbor-portal` and `harbor-core` pods for errors:
kubectl logs -f-n harbor kubectl logs -f -n harbor
- Check Pod Status: Verify all Harbor pods are running in the `harbor` namespace:
-
Vulnerability Scanning Not Working / Stuck
Problem: Images pushed to Harbor are not being scanned, or scans are perpetually “Pending”.
Solution:
- Check Clair/Trivy Pods: Ensure `harbor-clair`, `harbor-clair-adapter`, or `harbor-trivy-adapter` pods are running and healthy:
kubectl get pods -n harbor | grep -E "clair|trivy" - Logs: Examine the logs of the scanner adapter (e.g., `harbor-trivy-adapter`) and the scanner itself (e.g., `harbor-trivy`) for errors related to database updates or communication issues.
- Resource Constraints: Scanners can be resource-intensive. Ensure the scanner pods have sufficient CPU and memory allocated.
- Database Connectivity: The scanner needs to update its vulnerability database. Check network connectivity and database access.
- Check Clair/Trivy Pods: Ensure `harbor-clair`, `harbor-clair-adapter`, or `harbor-trivy-adapter` pods are running and healthy:
-
Docker Login Certificate Error (`x509: certificate signed by unknown authority`)
Problem: When trying to `docker login your.harbor.domain`, you get a certificate error.
Solution:
- Untrusted CA: This usually means your client machine (or Kubernetes nodes) does not trust the CA that signed your Harbor’s SSL certificate. If you’re using self-signed certificates or a private CA, you need to add the CA certificate to your Docker daemon’s trusted certificates.
- For Linux: Copy your CA certificate to `/etc/docker/certs.d/your.harbor.domain/ca.crt` and restart Docker (`systemctl restart docker`).
- For macOS/Windows (Docker Desktop): Add the CA certificate to your system’s keychain.
- Invalid Certificate Chain: Ensure your `harbor-tls` secret contains the full certificate chain, not just the leaf certificate.
- Untrusted CA: This usually means your client machine (or Kubernetes nodes) does not trust the CA that signed your Harbor’s SSL certificate. If you’re using self-signed certificates or a private CA, you need to add the CA certificate to your Docker daemon’s trusted certificates.
-
Harbor Storage Issues (Disk Full, Image Push Fails)
Problem: Images fail to push, or Harbor reports storage errors.
Solution:
- Check PVCs: If using internal persistence, check the status and capacity of the PersistentVolumeClaims (PVCs) used by Harbor components (database, registry, chartmuseum):
kubectl get pvc -n harbor kubectl describe pvc-n harbor If a PVC is full, you may need to expand it (if your storage class supports it) or configure image retention policies in Harbor to clean up old images.
- External Storage: If using external object storage (S3, Azure Blob), verify the credentials and bucket configuration in your `values.yaml` are correct and that the bucket has sufficient capacity and permissions.
- Garbage Collection: Run Harbor’s garbage collection to remove unused image layers. This needs to be configured and run periodically.
- Check PVCs: If using internal persistence, check the status and capacity of the PersistentVolumeClaims (PVCs) used by Harbor components (database, registry, chartmuseum):
-
Notary Signing Fails
Problem: Images are not being signed, or content trust verification fails.
Solution:
- Notary Pods: Ensure `harbor-notary-server` and `harbor-notary-signer` pods are running and healthy.
- Notary Configuration: Verify Notary is enabled in your `values.yaml` and correctly configured.
- Key Management: Ensure the Notary keys are correctly generated and stored.
- Client-Side Trust: For content trust to work, clients (like `docker pull –disable-content-trust=false`) need to trust the Notary root keys.
FAQ Section
-
What is the difference between Harbor and Docker Hub?
Harbor is a private, open-source container registry designed for enterprise use, offering advanced features like vulnerability scanning, image signing, replication, and RBAC. Docker Hub is a public registry (with private repository options) primarily used for sharing and discovering public images, though it also offers private image storage. Harbor gives you full control over your images and infrastructure, often deployed within your own data center or cloud environment, whereas Docker Hub is a managed service.
-
Why should I use Harbor instead of a cloud provider’s registry (e.g., ECR, GCR)?
While cloud provider registries are excellent and deeply integrated with their respective ecosystems, Harbor offers a vendor-agnostic solution. This is beneficial for multi-cloud strategies, hybrid cloud deployments, or when you need specific features (like advanced replication or specific compliance requirements) that might not be available or are cost-prohibitive in a managed service. Harbor also gives you more control over the underlying infrastructure and data locality.
-
Is Harbor secure? How does it help with supply chain security?
Yes, Harbor is designed with security in mind. It enhances supply chain security through:
- Vulnerability Scanning: Integrates with tools like Clair and Trivy to scan images for known vulnerabilities.
- Content Trust (Notary): Allows images to be cryptographically signed, ensuring their integrity and authenticity.
- Image Immutability: Prevents alteration of images once pushed.
- RBAC: Fine-grained access control to projects and repositories.
- Replication: Securely replicate images to other Harbor instances.
For even deeper supply chain security, consider integrating Harbor with tools like Sigstore and Kyverno for policy enforcement and image provenance.
-
Can Harbor integrate with my CI/CD pipeline?
Absolutely. Harbor is designed to be a central part of your CI/CD workflow. You can configure your CI/CD tools (e.g., Jenkins, GitLab CI, GitHub Actions, Argo CD) to:
- Build Docker images.
- Tag images with your Harbor registry address.
- Push images to specific Harbor projects.
- Trigger vulnerability scans and enforce policies based on scan results.
- Pull signed images for deployment to Kubernetes.
-
How do I handle self-signed certificates with Harbor on Kubernetes?
If you’re using self-signed certificates for Harbor, your Kubernetes nodes and any client machines (where you run `docker login`) need to trust these certificates.
- For Kubernetes Nodes: You’ll need to configure the Docker daemon on each node to trust your CA certificate. This typically involves placing the `ca.crt` file in `/etc/docker/certs.d/your.harbor.domain/` and restarting the Docker daemon.
- For `imagePullSecrets`: Kubernetes itself doesn’t directly care about the CA for `imagePullSecrets` as long as the nodes’ Docker daemons trust it.
- For `docker login` on your workstation: Add the CA certificate to your operating system’s trust store.
For production, it’s highly recommended to use certificates from a trusted Certificate Authority or integrate with `cert-manager` for automated certificate provisioning and renewal.
Cleanup Commands
To remove the Harbor deployment and all associated resources from your Kubernetes cluster, use the following commands. Be cautious, as this will delete all Harbor data.
# Uninstall Harbor Helm release
helm uninstall harbor --namespace harbor
# Delete the Harbor namespace
kubectl delete namespace harbor
# Delete the ImagePullSecret if you created it manually in other namespaces
kubectl delete secret harbor-auth -n default # Adjust namespace if needed
# Delete the sample deployments
kubectl delete deployment nginx-from-harbor
kubectl delete deployment nginx-from-harbor-auto
# Remove the service account patch
kubectl patch serviceaccount default -p '{"imagePullSecrets": []}' -n default
Next Steps / Further Reading
You’ve successfully deployed Harbor and integrated it with your Kubernetes cluster. Here are some next steps to deepen your knowledge and enhance your setup:
- Explore Harbor Features: Dive into Harbor’s UI to explore features like project management, user management, replication, webhooks, and retention policies.
- Content Trust: Implement content trust using Notary to sign your images. This is a critical step for securing your software supply chain.
- Vulnerability Policy Enforcement
