diff options
Diffstat (limited to 'src/components/demos/zero-trust/scenarios')
4 files changed, 410 insertions, 0 deletions
diff --git a/src/components/demos/zero-trust/scenarios/classic-perimeter.ts b/src/components/demos/zero-trust/scenarios/classic-perimeter.ts new file mode 100644 index 0000000..6a6347d --- /dev/null +++ b/src/components/demos/zero-trust/scenarios/classic-perimeter.ts @@ -0,0 +1,123 @@ +import type { Edge, Node } from "@xyflow/react";
+import { MarkerType } from "@xyflow/react";
+import type { ZTNodeData, ZTScenarioDefinition } from "../types";
+
+const node = (
+ id: string,
+ x: number,
+ y: number,
+ data: ZTNodeData,
+): Node<ZTNodeData> => ({
+ id,
+ type: "ztNode",
+ position: { x, y },
+ data,
+});
+
+const edge = (
+ id: string,
+ source: string,
+ target: string,
+ label: string,
+ opts?: { dashed?: boolean; color?: string },
+): Edge => ({
+ id,
+ source,
+ target,
+ label,
+ animated: true,
+ markerEnd: { type: MarkerType.ArrowClosed, width: 18, height: 18 },
+ style: opts?.dashed
+ ? { strokeDasharray: "6 4", stroke: opts.color ?? "#94a3b8" }
+ : { stroke: opts?.color ?? "#64748b" },
+ labelStyle: { fill: "#334155", fontWeight: 500, fontSize: 11 },
+ labelBgStyle: { fill: "#f8fafc", fillOpacity: 0.95 },
+});
+
+export const classicPerimeterScenario: ZTScenarioDefinition = {
+ id: "classic-perimeter",
+ title: "Périmètre réseau classique",
+ subtitle: "Confiance implicite « à l’intérieur » du LAN",
+ intro:
+ "Modèle souvent associé au VPN : une fois le tunnel établi, le trafic interne est largement considéré comme fiable. Les déplacements latéraux (east-west) peuvent rester peu contrôlés.",
+ nodes: [
+ node("user", 40, 200, {
+ kind: "user",
+ label: "Utilisateur",
+ role: "Identité",
+ }),
+ node("laptop", 200, 200, {
+ kind: "device",
+ label: "Poste",
+ role: "Appareil",
+ }),
+ node("vpn", 360, 200, {
+ kind: "gateway",
+ label: "Passerelle / VPN",
+ role: "Réseau",
+ }),
+ node("lan", 560, 120, {
+ kind: "network",
+ label: "LAN « de confiance »",
+ role: "Segment interne",
+ }),
+ node("app", 560, 40, {
+ kind: "workload",
+ label: "Application",
+ role: "Charge de travail",
+ }),
+ node("db", 720, 200, {
+ kind: "data",
+ label: "Données",
+ role: "Stockage",
+ }),
+ ],
+ edges: [
+ edge("e-u-l", "user", "laptop", "Session locale"),
+ edge("e-l-v", "laptop", "vpn", "Tunnel VPN", { color: "#0d9488" }),
+ edge("e-v-lan", "vpn", "lan", "Accès réseau étendu"),
+ edge("e-lan-app", "lan", "app", "HTTP/S — confiance zone"),
+ edge("e-app-db", "app", "db", "SQL — souvent large confiance"),
+ ],
+ steps: [
+ {
+ id: "s1",
+ title: "Vue d’ensemble",
+ description:
+ "L’utilisateur joint le réseau via une passerelle. Le segment interne est souvent traité comme un tout.",
+ highlightNodes: ["user", "laptop", "vpn", "lan", "app", "db"],
+ highlightEdges: [],
+ pillars: ["network"],
+ practices: [
+ "Cartographier les flux réels (y compris east-west), pas seulement l’accès distant.",
+ "Ne pas confondre « chiffrement du tunnel » et « confiance des identités ».",
+ ],
+ },
+ {
+ id: "s2",
+ title: "Tunnel jusqu’au périmètre",
+ description:
+ "Le VPN chiffre le transport, mais ne remplace pas une décision d’accès fine à chaque ressource.",
+ highlightNodes: ["laptop", "vpn"],
+ highlightEdges: ["e-l-v"],
+ pillars: ["network", "device"],
+ practices: [
+ "Exiger posture et conformité des appareils (MDM, santé du poste).",
+ "Journaliser les accès au réseau et corréler avec les accès applicatifs.",
+ ],
+ },
+ {
+ id: "s3",
+ title: "Confiance plate en interne",
+ description:
+ "Une fois dans le LAN, l’application parle souvent à la base avec des comptes ou règles larges : surface d’attaque east-west élevée si un poste est compromis.",
+ highlightNodes: ["lan", "app", "db"],
+ highlightEdges: ["e-lan-app", "e-app-db"],
+ pillars: ["application", "data", "network"],
+ practices: [
+ "Segmenter et appliquer des politiques au plus près des charges (micro-segmentation).",
+ "Principe du moindre privilège sur les comptes de service et les flux base de données.",
+ ],
+ },
+ ],
+};
diff --git a/src/components/demos/zero-trust/scenarios/east-west.ts b/src/components/demos/zero-trust/scenarios/east-west.ts new file mode 100644 index 0000000..1200da7 --- /dev/null +++ b/src/components/demos/zero-trust/scenarios/east-west.ts @@ -0,0 +1,126 @@ +import { MarkerType } from "@xyflow/react";
+import type { ZTNodeData, ZTScenarioDefinition } from "../types";
+
+const node = (
+ id: string,
+ x: number,
+ y: number,
+ data: ZTNodeData,
+): Node<ZTNodeData> => ({
+ id,
+ type: "ztNode",
+ position: { x, y },
+ data,
+});
+
+const edgeOk = (
+ id: string,
+ source: string,
+ target: string,
+ label: string,
+): Edge => ({
+ id,
+ source,
+ target,
+ label,
+ animated: true,
+ markerEnd: { type: MarkerType.ArrowClosed, width: 18, height: 18 },
+ style: { stroke: "#0d9488" },
+ labelStyle: { fill: "#134e4a", fontWeight: 500, fontSize: 11 },
+ labelBgStyle: { fill: "#ecfdf5", fillOpacity: 0.95 },
+});
+
+const edgeBlocked = (
+ id: string,
+ source: string,
+ target: string,
+ label: string,
+): Edge => ({
+ id,
+ source,
+ target,
+ label,
+ animated: false,
+ markerEnd: { type: MarkerType.ArrowClosed, width: 18, height: 18, color: "#dc2626" },
+ style: { stroke: "#dc2626", strokeDasharray: "6 4" },
+ labelStyle: { fill: "#991b1b", fontWeight: 600, fontSize: 11 },
+ labelBgStyle: { fill: "#fef2f2", fillOpacity: 0.95 },
+});
+
+export const eastWestScenario: ZTScenarioDefinition = {
+ id: "east-west",
+ title: "Micro-segmentation east-west",
+ subtitle: "Contrôler les flux latéraux entre charges",
+ intro:
+ "Sans segmentation, un compromis sur un service peut se propager. Les politiques réseau et applicatives limitent qui peut parler à qui, avec observabilité centralisée.",
+ nodes: [
+ node("svc-a", 80, 200, {
+ kind: "workload",
+ label: "Service A",
+ role: "Microservice",
+ }),
+ node("svc-b", 480, 200, {
+ kind: "workload",
+ label: "Service B",
+ role: "Microservice",
+ }),
+ node("seg", 280, 200, {
+ kind: "gateway",
+ label: "Segmentation / politique",
+ role: "Contrôle réseau",
+ }),
+ node("siem", 280, 40, {
+ kind: "monitoring",
+ label: "SIEM / observabilité",
+ role: "Journalisation",
+ }),
+ ],
+ edges: [
+ edgeOk("e-a-s", "svc-a", "seg", "Flux autorisé et inspecté"),
+ edgeOk("e-s-b", "seg", "svc-b", "Suite si politique OK"),
+ edgeBlocked("e-a-b", "svc-a", "svc-b", "Direct — refusé"),
+ edgeOk("e-a-m", "svc-a", "siem", "Événements"),
+ edgeOk("e-b-m", "svc-b", "siem", "Événements"),
+ ],
+ steps: [
+ {
+ id: "ew1",
+ title: "Flux latéraux contrôlés",
+ description:
+ "Le chemin autorisé passe par la couche de segmentation (pare-feu distribué, service mesh, politiques cloud).",
+ highlightNodes: ["svc-a", "seg", "svc-b"],
+ highlightEdges: ["e-a-s", "e-s-b"],
+ pillars: ["network", "application"],
+ practices: [
+ "Définir des groupes de charges et des règles explicites (allow-list), pas un « tout ouvert » en interne.",
+ "Réviser régulièrement les règles avec les propriétaires métier.",
+ ],
+ },
+ {
+ id: "ew2",
+ title: "Blocage du raccourci",
+ description:
+ "Une tentative de communication directe entre services sans passer par la politique est refusée et visible.",
+ highlightNodes: ["svc-a", "svc-b"],
+ highlightEdges: ["e-a-b"],
+ pillars: ["network", "data"],
+ practices: [
+ "Supposer la compromission : limiter le blast radius par défaut.",
+ "Tester les règles (red team / tests de fuite) pour valider la segmentation.",
+ ],
+ },
+ {
+ id: "ew3",
+ title: "Visibilité et corrélation",
+ description:
+ "Les journaux remontent vers une couche d’observabilité pour corréler identités, flux et alertes.",
+ highlightNodes: ["svc-a", "svc-b", "siem"],
+ highlightEdges: ["e-a-m", "e-b-m"],
+ pillars: ["network", "application"],
+ practices: [
+ "Never trust, always verify : la supervision continue valide que les politiques sont effectivement appliquées.",
+ "Alertes sur les flux non conformes ou les nouvelles dépendances applicatives.",
+ ],
+ },
+ ],
+};
diff --git a/src/components/demos/zero-trust/scenarios/index.ts b/src/components/demos/zero-trust/scenarios/index.ts new file mode 100644 index 0000000..c8d557b --- /dev/null +++ b/src/components/demos/zero-trust/scenarios/index.ts @@ -0,0 +1,18 @@ +import { classicPerimeterScenario } from "./classic-perimeter";
+import { eastWestScenario } from "./east-west";
+import { zeroTrustAccessScenario } from "./zero-trust-access";
+import type { ZTScenarioDefinition } from "../types";
+
+export const ZERO_TRUST_SCENARIOS: ZTScenarioDefinition[] = [
+ classicPerimeterScenario,
+ zeroTrustAccessScenario,
+ eastWestScenario,
+];
+
+export function getScenarioById(
+ id: string,
+): ZTScenarioDefinition | undefined {
+ return ZERO_TRUST_SCENARIOS.find((s) => s.id === id);
+}
+
+export { classicPerimeterScenario, zeroTrustAccessScenario, eastWestScenario };
diff --git a/src/components/demos/zero-trust/scenarios/zero-trust-access.ts b/src/components/demos/zero-trust/scenarios/zero-trust-access.ts new file mode 100644 index 0000000..9dd3a4d --- /dev/null +++ b/src/components/demos/zero-trust/scenarios/zero-trust-access.ts @@ -0,0 +1,143 @@ +import type { Edge, Node } from "@xyflow/react";
+import { MarkerType } from "@xyflow/react";
+import type { ZTNodeData, ZTScenarioDefinition } from "../types";
+
+const node = (
+ id: string,
+ x: number,
+ y: number,
+ data: ZTNodeData,
+): Node<ZTNodeData> => ({
+ id,
+ type: "ztNode",
+ position: { x, y },
+ data,
+});
+
+const edge = (
+ id: string,
+ source: string,
+ target: string,
+ label: string,
+ color?: string,
+ handles?: { sourceHandle?: string; targetHandle?: string },
+): Edge => ({
+ id,
+ source,
+ target,
+ label,
+ sourceHandle: handles?.sourceHandle,
+ targetHandle: handles?.targetHandle,
+ animated: true,
+ markerEnd: { type: MarkerType.ArrowClosed, width: 18, height: 18 },
+ style: { stroke: color ?? "#0f766e" },
+ labelStyle: { fill: "#134e4a", fontWeight: 500, fontSize: 11 },
+ labelBgStyle: { fill: "#ecfdf5", fillOpacity: 0.95 },
+});
+
+export const zeroTrustAccessScenario: ZTScenarioDefinition = {
+ id: "zero-trust-access",
+ title: "Accès avec vérification continue",
+ subtitle: "Chaque requête est évaluée : identité, contexte, politique",
+ intro:
+ "Approche alignée sur NIST SP 800-207 : pas de confiance implicite au réseau. L’identité et le contexte (appareil, risque) alimentent une décision d’accès avant d’atteindre l’application et les données.",
+ nodes: [
+ node("user", 40, 220, {
+ kind: "user",
+ label: "Utilisateur",
+ role: "Identité",
+ }),
+ node("device", 220, 220, {
+ kind: "device",
+ label: "Poste / mobile",
+ role: "Appareil",
+ }),
+ node("idp", 220, 40, {
+ kind: "idp",
+ label: "IdP (OIDC)",
+ role: "Authentification",
+ }),
+ node("pep", 420, 220, {
+ kind: "gateway",
+ label: "PEP / API GW",
+ role: "Application du contrôle",
+ }),
+ node("app", 600, 120, {
+ kind: "workload",
+ label: "Application",
+ role: "Charge de travail",
+ }),
+ node("data", 600, 300, {
+ kind: "data",
+ label: "Données",
+ role: "Stockage chiffré",
+ }),
+ ],
+ edges: [
+ edge("e-ud", "user", "device", "Interaction", undefined, {
+ sourceHandle: "right-s",
+ targetHandle: "left-t",
+ }),
+ edge("e-di", "device", "idp", "Authorization Code + PKCE", "#0369a1", {
+ sourceHandle: "top-s",
+ targetHandle: "bot-t",
+ }),
+ edge("e-id", "idp", "device", "Jetons (access, refresh)", "#0369a1", {
+ sourceHandle: "bot-s",
+ targetHandle: "top-t",
+ }),
+ edge("e-dp", "device", "pep", "Requête + jeton", "#0f766e", {
+ sourceHandle: "right-s",
+ targetHandle: "left-t",
+ }),
+ edge("e-pa", "pep", "app", "Autorisé si politique OK", "#0f766e", {
+ sourceHandle: "top-s",
+ targetHandle: "bot-t",
+ }),
+ edge("e-ad", "app", "data", "mTLS / chiffrement", "#7c3aed", {
+ sourceHandle: "bot-s",
+ targetHandle: "top-t",
+ }),
+ ],
+ steps: [
+ {
+ id: "z1",
+ title: "Authentification forte et contexte",
+ description:
+ "L’IdP émet des jetons après vérification de l’identité et du contexte (MFA, risque, appareil).",
+ highlightNodes: ["user", "device", "idp"],
+ highlightEdges: ["e-ud", "e-di", "e-id"],
+ pillars: ["identity", "device"],
+ practices: [
+ "MFA adaptatif ; pas de secrets long-terme exposés côté client (PKCE pour les clients publics).",
+ "Évaluer la posture de l’appareil avant d’accorder la session.",
+ ],
+ },
+ {
+ id: "z2",
+ title: "Décision de politique au point d’application",
+ description:
+ "Le PEP (Policy Enforcement Point) applique les règles : qui, quoi, depuis où, avec quel risque — avant d’atteindre la charge de travail.",
+ highlightNodes: ["device", "pep", "app"],
+ highlightEdges: ["e-dp", "e-pa"],
+ pillars: ["application", "network"],
+ practices: [
+ "Séparer clairement PDP (politique) et PEP (application) dans l’architecture cible.",
+ "Moindre privilège : scopes OAuth/OIDC minimaux, rôles applicatifs justifiés.",
+ ],
+ },
+ {
+ id: "z3",
+ title: "Protection des données jusqu’au stockage",
+ description:
+ "Les flux vers les données sont chiffrés et tracés ; l’accès reste soumis au contrôle continu (révocation, session courte, audit).",
+ highlightNodes: ["app", "data"],
+ highlightEdges: ["e-ad"],
+ pillars: ["data", "application"],
+ practices: [
+ "Chiffrement au repos et en transit ; classification des données sensibles.",
+ "Observabilité : journaux corrélés pour détecter les abus de jetons ou les accès anormaux.",
+ ],
+ },
+ ],
+};
|
