Confidentialite¶
Harbor manipule des données classees Confidentiel : images conteneur embarquant du code proprietaire, des fichiers de configuration et des charts Helm revelant l'architecture interne. Ce chapitre detaille les mesures de protection correspondantes, en référence au cadre de Classification et zones de confiance.
Rappel de classification¶
| Donnée | Classification | Justification |
|---|---|---|
| Images conteneur applicatives | Confidentiel | Contiennent le code compile et les configs |
| Charts Helm | Confidentiel | Révèlent l'architecture de déploiement |
| SBOM et attestations | Confidentiel | Révèlent la liste des dependances |
| Images de base (library) | Interne | Images publiques validees, pas de code proprietaire |
| Résultats de scan | Confidentiel | Révèlent les vulnerabilites exploitables |
| Credentials robot accounts | Restreint | Accès direct au push/pull |
| Logs d'audit Harbor | Confidentiel | Révèlent les patterns d'usage et de déploiement |
| Configuration Harbor (DB, cles) | Restreint | Compromission = contrôle total du registre |
Impact d'une compromission
La compromission du registre permet à un attaquant d'injecter des images malveillantes qui seront déployées automatiquement en production. C'est un vecteur d'attaque de la supply chain logicielle.
RBAC par projet¶
Modèle de rôles¶
Harbor définit des rôles par projet avec des permissions granulaires :
| Rôle | Push | Pull | Scan | Delete | Config projet | Robot mgmt |
|---|---|---|---|---|---|---|
| Project Admin | Oui | Oui | Oui | Oui | Oui | Oui |
| Maintainer | Oui | Oui | Oui | Oui | Non | Oui |
| Developer | Oui | Oui | Non | Non | Non | Non |
| Guest | Non | Oui | Non | Non | Non | Non |
| Limited Guest | Non | Oui* | Non | Non | Non | Non |
*Limited Guest : pull uniquement sur les artefacts explicitement partages.
Configuration des projets¶
# Projet prive — equipe backend uniquement
curl -X POST https://harbor.example.com/api/v2.0/projects \
-H "Content-Type: application/json" \
-u admin:ADMIN_PASSWORD \
-d '{
"project_name": "app-backend",
"public": false,
"metadata": {
"auto_scan": "true",
"severity": "high",
"enable_content_trust": "true",
"prevent_vul": "true",
"reuse_sys_cve_allowlist": "true"
}
}'
# Ajouter un membre avec le role Developer
curl -X POST "https://harbor.example.com/api/v2.0/projects/app-backend/members" \
-H "Content-Type: application/json" \
-u admin:ADMIN_PASSWORD \
-d '{
"role_id": 2,
"member_user": {
"username": "dev-jean"
}
}'
Matrice d'accès recommandee¶
| Projet | Visibilité | Équipe DevOps | Équipe Dev | Kubernetes | Auditeurs |
|---|---|---|---|---|---|
library | Public* | Admin | Guest | Pull | Guest |
app-backend | Prive | Maintainer | Developer | Pull | Guest |
app-frontend | Prive | Maintainer | Developer | Pull | Guest |
charts | Prive | Admin | Developer | Pull | Guest |
mirror | Public* | Admin | Guest | Pull | Guest |
*Public interne = visible par tous les utilisateurs authentifies Harbor, pas accessible depuis Internet.
Robot accounts avec scope minimal¶
Principe du moindre privilege¶
Chaque robot account ne doit avoir que les permissions strictement nécessaires :
| Robot | Projets autorises | Permissions | Expire |
|---|---|---|---|
robot-ci-backend | app-backend | Push, Pull | 90 jours |
robot-ci-frontend | app-frontend | Push, Pull | 90 jours |
robot-k8s-prod | app-*, library, charts | Pull | 90 jours |
robot-k8s-dev | library | Pull | 30 jours |
robot-mirror | mirror | Push, Pull | 180 jours |
# Creer un robot CI avec scope minimal
curl -X POST https://harbor.example.com/api/v2.0/robots \
-H "Content-Type: application/json" \
-u admin:ADMIN_PASSWORD \
-d '{
"name": "robot-ci-backend",
"description": "CI/CD push for app-backend only",
"duration": 90,
"level": "project",
"permissions": [
{
"namespace": "app-backend",
"kind": "project",
"access": [
{"resource": "repository", "action": "push"},
{"resource": "repository", "action": "pull"},
{"resource": "tag", "action": "create"},
{"resource": "artifact-label", "action": "create"}
]
}
]
}'
Ne jamais utiliser le compte admin dans les pipelines
Le compte admin a accès a tous les projets et toutes les fonctions. Utiliser exclusivement des robot accounts avec des scopes limites dans les pipelines CI/CD et les configurations Kubernetes.
Politique de scan de vulnerabilites¶
Configuration de la politique de blocage¶
Harbor peut empecher le pull d'images contenant des vulnerabilites critiques :
| Sévérité | Action | Applicable a |
|---|---|---|
| Critical | Bloquer le pull | Tous les projets |
| High | Bloquer le pull | Projets applicatifs |
| Medium | Alerte, pull autorise | Tous les projets |
| Low | Information, pas d'action | Tous les projets |
# Configurer la politique de blocage sur un projet
curl -X PUT "https://harbor.example.com/api/v2.0/projects/app-backend" \
-H "Content-Type: application/json" \
-u admin:ADMIN_PASSWORD \
-d '{
"metadata": {
"prevent_vul": "true",
"severity": "high",
"auto_scan": "true"
}
}'
CVE allowlist¶
Pour les vulnerabilites connues sans correctif disponible (unfixed), Harbor permet de définir une allowlist :
# Ajouter une CVE a la allowlist du projet
curl -X PUT "https://harbor.example.com/api/v2.0/projects/app-backend" \
-H "Content-Type: application/json" \
-u admin:ADMIN_PASSWORD \
-d '{
"cve_allowlist": {
"items": [
{"cve_id": "CVE-2024-12345"},
{"cve_id": "CVE-2024-67890"}
],
"expires_at": 1735689600
}
}'
Allowlist avec expiration
Toute CVE ajoutee a la allowlist doit avoir une date d'expiration. Les exceptions permanentes ne sont pas acceptables — elles doivent etre revues régulièrement.
Tag immutability¶
L'immutabilite des tags empeche l'ecrasement d'une version déjà poussee. C'est une protection critique contre la modification malveillante d'images en production.
Regles d'immutabilite¶
| Pattern de tag | Immutable | Justification |
|---|---|---|
v*.*.* | Oui | Versions semantiques — jamais ecrasees |
sha-* | Oui | Hash de commit — identifiant unique |
latest | Non | Tag mutable par nature, usage dev uniquement |
*-dev | Non | Tags de développement, réutilisables |
# Creer une regle d'immutabilite
curl -X POST "https://harbor.example.com/api/v2.0/projects/app-backend/immutabletagrules" \
-H "Content-Type: application/json" \
-u admin:ADMIN_PASSWORD \
-d '{
"tag_selectors": [
{
"kind": "doublestar",
"decoration": "matches",
"pattern": "v*.*.*"
},
{
"kind": "doublestar",
"decoration": "matches",
"pattern": "sha-*"
}
],
"scope_selectors": {
"repository": [
{
"kind": "doublestar",
"decoration": "repoMatches",
"pattern": "**"
}
]
}
}'
Audit log¶
Événements traces¶
Harbor journalise toutes les opérations sur les artefacts :
| Événement | Données enregistrees | Retention |
|---|---|---|
| Push artefact | Qui, quoi, digest, tag, timestamp | 1 an |
| Pull artefact | Qui, quoi, digest, tag, IP source, timestamp | 1 an |
| Delete artefact | Qui, quoi, digest, tag, timestamp | 5 ans |
| Scan lance/termine | Artefact, résultats (nb vulns), timestamp | 1 an |
| Réplication | Source, destination, artefacts, statut, timestamp | 1 an |
| Creation/suppression robot | Admin, robot name, scope, timestamp | 5 ans |
| Modification projet | Admin, projet, changements, timestamp | 5 ans |
| Connexion/deconnexion | Utilisateur, IP, méthode auth, timestamp | 1 an |
Exporter les logs vers le SIEM¶
# Configurer Alloy/Promtail pour collecter les logs Harbor
# alloy-harbor.river
loki.source.kubernetes "harbor" {
targets = discovery.kubernetes.harbor.targets
forward_to = [loki.write.default.receiver]
clustering {
enabled = true
}
}
discovery.kubernetes "harbor" {
role = "pod"
namespaces {
names = ["harbor"]
}
selectors {
role = "pod"
label = "app=harbor"
}
}
Alertes de sécurité sur les logs¶
| Alerte | Condition | Sévérité |
|---|---|---|
| Push non autorise | Push depuis une IP hors CI/CD | Critical |
| Suppression d'artefact en prod | Delete sur un projet applicatif | Warning |
| Echec de scan répète | > 3 scan failures consecutifs | Warning |
| Robot token expire utilise | Authentification échouée avec robot token | Warning |
| Modification de politique projet | Changement de sévérité ou d'immutabilite | Info |
Stockage chiffre¶
Chiffrement au repos¶
| Composant | Méthode de chiffrement |
|---|---|
| Blobs (images) | MinIO server-side encryption (SSE-S3 ou SSE-KMS) |
| PostgreSQL | TDE (Transparent Data Encryption) ou chiffrement volume |
| Redis | Chiffrement volume |
| Backups | AES-256 via Vault Transit |
# Configurer MinIO avec chiffrement SSE-KMS
mc admin config set minio identity_openid \
config_url="https://keycloak.example.com/realms/organization/.well-known/openid-configuration"
# Activer le chiffrement par defaut sur le bucket
mc encrypt set sse-s3 minio/harbor-registry
Chiffrement en transit¶
| Flux | Protocole | Port |
|---|---|---|
| Client → Harbor | TLS 1.3 | 443 |
| Harbor Core → Registry | mTLS | 5000 |
| Harbor → PostgreSQL | TLS (require) | 5432 |
| Harbor → Redis | TLS | 6380 |
| Harbor → MinIO | TLS | 9000 |
| Réplication inter-Harbor | TLS | 443 |
Isolation réseau¶
Harbor est déployé dans la zone Chaîne logicielle avec des regles de flux strictes :
┌─────────────────────────────────────────────────────────┐
│ Zone Chaine logicielle │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Segment Registre (10.30.2.0/24) │ │
│ │ │ │
│ │ ┌────────┐ ┌────────┐ ┌───────┐ ┌─────┐ │ │
│ │ │ Harbor │ │ Harbor │ │ Trivy │ │Redis│ │ │
│ │ │ Core#1 │ │ Core#2 │ │ │ │ │ │ │
│ │ └────────┘ └────────┘ └───────┘ └─────┘ │ │
│ │ │ │
│ │ ┌────────┐ ┌───────────┐ │ │
│ │ │Registry│ │PostgreSQL │ │ │
│ │ └────────┘ └───────────┘ │ │
│ └──────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
Regles de flux¶
| Source | Destination | Port | Protocole | Justification |
|---|---|---|---|---|
| CI/CD (Gitea Actions) | Harbor | 443/TCP | HTTPS | Push images et charts |
| Kubernetes (prod) | Harbor | 443/TCP | HTTPS | Pull images |
| Kubernetes (dev) | Harbor | 443/TCP | HTTPS | Pull images de base |
| Harbor | PostgreSQL | 5432/TCP | TLS | Metadonnees |
| Harbor | MinIO | 9000/TCP | TLS | Stockage blobs |
| Harbor | Redis | 6380/TCP | TLS | Cache et queue |
| Harbor | NVD/GitHub | 443/TCP | HTTPS | Mise à jour base CVE |
| Harbor | Harbor DR | 443/TCP | HTTPS | Réplication |
| Management | Harbor | 9090/TCP | HTTPS | Metriques Prometheus |
Aucun accès direct aux composants internes
PostgreSQL, Redis et MinIO ne sont accessibles que depuis les composants Harbor. Aucun autre service ne doit pouvoir s'y connecter directement.