Aller au contenu

Installation et configuration de Harbor

Pre-requis

Composant Version minimale Notes
Kubernetes 1.28+ Pour déploiement Helm
Helm 3.12+ Chart Harbor officiel
Podman (ou Docker) 4.0+ Pour déploiement standalone
PostgreSQL 15+ Instance externe, TLS active
MinIO / S3 RELEASE.2024+ Stockage des blobs
Certificat TLS x509, SAN Wildcard ou spécifique a Harbor

Option A : Déploiement Helm (Kubernetes)

Preparer l'infrastructure

PostgreSQL externe

# Creer la base de donnees Harbor
psql -h postgres.example.com -U admin -c "
  CREATE USER harbor WITH PASSWORD 'CHANGEME';
  CREATE DATABASE harbor OWNER harbor;
  CREATE DATABASE harbor_notary_server OWNER harbor;
  CREATE DATABASE harbor_notary_signer OWNER harbor;
  GRANT ALL PRIVILEGES ON DATABASE harbor TO harbor;
"

Bucket S3 (MinIO)

# Creer le bucket pour Harbor
mc alias set minio https://minio.example.com admin CHANGEME
mc mb minio/harbor-registry
mc policy set private minio/harbor-registry

Secret TLS

# Creer le secret TLS dans le namespace harbor
kubectl create namespace harbor

kubectl create secret tls harbor-tls \
  --cert=harbor.example.com.crt \
  --key=harbor.example.com.key \
  -n harbor

Installer le chart Helm

# Ajouter le repository Harbor
helm repo add harbor https://helm.goharbor.io
helm repo update

Créer le fichier de valeurs :

# harbor-values.yaml
expose:
  type: ingress
  tls:
    enabled: true
    certSource: secret
    secret:
      secretName: harbor-tls
  ingress:
    hosts:
      core: harbor.example.com
    className: traefik
    annotations:
      traefik.ingress.kubernetes.io/router.entrypoints: websecure

externalURL: https://harbor.example.com

persistence:
  enabled: true
  resourcePolicy: "keep"
  imageChartStorage:
    type: s3
    s3:
      region: us-east-1
      bucket: harbor-registry
      accesskey: MINIO_ACCESS_KEY
      secretkey: MINIO_SECRET_KEY
      regionendpoint: https://minio.example.com
      secure: true

database:
  type: external
  external:
    host: postgres.example.com
    port: "5432"
    username: harbor
    password: CHANGEME
    coreDatabase: harbor
    sslmode: require

redis:
  type: external
  external:
    addr: redis.example.com:6379
    password: CHANGEME

# Composants Harbor
core:
  replicas: 2
  resources:
    requests:
      cpu: 500m
      memory: 512Mi
    limits:
      cpu: 2000m
      memory: 2Gi

registry:
  replicas: 2
  resources:
    requests:
      cpu: 500m
      memory: 512Mi
    limits:
      cpu: 2000m
      memory: 2Gi

jobservice:
  replicas: 1
  resources:
    requests:
      cpu: 250m
      memory: 256Mi
    limits:
      cpu: 1000m
      memory: 1Gi

trivy:
  enabled: true
  replicas: 2
  resources:
    requests:
      cpu: 500m
      memory: 512Mi
    limits:
      cpu: 2000m
      memory: 2Gi

# Metriques Prometheus
metrics:
  enabled: true
  serviceMonitor:
    enabled: true

# Garbage collection planifie
gc:
  enabled: true
  schedule: "0 2 * * 0"  # Dimanche 2h du matin
  deleteUntagged: true
# Deployer Harbor
helm install harbor harbor/harbor \
  -f harbor-values.yaml \
  -n harbor \
  --wait --timeout 10m

# Verifier le deploiement
kubectl get pods -n harbor

Sortie attendue :

