[FR] Aide-mémoire DevSecOps : Livraison Continue
Cet aide-mémoire synthétise les principaux contrôles de sécurité à effectuer dans le cadre d’un process de livraison continue: depuis la phase de planning jusqu’à la livraison du build final. J’ai le point de vue d’un consultant GRC qui intervient uniquement dans la phase de planning et donc je suis intéressé par des retours d’ingénieurs DevOps ou de spécialistes du DevSecOps.
Planning
La phase de Planning consiste à définir les spécifications, élaborer le planning, organiser les tâches… Pour repartir et structurer le travail durant les sprints, les spécifications sont subdivisées en Epic, User Stories et Tâches, qui seront suivies et gérées dans un outil de gestion de projets SRUM ou Kanban (comme JIRA ou Trello). De plus, des critères d'acceptation sont définis pour chaque User Story, permettant de savoir exactement ce qui doit être réalisé et comment mesurer la réussite d’une tâche.
La philosophie du DevSecOps consiste à « shift left » la sécurité. Traditionnellement, les contrôles de sécurité sont concentrés sur les phases de test, tandis que le DevSecOps prône une approche « Sécurité By Design » qui intègre la sécurité dès la conception du projet. Cette approche permet à la fois d'améliorer le niveau de sécurité en étant proactif dans la gestion des risques et de gagner du temps en réduisant la dette technique. A cette phase, cela se traduit concrètement par une analyse de risques (EBIOS RM par exemple) qui, avec une approche holistique et itérative, identifie les risques numériques pesant sur le projet. Cette analyse permettra d'établir un plan d'action en priorisant les contrôles nécessaires en fonction des risques.
Cette analyse de risque, qui peut être d'un niveau d'abstraction assez élevé en fonction des méthodes, doit être complétée par une analyse granulaire des modes opératoires que pourraient employer les attaquants pour nuire au système. Ces modes opératoires permettent d'aboutir à des contre-mesures précises. L'atelier 4 d'EBIOS RM peut servir de méthode de modélisation de la menace, mais d'autres méthodes existent, telles que PASTA et OWASP Threat Modeling. Si des données à caractère personnel sont présentes, une analyse de conformité RGPD (par exemple AIPD) peut être nécessaire.
Les mesures identifiées dans l'analyse de risque et la modélisation de la menace, ainsi que les exigences réglementaires, doivent ensuite être traduites dans le backlog de tâches du projet. Pour ce faire, une approche possible est de créer des « Security Stories » en se basant sur des exemples comme Safecode Security Stories ou OWASP User Security Stories and Acceptance Criteria.
Enfin, la formation est la clé de voûte de la sécurisation du DevSecOps : c'est l'ultime moyen de « shift left » la sécurité en créant une culture de la sécurité qui imprègne les différentes parties prenantes, de l'architecte aux développeurs en passant par le chef de projet. **Même dans un pipeline CI/CD automatisé, le facteur humain reste le plus important. **
Code
La phase de Code est celle où les User Stories sont mises en œuvre sous forme de code source par les développeurs. Il peut s’agir de code applicatif, mais aussi de fichiers de configuration Infra as Code par exemple. Le code source est ensuite commit dans un dépôt de code source (GitHub par exemple).
Il est recommandé de suivre des standards de développement sécurisé pour éviter les vulnérabilités dès la conception (se prémunir des buffer overflow par exemple). Des plugins peuvent être intégrés dans les environnements de développement (IDE) tels que SonarLint (outil de SAST) pour détecter les vulnérabilités et fournir une aide à la décision en temps réel. Une fois de plus, la philosophie est de « décaler vers la gauche » (shift left) la sécurité et d'éviter d'accumuler de la dette technique avant même de commit le code.
Il est aussi utile de mettre en place des pré-commit hook avec des outils tels que git-secrets, qui permettent d'éviter de commit du code contenant des informations sensibles (mots de passe, clés d'API, etc.). En effet, il peut être extrêmement gênant de ne s'en rendre compte qu'après le commit...
Le commit lui-même doit être signé pour s'assurer de l'identité de l'auteur et prévenir une atteinte à l'intégrité du code. La protection de la chaîne d'approvisionnement logicielle est un sujet complexe qui ne se limite pas à simplement signer les commits, et je vous encourage vivement à consulter le framework SLSA qui a été proposé par Google.
SLSA Résumé des menaces sur la supply chain
Source: https://slsa.dev/
Une attention particulière doit être portée à la sécurité du dépôt Git, notamment en ce qui concerne la gestion des droits (qui doivent d'ailleurs être revus régulièrement) et l'authentification.
Enfin, une revue de code peut être organisée et, selon le niveau de maturité, peut s'inspirer du Guide de Revue de code OWASP pour aller en profondeur sur les sujets de sécurité.
Build
Le Build est la phase qui va comprendre l’automatisation (avec Jenkins par exemple) de la compilation, de l’analyse statique, des tests unitaires et du packaging. L’artefact généré diffère en fonction du contexte: un APK pour du dev mobile, un .exe, une image de container… Ce dernier est alors stocké dans un gestionnaire d’artefact comme jFrog Artifactory.
L'analyse statique du code (Static Application Security Testing ou SAST) consiste en l’examen du code source non compilé (« statique ») par des outils automatisés à la recherche d’erreurs et de vulnérabilités. C’est une étape essentielle et constitue autant un enjeu qualité que sécurité. Des outils, d’ailleurs autrefois traditionnellement orientés vers la qualité (SonarQube), développent de plus en plus de fonctionnalités en matière de sécurité et assurent un double emploi.
L'analyse des dépendances (Software Composition Analysis ou SCA) avec des outils tels qu’OWASP Dependency Check permet de détecter les bibliothèques et composants tiers vulnérables. En ce qui concerne les composants tiers, il est crucial de s’assurer de la fiabilité des librairies choisies que ce soit en termes de sécurité que d’obsolescence. Quelques critères peuvent être la réputation des développeurs, la documentation, la présence d’un canal pour remonter la détection d’une vulnérabilité, l’historique des vulnérabilités et la réaction de l’équipe…
Source: https://imgs.xkcd.com/comics/dependency.png
J’en profite pour rappeler l’importance de l’établissement d’un SBOM (Software Bill Of Material = nomenclature logicielle) qui va lister tous les composants utilisés par le projet et les informations associées (version, checksum…). C’est la première étape pour sécuriser la supply chain (voir SLSA).
Cette analyse des dépendances est importante à ce stade, mais il est également utile de procéder à une vérification supplémentaire et d'analyser les binaires/images à la recherche de composants vulnérables après compilation et packaging, car des composants peuvent s'ajouter de manière non standard et rester indétectés par une simple analyse du manifeste.
Une attention particulière doit être portée aux images de conteneurs. Ces dernières doivent être minimalistes dans les packages et dépendances pour réduire la surface d'attaque (pas de shell, par exemple). Tous les composants et dépendances logiciels, ainsi que leurs versions, doivent être systématiquement tracés dans le SBOM. De plus, les images de base des conteneurs doivent être obtenues à partir de sources fiables et une vérification de l’intégrité par checksum doit être effectuée.
De la même manière que le code, les fichiers de configuration Infrastructure as Code (IaC) doivent être analysés par des outils automatisés pour détecter les vulnérabilités.
Écrire des secrets en dur dans le code est à proscrire, pour s'en prémunir, des outils tels que le Vault HashiCorp sont indispensables pour stocker les secrets de manière sécurisée et mettre en oeuvre des secrets dynamiques. De plus, même si des pré-commit hook de détection des secrets ont été mis en place en amont, il est aussi indispensable d'avoir des scans de détection des secrets, car un développeur pourrait passer outre les pré-commit hook. Certains de ces outils, comme detect-secret , permettent un suivi, ce qui est extrêmement utile dans la gestion des faux positifs (anciens secrets présents dans l'historique de commit, par exemple). Ces scans de détection de secrets doivent être réalisés sur le dépôt Git, mais aussi, idéalement, en fin de processus sur l'artefact produit (image de conteneur, par exemple) avec un scanner comme Trivy pour trouver des secrets qui se seraient glissés dans l’image entre temps.
Test
Cette phase comprend le déploiement dans un environnement de test et la réalisation des différents types de tests (intégration, fonctionnels…) pour s’assurer de la conformité aux spécifications et aux exigences de sécurité et de qualité.
La phase de test est particulièrement intéressante pour les contrôles de sécurité, car elle permet de détecter les vulnérabilités qui ne sont détectables que lorsque l'application est en cours d'exécution (faiblesses dans l’authentification ou la validation d’input par exemple). Les outils d'analyse dynamique (DAST) tels qu’OWASP ZAP permettent d'effectuer ce genre de test en prenant un point de vue extérieur (type boîte noire), sans vision sur le code source de l'application. Ces outils de DAST peuvent être automatisés dans une certaine mesure avec des projets comme BDD-Security ou Gauntlt.
Les outils d'analyse interactive (IAST) adoptent une approche différente, car ils vont opérer des tests tout en ayant une vision sur le code source et le comportement de l’application en exécution. L'avantage par rapport au DAST est une plus grande facilité d'automatisation et un feedback direct sur l'origine de la vulnérabilité.
Pour une description plus détaillée des différents tests possibles à ce stade, je recommande ces excellentes slides du MITRE.
Si l'environnement de test est iso-prod (ou bien qu’on est en pré-prod), il est possible d'examiner la sécurité de l'infrastructure dès la phase de test à l'aide de scanners de vulnérabilités tels que Nessus. L'environnement de test ne doit idéalement pas contenir de données réelles ou bien complètement anonymisées pour éviter des fuites de données ou des non-conformités réglementaires (RGPD). De plus, l’environnement de test doit être isolé de l'environnement de production, maîtrisé et durci.
Release
La phase de release correspond au moment où le livrable final est prêt à être déployé sur l’environnement de production. Ce dernier est stocké dans un gestionnaire d’artefacts.
Les livrables finaux doivent être cryptographiquement signés pour permettre un contrôle d'intégrité avant le déploiement en production. Des outils comme cosign peuvent être utilisés. Encore une fois, la protection de la chaîne d'approvisionnement logicielle est un sujet complexe et je vous invite à consulter le Framework Supply-Chain Levels for Software Artifacts.
Des scans continus des images et artefacts doivent être organisés pour détecter les vulnérabilités qui ne manqueront pas d'apparaître entre les builds.