Sécurité système vs sécurité code¶
Deux niveaux complementaires — l'un protégé le code, l'autre protégé la structure.
Deux niveaux, deux responsabilités¶
La sécurité d'un système se joue a deux niveaux distincts. Au niveau du code, on traite les vulnérabilités applicatives : injections SQL, mauvaise gestion des secrets, dépendances compromises. Au niveau de l'architecture, on traite la structure du système : comment les composants se font confiance, comment les flux sont segmentes, comment les frontieres de sécurité sont définies.
Ces deux niveaux sont complementaires. Un code parfaitement sécurisé dans une architecture mal conçue reste vulnerable — un attaquant qui compromet un service interne peut pivoter librement si aucune frontiere de confiance ne l'en empêché. Inversement, une architecture bien segmentee n'empêche pas les vulnérabilités applicatives dans chaque service.
La sécurité applicative (OWASP, gestion des secrets, SAST/DAST) est traitee dans Securiser son code. Ce chapitre se concentre sur la sécurité au niveau des composants, des flux et des zones de confiance.
Questions de l'architecture¶
Les questions que l'architecture de sécurité doit traiter :
- Quels composants peuvent communiquer entre eux ?
- Sur quel fondement accorde-t-on la confiance entre services ?
- Comment les données traversent-elles les frontieres de sécurité ?
- Quelles garanties offre le système si un composant est compromis ?
- Comment détecté-t-on et contient-on une breche ?
Questions du code¶
Les questions que le code sécurisé doit traiter :
- Comment valider les entrees utilisateur ?
- Comment gérer les tokens et les sessions ?
- Comment éviter les injections ?
- Comment stocker les secrets ?
- Comment gérer les erreurs sans exposer d'informations sensibles ?
Les deux niveaux doivent être traites. Un code sécurisé dans une architecture non segmentee reste vulnerable à la propagation laterale. Une architecture bien segmentee avec du code vulnerable reste exposee aux attaques applicatives dans chaque zone.
En pratique, la répartition des responsabilités entre équipes suit souvent cette séparation. L'équipe sécurité et les architectes traitent la sécurité système. Les équipes de développement traitent la sécurité du code. La coordination entre les deux est le rôle du RSSI ou du security champion.
Principes de sécurité architecturale¶
Les principes de sécurité architecturale guident les décisions de conception. Ils ne sont pas des règles rigides mais des heuristiques eprouvees — les violer doit être un choix délibéré et documente, jamais un oubli.
Moindre privilege¶
Chaque composant, service ou utilisateur ne reçoit que les permissions strictement nécessaires a sa fonction. Pas plus, pas moins. Un service de catalogue n'a pas besoin d'écrire dans la base de données de commandes. Un job batch n'a pas besoin d'un token admin permanent.
En pratique :
- Les tokens ont une durée de vie courte et des scopes limites
- Les service accounts ont des rôles spécifiques, jamais "admin"
- Les accès élevés sont obtenus par elevation temporaire (just-in-time), pas maintenus en permanence
- Les permissions sont revoquees des qu'elles ne sont plus nécessaires
| Violation courante | Application du principe |
|---|---|
| Service avec accès admin à la DB | Accès limite aux tables et opérations requises |
| Token API sans expiration | Token avec TTL court + rotation automatique |
| Compte de service partage | Un compte par service avec permissions ciblees |
| Pod Kubernetes en mode privileged | Capabilities reduites au minimum nécessaire |
Defense en profondeur¶
Aucune mesure de sécurité n'est infaillible. La defense en profondeur empile des couches de protection indépendantes. Si une couche est contournee, la suivante prend le relais. Ce principe est développé en détail dans Defense en profondeur.
Fail secure¶
Quand un composant échoué, il doit échouer dans un état sécurisé. Une erreur d'authentification doit refuser l'accès, pas l'accorder. Un service qui perd la connexion a son système d'autorisation doit refuser toutes les requêtes, pas les laisser passer.
# Fail open (dangereux)
def authorize(request):
try:
return auth_service.check(request)
except ConnectionError:
return True # Si le service d'auth est down, on laisse passer
# Fail secure (correct)
def authorize(request):
try:
return auth_service.check(request)
except ConnectionError:
return False # Si le service d'auth est down, on refuse
Le fail secure s'applique a tous les niveaux :
- Firewall — en cas de panne, bloquer tout le trafic plutôt que tout laisser passer
- Admission controller — si la vérification de signature échoué, refuser le déploiement
- Circuit breaker — quand le service d'autorisation est down, refuser les requêtes
Séparation des responsabilités¶
Les fonctions critiques doivent être réparties entre plusieurs composants ou acteurs pour éviter qu'un seul point de compromission ne donne accès à tout. On ne confie pas la génération des certificats, leur distribution et leur revocation au même composant.
En architecture :
- Le service qui généré les tokens n'est pas le même qui les valide
- Le pipeline CI qui construit les artefacts est distinct de celui qui les deploie
- Les logs d'audit sont envoyes a un système externe que les services ne peuvent pas modifier
- Les secrets sont gérés par un vault dédié, pas stockes dans la configuration
Mediation complète¶
Chaque accès a une ressource doit passer par un point de contrôle. Il ne doit pas exister de chemin qui contourne l'autorisation. En architecture, cela signifie :
- Pas d'accès direct à la base de données depuis un client externe
- Pas de shortcut réseau qui contourne l'API Gateway
- Pas de service interne accessible sans passer par le mesh ou le proxy
- Les accès administratifs passent par un bastion ou un jump host, jamais en direct
La mediation complète est souvent violee par des chemins "de debug" ou "temporaires" qui deviennent permanents. Un port de base de données ouvert "le temps du dev" qui reste ouvert en production est un classique. L'audit régulier des chemins d'accès — ports ouverts, routes réseau, règles de pare-feu — est indispensable pour maintenir la mediation complète dans le temps.
Réduction de la surface d'attaque¶
Chaque endpoint expose, chaque port ouvert, chaque dépendance ajoutee augmente la surface d'attaque. Le principe est de minimiser ce qui est expose.
| Surface | Réduction |
|---|---|
| Ports réseau | Fermer tout, ouvrir uniquement le nécessaire |
| APIs publiques | Exposer le minimum, authentifier le reste |
| Dépendances | Auditer, limiter, mettre à jour régulièrement |
| Images Docker | Base minimale (distroless, Alpine), pas de shell |
| Endpoints de debug | Jamais en production (pprof, actuator sans protection) |
| Metadata cloud | Bloquer l'accès IMDS depuis les containers |
Architecture de sécurité — vue d'ensemble¶
Les concepts de ce chapitre — analyse de risques, zero trust, defense en profondeur, mTLS, supply chain — se combinent. Ils ne sont pas des options indépendantes a activer séparément, mais des couches d'un même modèle de sécurité système cohérent.
graph TD
EBIOS["Analyse de risques\nEBIOS / STRIDE"] --identifie--> MENACES["Menaces prioritaires"]
MENACES --guide--> ZT["Zero trust\nAuthentification, autorisation"]
MENACES --guide--> DD["Defense en profondeur\nCouches, zones, segmentation"]
MENACES --guide--> SC["Supply chain\nSignature, verification"]
ZT --implemente--> MTLS["mTLS\nIdentite cryptographique"]
DD --implemente--> SEG["Segmentation\nNetwork policies, WAF"]
SC --implemente--> SBOM["SBOM + cosign\nVerification au deploiement"] L'analyse de risques guide les décisions de segmentation. Le zero trust orienté l'authentification entre services. Le mTLS implémenté l'identité de workload. La defense en profondeur couvre les cas où une couche est contournee. La supply chain security garantit que les artefacts déployés sont intégrés.
Sécurité architecturale dans le cycle de vie¶
La sécurité n'est pas une phase du projet — c'est une preoccupation transversale présenté à chaque étape.
| Phase | Activité sécurité |
|---|---|
| Cadrage | Analyse de risques EBIOS, classification des données |
| Conception | Threat modeling STRIDE, choix de segmentation |
| Développement | SAST, gestion des secrets, revue de code orientée secu |
| Intégration | DAST, scan de dépendances, génération SBOM |
| Déploiement | Signature des artefacts, admission control, mTLS |
| Production | Monitoring sécurité, détection d'anomalies, rotation |
| Évolution | Re-évaluation des menaces à chaque changement majeur |
Warning
La sécurité architecturale traitee ici ne remplacé pas la sécurité applicative — les deux sont nécessaires. Un système sécurisé au niveau architectural mais avec des injections SQL dans chaque service reste vulnerable.
Compliance et référentiels¶
Les décisions de sécurité architecturale s'inscrivent souvent dans un cadre reglementaire ou normatif. Les référentiels les plus courants :
| Référentiel | Portee | Lien avec l'architecture |
|---|---|---|
| ISO 27001/27002 | Système de management de la sécurité | Contrôles techniques et organisationnels |
| ISO 27005 | Gestion des risques de sécurité | Méthodologie d'analyse de risques |
| EBIOS RM | Analyse de risques (ANSSI) | Ateliers structures, scenarios d'attaque |
| RGPD | Protection des données personnelles | Chiffrement, pseudonymisation, audit |
| SOC 2 | Contrôles de sécurité pour les SaaS | Logging, accès, chiffrement, disponibilité |
| PCI DSS | Données de paiement | Segmentation réseau, chiffrement, audit |
Ces référentiels ne dictent pas l'architecture — ils définissent des exigences auxquelles l'architecture doit répondre. L'analyse de risques (EBIOS, chapitre suivant) est le pont entre les exigences reglementaires et les décisions techniques.
Modèle de menace vs modèle de confiance¶
Deux concepts fondamentaux structurent la réflexion sécurité au niveau architectural.
Modèle de menace¶
Le modèle de menace décrit qui pourrait attaquer le système, avec quels moyens, et quels objectifs. Il est formalisé par des méthodes comme EBIOS (niveau organisationnel) ou STRIDE (niveau technique). Sans modèle de menace, on ne sait pas contre quoi on se protégé — et on finit par déployer des mesures coûteuses contre des menaces improbables tout en negligeant les menaces réelles.
Le modèle de menace répond aux questions :
- Qui sont les attaquants potentiels ? (etatique, criminel, insider, opportuniste)
- De quelles ressources disposent-ils ? (temps, budget, compétences)
- Quels sont leurs objectifs ? (vol de données, sabotage, rancon, espionnage)
- Quels vecteurs d'entree peuvent-ils exploiter ? (réseau, supply chain, social engineering)
Modèle de confiance¶
Le modèle de confiance définit les hypothèses de confiance entre les composants du système. Dans un modèle périmètre, on fait confiance à tout ce qui est dans le réseau interne. Dans un modèle zero trust, on ne fait confiance a rien par défaut.
Le modèle de confiance répond aux questions :
- Quels composants se font mutuellement confiance ?
- Sur quels mécanismes cette confiance repose-t-elle ? (certificat, token, position réseau)
- Que se passe-t-il si un composant de confiance est compromis ?
- Les hypothèses de confiance sont-elles documentees et revisitees ?
graph TD
subgraph "Modele perimetre"
FW[Pare-feu] --text--> ZONE["Zone interne\nConfiance implicite"]
ZONE --> SA[Service A]
ZONE --> SB[Service B]
SA --text--> SB
end
subgraph "Zero trust"
GW[Gateway] --text--> SA2[Service A]
SA2 --text--> SB2[Service B]
SB2 --text--> DB2[(Database)]
end La combinaison modèle de menace + modèle de confiance fonde toutes les décisions de sécurité architecturale. Le modèle de menace dit contre quoi on se protégé. Le modèle de confiance dit sur quoi on s'appuie. Les deux doivent être explicites et documentes.
Anti-patterns de sécurité architecturale¶
Les erreurs les plus courantes en sécurité architecturale ne viennent pas de vulnérabilités exotiques mais de décisions de conception classiques.
| Anti-pattern | Pourquoi c'est un problème | Alternative |
|---|---|---|
| Sécurité par l'obscurite | Compter sur le secret de l'implémentation | Mécanismes cryptographiques verifiables |
| Single point of failure sécurité | Un seul composant protégé tout | Defense en profondeur, couches indépendantes |
| Confiance implicite réseau | "C'est interne, donc c'est sur" | mTLS, zero trust, vérification à chaque requête |
| Secrets dans le code / la config | Rotation impossible, exposition dans les logs | Vault, secret manager, injection au runtime |
| Logs sans protection | Un attaquant efface ses traces | Logs immutables, envoi en temps réel vers un SIEM |
| Authentification sans autorisation | On sait qui est l'appelant, pas ce qu'il peut faire | RBAC/ABAC systematique à chaque endpoint |
| Permissions permanentes élevées | Surface d'attaque maximale en permanence | Just-in-time access, elevation temporaire |
Note
Documenter explicitement le modèle de menace et le modèle de confiance est aussi important que les implémenter. Un modèle implicite est un modèle que personne ne remet en question — et qui dérivé avec le temps.
Chapitre suivant : EBIOS Risk Manager — l'analyse de risques organisationnelle en 5 ateliers, méthode de référence de l'ANSSI.