NAME                                  READY   STATUS    RESTARTS   AGE
harbor-core-6f8b9c7d4-abc12          1/1     Running   0          2m
harbor-core-6f8b9c7d4-def34          1/1     Running   0          2m
harbor-jobservice-5d4c3b2a1-ghi56    1/1     Running   0          2m
harbor-registry-7e6d5c4b3-jkl78      1/1     Running   0          2m
harbor-registry-7e6d5c4b3-mno90      1/1     Running   0          2m
harbor-trivy-8f7e6d5c4-pqr12         1/1     Running   0          2m
harbor-trivy-8f7e6d5c4-stu34         1/1     Running   0          2m

Option B : Déploiement Podman (standalone)

Pour les environnements sans Kubernetes, Harbor fournit un installeur offline.

Telecharger l'installeur

# Telecharger la derniere version
HARBOR_VERSION=2.11.0
curl -LO "https://github.com/goharbor/harbor/releases/download/v${HARBOR_VERSION}/harbor-offline-installer-v${HARBOR_VERSION}.tgz"

# Extraire
tar xzf "harbor-offline-installer-v${HARBOR_VERSION}.tgz"
cd harbor

Configurer harbor.yml

# harbor.yml
hostname: harbor.example.com

http:
  port: 80

https:
  port: 443
  certificate: /etc/harbor/certs/harbor.example.com.crt
  private_key: /etc/harbor/certs/harbor.example.com.key

harbor_admin_password: CHANGEME

database:
  host: postgres.example.com
  port: 5432
  db_name: harbor
  username: harbor
  password: CHANGEME
  max_idle_conns: 50
  max_open_conns: 1000
  ssl_mode: require

data_volume: /data/harbor

storage_service:
  s3:
    accesskey: MINIO_ACCESS_KEY
    secretkey: MINIO_SECRET_KEY
    region: us-east-1
    regionendpoint: https://minio.example.com
    bucket: harbor-registry
    secure: true

trivy:
  ignore_unfixed: false
  security_check: vuln
  insecure: false

jobservice:
  max_job_workers: 10

log:
  level: info
  local:
    rotate_count: 50
    rotate_size: 200M
    location: /var/log/harbor

metric:
  enabled: true
  port: 9090
  path: /metrics

Installer et démarrer

# Preparer la configuration
./prepare

# Installer (avec Trivy)
./install.sh --with-trivy

# Verifier les conteneurs
podman ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

Configuration post-installation

Changer le mot de passe admin

# Se connecter a l'interface web
# https://harbor.example.com
# Login : admin / Harbor12345 (defaut)

# Ou via API
curl -X PUT https://harbor.example.com/api/v2.0/users/1/password \
  -H "Content-Type: application/json" \
  -u admin:Harbor12345 \
  -d '{
    "old_password": "Harbor12345",
    "new_password": "NEW_SECURE_PASSWORD"
  }'

Changer le mot de passe admin immédiatement

Le mot de passe par defaut est connu de tous. Le changer des la première connexion et stocker le nouveau mot de passe dans Vault.

Configurer l'authentification OIDC

# Configurer Keycloak comme provider OIDC
curl -X PUT https://harbor.example.com/api/v2.0/configurations \
  -H "Content-Type: application/json" \
  -u admin:NEW_SECURE_PASSWORD \
  -d '{
    "auth_mode": "oidc_auth",
    "oidc_name": "Keycloak",
    "oidc_endpoint": "https://keycloak.example.com/realms/organization",
    "oidc_client_id": "harbor",
    "oidc_client_secret": "CLIENT_SECRET",
    "oidc_scope": "openid,profile,email,groups",
    "oidc_groups_claim": "groups",
    "oidc_admin_group": "harbor-admins",
    "oidc_verify_cert": true,
    "oidc_auto_onboard": true
  }'

Créer les projets

# Projet pour les images de base
curl -X POST https://harbor.example.com/api/v2.0/projects \
  -H "Content-Type: application/json" \
  -u admin:NEW_SECURE_PASSWORD \
  -d '{
    "project_name": "library",
    "public": true,
    "metadata": {
      "auto_scan": "true",
      "severity": "critical",
      "enable_content_trust": "true",
      "prevent_vul": "true"
    },
    "storage_limit": 53687091200
  }'

