Modèle de données¶
Les tables clés sont les suivantes :
- attributes
- domains
- frameworks
- controls
- measures
- documents
- risks
- actions
- exceptions
controls= mesures de sécurité (exigences à mettre en œuvre).
measures= contrôles (vérifications périodiques de ces exigences).
risks= risques de sécurité de l'information (registre ISO 27001 §6.1.2).
actions= plans d'action (remédiation des contrôles en échec et des risques).
exceptions= exceptions (dérogations temporaires à une mesure de sécurité).
Dépendances entre tables¶
Vue d'ensemble : qui utilise quoi.
flowchart LR
controls --> |"domain_id (0:1)"| domains
domains -.->|"framework = code"| frameworks
controls <-->|"control_measure (N:N)"| measures
attributes -.-o |"optional"| controls
attributes -.-o |"optional"| measures
measures -->|"measure_id (0:1)"| measures
documents -->|"document_id (1:1)"| measures
risks -->|"owner_id (0:1)"| users
risks <-->|"control_risk (N:N)"| controls
actions -->|"measure_id (0:1)"| measures
actions <-->|"action_control (N:N)"| controls
actions <-->|"action_risk (N:N)"| risks
actions <-->|"action_user (N:N)"| users
exceptions -->|"control_id (0:1)"| controls
exceptions -->|"created_by, submitted_by, approved_by (0:1)"| users
Le schéma détaillé ci-dessous décrit les champs de chaque table.
erDiagram
domains ||--o{ controls : "domain_id"
frameworks |o--o{ domains : "code = framework"
controls }o--o{ measures : "many-to-many"
attributes }o--o{ controls : "optionnel"
attributes }o--o{ measures : "optionnel"
measures o|--o| measures : "next_id"
documents }o--o| measures : "optionnel"
risks }o--o{ controls : "control_risk"
users ||--o{ risks : "owner_id"
measures |o--o{ actions : "measure_id"
actions }o--o{ controls : "action_control"
actions }o--o{ risks : "action_risk"
actions }o--o{ users : "action_user"
controls |o--o{ exceptions : "control_id"
users |o--o{ exceptions : "created_by, approved_by"
domains {
int id PK
string framework
string title
string description
}
frameworks {
int id PK
string code UK
string name
string version
string publisher
}
attributes {
int id PK
string name
string values
}
controls {
int id PK
int domain_id FK
string name
string clause
string objective
array measures
array attributes
array risks
}
measures {
int id PK
int next_id FK
string name
int periodicity
date plan_date
date realisation_date
int status
array controls
array attributes
}
documents {
int id PK
int measure_id FK
}
risks {
int id PK
int owner_id FK
string name
string status
int probability
int impact
int review_frequency
date next_review_at
array controls
}
actions {
int id PK
int measure_id FK
string reference
int type
int status
int progress
date due_date
date close_date
}
exceptions {
int id PK
int control_id FK
string name
int status
date start_date
date end_date
int created_by FK
int approved_by FK
}
Les relations sont les suivantes :
| Lien | Type | Description |
|---|---|---|
domains → controls |
Clé étrangère (1:N) | Chaque mesure de sécurité référence son domaine via domain_id |
frameworks → domains |
Optionnel (1:N) via le code | Le champ framework d'un domaine contient le code de son référentiel ; la ligne de frameworks y ajoute ses métadonnées |
controls ↔ measures |
Many-to-many (bidirectionnel) | Chaque mesure de sécurité liste ses instances d'audit dans measures[] ; chaque instance d'audit liste ses mesures de sécurité dans controls[] |
attributes → controls |
Optionnel | Le champ attributes d'une mesure de sécurité peut contenir une liste d'IDs d'attributs |
attributes → measures |
Optionnel | Idem pour les instances d'audit |
measures → measures |
Auto-référence via next_id |
Permet de chaîner les campagnes successives d'un même audit |
documents → measures |
Optionnel (1:N) | Les documents et preuves sont attachés aux instances d'audit via measure_id |
risks ↔ controls |
Many-to-many via control_risk |
Un risque mitigé doit être lié à au moins un contrôle de sécurité ; la liste est stockée dans controls[] du risque |
users → risks |
Optionnel (1:N) | Chaque risque peut être attribué à un propriétaire (owner_id) responsable de la revue périodique |
measures → actions |
Optionnel (1:N) | Un plan d'action créé lors de la réalisation d'un contrôle le référence via measure_id |
actions ↔ controls |
Many-to-many via action_control |
Mesures de sécurité (clauses) concernées par le plan d'action |
actions ↔ risks |
Many-to-many via action_risk |
Plans d'action traitant un risque ; requis pour un risque Non accepté |
actions ↔ users |
Many-to-many via action_user |
Responsables du plan d'action |
controls → exceptions |
Optionnel (1:N) | Chaque exception référence la mesure de sécurité à laquelle elle déroge via control_id |
users → exceptions |
Optionnel (1:N) | Auteur (created_by), demandeur (submitted_by) et valideur (approved_by) de l'exception |
Note : il n'y a pas de table de jonction exposée pour la relation controls/measures.
Les IDs sont directement embarqués dans chaque objet des deux côtés.
La table pivotcontrol_riskrelie les risques aux mesures de sécurité.
Les tables pivotaction_control,action_risketaction_userrelient les plans d'action aux mesures de sécurité, aux risques et aux responsables.
attributes¶
Les attributs sont des référentiels de classification multi-valeurs.
Chaque attribut définit un ensemble de tags (préfixés #) qui peuvent être associés aux mesures de sécurité et aux instances d'audit.
| Champ | Type | Description |
|---|---|---|
id |
integer | Identifiant unique (PK) |
name |
string | Intitulé de la taxonomie (ex : Security measures, Risk_Level) |
values |
string | Liste de valeurs possibles séparées par des espaces, chacune préfixée # (ex : #Preventive #Detective #Corrective) |
created_at |
datetime | Date de création (ISO 8601, UTC) |
updated_at |
datetime | Date de dernière modification |
Exemple :
{
"id": 1,
"name": "Security measures",
"values": "#Preventive #Detective #Corrective",
"created_at": "2026-05-17T20:35:52.000000Z",
"updated_at": "2026-05-17T20:35:52.000000Z"
}
domains¶
Les domaines regroupent les mesures de sécurité par thématique.
Chaque domaine appartient à un cadre réglementaire ou méthodologique (framework).
| Champ | Type | Description |
|---|---|---|
id |
integer | Identifiant unique (PK) |
framework |
string | Référentiel d'appartenance (ex : NIS2, Vulnerability Management) |
title |
string | Nom du domaine (ex : Pilotage et Gouvernance NIS2) |
description |
string | Description du périmètre couvert, souvent avec référence à l'article ou à la norme |
created_at |
datetime | Date de création |
updated_at |
datetime | Date de dernière modification |
Exemple :
{
"id": 1,
"framework": "NIS2",
"title": "Pilotage et Gouvernance NIS2",
"description": "Pilotage stratégique et opérationnel selon Art. 21.1 et 21.2.a",
"created_at": "2026-05-17T20:35:52.000000Z",
"updated_at": "2026-05-17T20:35:52.000000Z"
}
frameworks¶
La table frameworks ajoute des métadonnées aux codes de référentiel utilisés dans domains.framework. Elle ne remplace
pas ce champ : un référentiel est lié à ses domaines, et à travers eux à ses mesures de sécurité, par son code.
Une ligne est créée automatiquement, avec le code comme nom, lorsqu'un domaine est enregistré avec un nouveau code de
référentiel. Les correspondances utilisent ces codes pour choisir les référentiels source et cible.
| Champ | Type | Description |
|---|---|---|
id |
integer | Identifiant unique (PK) |
code |
string | Code du référentiel, identique à domains.framework (unique, ex. : 27001:2022) |
name |
string | Nom du référentiel (le code par défaut) |
version |
string | Version du référentiel (vide par défaut) |
publisher |
string | Éditeur du référentiel (vide par défaut) |
jurisdiction |
string | null | Juridiction dans laquelle le référentiel s'applique |
source_url |
string | null | URL de la source officielle |
status |
string | null | Statut du référentiel (texte libre) |
publication_date |
date | null | Date de publication |
effective_date |
date | null | Date d'entrée en vigueur |
notes |
string | null | Notes libres |
created_at |
datetime | Date de création |
updated_at |
datetime | Date de dernière modification |
Exemple :
{
"id": 2,
"code": "NIS2-ReCyF-2.5-FR",
"name": "ReCyF 2.5",
"version": "2.5",
"publisher": "ANSSI",
"jurisdiction": "France",
"source_url": "https://messervices.cyber.gouv.fr/nis2#exigences",
"status": null,
"publication_date": null,
"effective_date": null,
"notes": null
}
controls¶
Les mesures de sécurité décrivent les exigences à mettre en œuvre.
Chaque mesure de sécurité appartient à un domaine et est vérifiée par une ou plusieurs instances d'audit.
| Champ | Type | Description |
|---|---|---|
id |
integer | Identifiant unique (PK) |
domain_id |
integer | Référence vers domains.id (FK, obligatoire) |
name |
string | Nom de la mesure, souvent avec le numéro d'article (ex : Art.21.2.a - Analyse de Risques) |
clause |
string | Identifiant court de la clause normative (ex : NIS2-Art.21.2.a) |
objective |
string | Objectif attendu par cette mesure de sécurité |
input |
string | null | Données ou ressources nécessaires à la mise en œuvre |
model |
string | null | Modèle ou méthode opérationnelle recommandée |
indicator |
string | null | Indicateur de performance structuré (Target, Frequency, Owner) |
action_plan |
string | null | Plan d'action ou traitement associé |
attributes |
array | null | Liste d'IDs d'attributs associés ; null si aucun |
measures |
array | Liste des IDs d'instances d'audit qui vérifient cette mesure de sécurité |
created_at |
datetime | Date de création |
updated_at |
datetime | Date de dernière modification |
Exemple :
{
"id": 1,
"domain_id": 1,
"name": "Art.21.2.a - Analyse de Risques",
"clause": "NIS2-Art.21.2.a",
"objective": "Évaluation des menaces pesant sur les actifs critiques selon méthodologie EBIOS RM ou équivalent",
"input": "Liste des actifs critiques, méthodologie EBIOS RM",
"model": "Analyse annuelle selon ISO 27005 ou EBIOS RM",
"indicator": "Target: Score résiduel ≤ acceptable | Frequency: Annuel | Owner: RSSI",
"action_plan": "Plan de traitement des risques validé par Direction",
"attributes": null,
"measures": [1]
}
measures¶
Les instances d'audit décrivent les vérifications opérationnelles périodiques.
Une instance d'audit vérifie qu'une ou plusieurs mesures de sécurité sont bien appliquées.
Elle porte les données de planification, de réalisation et de résultat.
| Champ | Type | Description |
|---|---|---|
id |
integer | Identifiant unique (PK) |
name |
string | Intitulé de la vérification |
objective |
string | null | Objectif spécifique de cette instance d'audit |
input |
string | null | Données ou preuves nécessaires à la réalisation |
model |
string | null | Mode opératoire de l'audit |
action_plan |
string | null | Actions correctives si l'audit échoue |
periodicity |
integer | null | Fréquence en mois (ex : 12 = annuel, 3 = trimestriel) |
plan_date |
date | null | Date prévue de réalisation (YYYY-MM-DD) |
realisation_date |
date | null | Date effective de réalisation |
observations |
string | null | Commentaires libres sur le résultat |
score |
number | null | Score numérique issu de l'évaluation ; null si non réalisé |
note |
number | null | Note qualitative complémentaire |
status |
integer | État courant de l'instance d'audit (voir ci-dessous) |
next_id |
integer | null | ID de l'instance suivante dans la chaîne historique (FK self) |
attributes |
array | null | Liste d'IDs d'attributs associés ; null si aucun |
scope |
string | null | Périmètre d'application (entité, site, système) |
controls |
array | Liste des IDs de mesures de sécurité vérifiées par cette instance d'audit |
created_at |
datetime | Date de création |
updated_at |
datetime | Date de dernière modification |
Valeurs du champ status¶
| Valeur | Signification |
|---|---|
0 |
À réaliser / Non planifié (realisation_date est null) |
1 |
Proposé (l'audité a soumis un résultat, en attente de validation) |
2 |
Réalisé / Terminé (realisation_date est renseignée) |
Exemple :
{
"id": 1,
"name": "Revue et signature formelle de l'analyse de risques",
"objective": "Validation par la direction de la stratégie de traitement des risques",
"model": "Présentation Codir + signature formelle",
"periodicity": 12,
"plan_date": "2026-07-31",
"realisation_date": "2025-03-25",
"score": null,
"status": 2,
"next_id": null,
"attributes": null,
"scope": null,
"controls": [1]
}
documents¶
La table documents stocke les pièces jointes et preuves documentaires associées aux instances d'audit.
Chaque document est lié à un enregistrement measures via measure_id.
risks¶
Le registre des risques enregistre les risques de sécurité de l'information conformément aux exigences de la norme ISO 27001:2022 §6.1.2 et §8.2.
Chaque risque est évalué selon une méthode de scoring configurable, optionnellement assigné à un propriétaire, et soumis à un cycle de revue périodique.
Un risque avec le statut Mitigé doit être lié à au moins un contrôle de sécurité via la table pivot control_risk.
| Champ | Type | Description |
|---|---|---|
id |
integer | Identifiant unique (PK) |
name |
string | Intitulé court et identifiable du risque (obligatoire) |
description |
string | null | Description détaillée du risque |
owner_id |
integer | null | Référence vers users.id — responsable de la revue périodique |
probability |
integer | Niveau de probabilité (1 à N, formules standard), ou niveau de menace avec la formule MONARC |
probability_comment |
string | null | Commentaire libre sur l'évaluation de la probabilité |
impact |
integer | Niveau de gravité si le risque se matérialise (1 à N) |
impact_comment |
string | null | Commentaire libre sur l'évaluation de l'impact |
exposure |
integer | null | Accessibilité du système (formule BSI 200-3 : 0 = hors réseau, 1 = interne, 2 = Internet) |
vulnerability |
integer | null | Niveau d'exploitabilité des failles connues (formule BSI 200-3), ou niveau de vulnérabilité (formule MONARC) |
residual_risk |
integer | null | Risque résiduel saisi manuellement (formule MONARC uniquement) |
status |
enum | Décision de traitement (voir valeurs ci-dessous) |
status_comment |
string | null | Commentaire libre sur la décision de traitement |
review_frequency |
integer | Intervalle en mois entre deux revues (défaut : 12) |
next_review_at |
date | null | Date prévue de la prochaine revue |
controls |
array | Liste des IDs de contrôles de sécurité liés à ce risque (via control_risk) |
created_at |
datetime | Date de création |
updated_at |
datetime | Date de dernière modification |
deleted_at |
datetime | null | Date de suppression logique |
Valeurs du champ status¶
| Valeur | Signification |
|---|---|
not_evaluated |
Non évalué |
not_accepted |
Non accepté — un plan d'action lié est requis |
temporarily_accepted |
Accepté temporairement |
accepted |
Accepté |
mitigated |
Mitigé — au moins un contrôle de sécurité lié est requis |
transferred |
Transféré (assurance, tiers) |
avoided |
Évité |
Exemple :
{
"id": 1,
"name": "Accès non autorisé aux données sensibles",
"description": "Risque d'exfiltration de données via des identifiants compromis.",
"owner_id": 3,
"probability": 3,
"impact": 4,
"exposure": null,
"vulnerability": null,
"residual_risk": null,
"status": "mitigated",
"status_comment": "Politique de contrôle d'accès déployée au T1.",
"review_frequency": 12,
"next_review_at": "2027-06-01",
"controls": [12, 15],
"created_at": "2026-06-09T10:00:00.000000Z",
"updated_at": "2026-06-09T10:00:00.000000Z",
"deleted_at": null
}
actions¶
La table actions contient les plans d'action mis en place pour remédier à un contrôle en échec, à une non-conformité
ou à un risque. Un plan d'action peut être créé manuellement ou lors de la réalisation d'un contrôle ; il est alors lié
à ce contrôle via measure_id. Les mesures de sécurité, les risques et les responsables d'un plan d'action sont
stockés dans les tables pivot action_control, action_risk et action_user.
| Champ | Type | Description |
|---|---|---|
id |
integer | Identifiant unique (PK) |
reference |
string | null | Référence du plan d'action (ex. : ACT-2026-001, 32 caractères max.) |
type |
integer | Type de plan d'action (voir valeurs ci-dessous) |
status |
integer | Statut du plan d'action (voir valeurs ci-dessous) |
progress |
integer | null | Avancement en pourcentage (0 à 100) |
criticity |
integer | Non utilisé par l’application |
name |
string | null | Nom du plan d'action |
scope |
string | null | Périmètre (32 caractères max.) |
cause |
string | null | Cause du plan d'action (observations du contrôle en échec) |
remediation |
string | null | Remédiation à réaliser |
measure_id |
integer | null | Référence vers measures.id — contrôle à l'origine du plan d'action |
creation_date |
date | null | Date de création du plan d'action |
due_date |
date | null | Date d'échéance |
close_date |
date | null | Date de clôture |
justification |
string | null | Justification de la clôture ou du rejet |
created_at |
datetime | Date de création |
updated_at |
datetime | Date de dernière modification |
Valeurs du champ type¶
| Valeur | Signification |
|---|---|
1 |
Non-conformité majeure |
2 |
Non-conformité mineure |
3 |
Observation |
4 |
Opportunité d'amélioration |
Valeurs du champ status¶
| Valeur | Signification |
|---|---|
0 |
Ouvert |
1 |
Clôturé |
2 |
Rejeté |
Exemple :
{
"id": 1,
"reference": "ACT-2026-001",
"type": 1,
"status": 0,
"progress": 60,
"criticity": 0,
"name": "Déploiement de l'authentification multifacteur sur les comptes à privilèges",
"scope": "Systèmes d'information",
"cause": "Les comptes administrateur ne sont protégés que par un mot de passe, sans second facteur d'authentification.",
"remediation": "Déployer une solution MFA (TOTP ou clé physique) sur l'ensemble des comptes à privilèges.",
"measure_id": null,
"creation_date": "2026-04-01",
"due_date": "2026-09-30",
"close_date": null,
"justification": null
}
exceptions¶
La table exceptions enregistre les exceptions (dérogations) accordées lorsqu'une mesure de sécurité ne peut pas être
appliquée : justification, mesures compensatoires et période de validité. Une exception suit un workflow de validation :
elle est créée en brouillon, soumise, puis approuvée ou refusée par un administrateur.
| Champ | Type | Description |
|---|---|---|
id |
integer | Identifiant unique (PK) |
control_id |
integer | null | Référence vers controls.id — mesure de sécurité concernée par l'exception |
name |
string | Nom de l'exception (obligatoire) |
description |
string | null | Description de l'exception |
justification |
string | null | Justification métier (raison pour laquelle la mesure de sécurité ne peut pas être appliquée) |
compensating_controls |
string | null | Mesures compensatoires réduisant le risque résiduel |
start_date |
date | null | Début de la période de validité |
end_date |
date | null | Fin de la période de validité ; null si pas d'échéance |
status |
integer | Statut de l'exception (voir valeurs ci-dessous) |
created_by |
integer | null | Référence vers users.id — auteur de l'exception |
submitted_by |
integer | null | Référence vers users.id — utilisateur ayant soumis l'exception |
submitted_at |
datetime | null | Date de soumission |
approved_by |
integer | null | Référence vers users.id — administrateur ayant approuvé ou refusé l'exception |
approved_at |
datetime | null | Date d'approbation ou de refus |
approval_comment |
string | null | Commentaire d'approbation, ou motif du refus |
created_at |
datetime | Date de création |
updated_at |
datetime | Date de dernière modification |
Valeurs du champ status¶
| Valeur | Signification |
|---|---|
0 |
Brouillon |
1 |
Soumise (en attente de validation) |
2 |
Approuvée |
3 |
Refusée |
4 |
Expirée |
Une exception approuvée dont la date de fin est dépassée est également affichée comme expirée.
Exemple :
{
"id": 4,
"control_id": 68,
"name": "Maintien temporaire d'un accès VPN partagé pour un prestataire",
"description": "Un compte VPN partagé continue d'être utilisé par le prestataire de maintenance applicative.",
"justification": "Le projet de bascule vers des accès nominatifs a pris du retard côté prestataire.",
"compensating_controls": "Journalisation renforcée des connexions et restriction des horaires d'accès.",
"start_date": "2026-03-01",
"end_date": "2026-06-01",
"status": 3,
"created_by": 2,
"submitted_by": 2,
"submitted_at": "2026-02-20T09:00:00.000000Z",
"approved_by": 1,
"approved_at": "2026-02-25T14:00:00.000000Z",
"approval_comment": "Les accès nominatifs doivent être en place avant la date de fin."
}