# Projet applicatif prive
curl -X POST https://harbor.example.com/api/v2.0/projects \
  -H "Content-Type: application/json" \
  -u admin:NEW_SECURE_PASSWORD \
  -d '{
    "project_name": "app-backend",
    "public": false,
    "metadata": {
      "auto_scan": "true",
      "severity": "high",
      "enable_content_trust": "true",
      "prevent_vul": "true"
    },
    "storage_limit": 21474836480
  }'

Configurer le scanner

# Verifier que Trivy est enregistre
curl -s https://harbor.example.com/api/v2.0/scanners \
  -u admin:NEW_SECURE_PASSWORD | jq '.[].name'
# → "Trivy"

# Definir Trivy comme scanner par defaut
SCANNER_UUID=$(curl -s https://harbor.example.com/api/v2.0/scanners \
  -u admin:NEW_SECURE_PASSWORD | jq -r '.[0].uuid')

curl -X PATCH "https://harbor.example.com/api/v2.0/scanners/${SCANNER_UUID}" \
  -H "Content-Type: application/json" \
  -u admin:NEW_SECURE_PASSWORD \
  -d '{"is_default": true}'

Activer le tag immutability

# Regle : les tags matchant v*.*.* sont immutables
curl -X POST https://harbor.example.com/api/v2.0/projects/app-backend/immutabletagrules \
  -H "Content-Type: application/json" \
  -u admin:NEW_SECURE_PASSWORD \
  -d '{
    "tag_selectors": [
      {
        "kind": "doublestar",
        "decoration": "matches",
        "pattern": "v*.*.*"
      }
    ],
    "scope_selectors": {
      "repository": [
        {
          "kind": "doublestar",
          "decoration": "repoMatches",
          "pattern": "**"
        }
      ]
    }
  }'

Configurer un endpoint de réplication

# Ajouter un endpoint de replication (registre DR)
curl -X POST https://harbor.example.com/api/v2.0/registries \
  -H "Content-Type: application/json" \
  -u admin:NEW_SECURE_PASSWORD \
  -d '{
    "name": "harbor-dr",
    "type": "harbor",
    "url": "https://harbor-dr.example.com",
    "credential": {
      "type": "basic",
      "access_key": "robot-replicator",
      "access_secret": "ROBOT_TOKEN"
    },
    "insecure": false
  }'

# Creer une regle de replication push
curl -X POST https://harbor.example.com/api/v2.0/replication/policies \
  -H "Content-Type: application/json" \
  -u admin:NEW_SECURE_PASSWORD \
  -d '{
    "name": "dr-replication",
    "src_registry": null,
    "dest_registry": {"id": 1},
    "dest_namespace_replace_count": 0,
    "trigger": {
      "type": "event_based"
    },
    "filters": [
      {"type": "name", "value": "app-*/**"},
      {"type": "tag", "value": "v*"}
    ],
    "enabled": true,
    "override": true
  }'

Vérification du déploiement

# Tester le login
podman login harbor.example.com -u admin -p NEW_SECURE_PASSWORD

# Pousser une image de test
podman pull docker.io/library/alpine:3.20
podman tag docker.io/library/alpine:3.20 harbor.example.com/library/alpine:3.20
podman push harbor.example.com/library/alpine:3.20

# Verifier le scan
curl -s "https://harbor.example.com/api/v2.0/projects/library/repositories/alpine/artifacts/3.20?with_scan_overview=true" \
  -u admin:NEW_SECURE_PASSWORD | jq '.scan_overview'

# Tester le pull
podman rmi harbor.example.com/library/alpine:3.20
podman pull harbor.example.com/library/alpine:3.20

Checklist post-installation

  • Mot de passe admin change et stocke dans Vault
  • Authentification OIDC configuree (Keycloak)
  • Projets crees avec scan automatique et tag immutability
  • Scanner Trivy verifie et base CVE a jour
  • Robot accounts crees pour CI/CD et Kubernetes
  • Réplication configuree vers le site DR
  • Metriques Prometheus accessibles
  • TLS verifie (pas de certificat auto-signe en production)