Dans notre article précédent sur CI/CD Pipelines, nous avons vu comment pirater un CI/CD scénario qui probablement était protégé.
Rappelons notre point du post précédent : nous avons commencé avec quelques pipeline qui était vulnérable à Empoisonné indirect Pipeline Internationaux (I-PPE) et, pour y remédier, nous avons décidé de diviser le pipeline Entre deux:
- Le 1st pipeline (Build CI), sans danger pour D-PPE et I-PPE, extrairait le code PR, réaliserait la construction et générerait un artefact
- Le 2nd pipeline (Test CI), également sans danger pour D-PPE et I-PPE, extrairait le code de base (pour éviter la modification du script shell) et exécuterait les scripts originaux sur l'artefact.
- Pour synchroniser le CI de test pipeline à exécuter APRÈS le Build CI pipeline, Nous avons utilisé workflow_run déclencheur.
Nous avons nommé cela le scénario n°3.
Bien que, comme nous l’avons mentionné dans cet article, il existe d’autres solutions, nous avons décidé de mettre en œuvre cette « solution » pour des raisons pédagogiques, afin de pouvoir approfondir les vulnérabilités de CI/CD pipelines.
Par la suite, nous avons vu comment pirater ce scénario en empoisonner l'artefact. C'est ce qu'on appelle Empoisonnement par des artefacts, c'est-à-dire la possibilité de modifier (pirater) le pipeline logique en modifiant un pipeline artefact.
Quel est le problème avec cette approche ? Nous avons vu que le problème se pose lorsqu'un utilisateur « crée » un nouveau pipeline.
Si un utilisateur ouvre un PR contenant un nouveau pipeline, GitHub exécutera cela pipeline (sous certaines conditions, comme nous l'avons vu dans la poste).
L'utilisateur peut alors créer un nouveau pipeline avec le même nom que Build CI !! Oui, c'est surprenant, mais GitHub permet de créer deux pipelinec'est du même nom !!
Lorsque l'utilisateur ouvre un PR avec ces modifications, le nouveau" pipeline sera exécuté (téléchargement d'un artefact empoisonné) et le CI de déploiement pipeline sera exécuté après cela, ce qui entraînera le script shell « modifié » écrasant le script shell « original » situé dans le pipeline espace de travail. Ainsi, cette « solution » n’évite pas la vulnérabilité I-PPE (comme on peut le voir ci-dessous)
Quels sont les problèmes? Il y a au moins quelques problèmes :
- Tout d'abord, comment être sûr que le processus de construction n'a pas été altéré ? Dans ce scénario, l'utilisateur malveillant a pu modifier le processus de génération prévu en utilisant son pipeline pour créer un artefact empoisonné.
- D'autre part, comment pouvons-nous évaluer la provenance d’un artefact ?
Ces questions nous jettent dans les bras du Attestations de logiciels domaine!!
Attestations de logiciels
An attestation est un morceau de données, représentation preuve d'un événement. Dans le monde réel, nous les appelons généralement certifications.
Par exemple, lorsqu'un laboratoire analyse votre sang, les données relatives au test sont enregistrées et certifiées. Les résultats des analyses de sang sont vérifiable et traçable.
Plus proche de notre domaine informatique, on pourrait deviner ce que serait une traduction de ce processus en, par exemple, un processus de compilation.
Les informations sur l'environnement et les outils du serveur de compilation, les matériaux (le code source) et les produits/artefacts (le code binaire) feraient partie de cette attestation.
Évidemment, l'attestation doit être générée par un certificateur autorisé (authentifié et non répudiable) pour assurer sa crédibilité.
Il est probable que certains d'entre vous se demandent... et quel est le problème ? différence entre signatures et attestations?
Signatures de code et attestations
À un niveau élevé, un Signature est créé à l’aide d’une paire de clés et d’un artefact. La paire de clés est constituée d'une clé publique et d'une clé privée.
L'utilisateur signe un artefact à l'aide de la clé privée, et d'autres peuvent ensuite vérifier la signature à l'aide de la clé publique. La clé privée doit rester secrète, mais la clé publique est largement diffusée.
Les signatures peuvent être utilisées prouver que le détenteur de la clé privée a utilisé la clé privée pour signer l'artefact.
Signatures ne prouve pas
- Les utilisateurs intention pour signer l'artefact (ils ont peut-être été trompés), ou
- L'intention de l'utilisateur de faire tout revendication spécifique concernant l'artefact
Avec Les attestations, plutôt que de signer directement un artefact, les utilisateurs créent une sorte de document qui capture leur intention derrière la signature de l'artefact et de tout revendications particulières étant faite dans le cadre de cette signature.
Cadre d'attestation intégré
Le cadre le plus courant est le Cadre d'attestation intégré
- définit une standard format des attestations qui lient les sujets, les artefacts décrits, à des métadonnées authentifiées sur l'artefact
- fournit un ensemble de prédicats prédéfinis pour communiquer des métadonnées authentifiées tout au long et à travers les chaînes d'approvisionnement logicielles
Entrons dans les détails du format de l'attestation.
An Attestation est une document signé numériquement qui contient Déclarations.
Le Déclaration est la couche intermédiaire de l'attestation, la liant à un domaine particulier Sujet et identifier sans ambiguïté les types de Prédicat:
- Sujet: à référence cryptographiquement sécurisée à l'artefact (généralement via un hachage), et
- Prédicats: un ensemble de spécificités prétentions à propos de cet artefact est appelé une déclaration. Ces affirmations peuvent être utilisées pour exprimer (et prouver plus tard) tout ce à quoi vous pouvez penser ! Ils peuvent représenter une approbation manuelle, la provenance d’un artefact, des résultats de tests automatisés, une piste d’audit, ou plus encore !
Lorsque cette déclaration est signée cryptographiquement, elle est alors appelée une Attestation
De cette façon, à titre d'exemple, Alice crée une déclaration sur un artefact et la signe à l'aide de sa clé privée, créant ainsi une attestation.
- Bob peut alors vérifier la signature dans cette attestation, lui permettant faire confiance aux affirmations à l'intérieur.
Bob peut alors utiliser ces revendications decider s'il faut ou non autoriser l'utilisation de cet artefact.
Les attestations pourraient-elles aider à résoudre l’empoisonnement par artefact ?
Après cette introduction aux Attestations, revenons à notre problématique. Comment les attestations peuvent-elles nous aider à résoudre notre problème, c'est-à-dire à éviter l'empoisonnement des artefacts ?
L'utilisateur malveillant a pu créer un artefact en contournant le mécanisme « officiel », c'est à dire en utilisant son pipeline pour générer l'artefact.
Ce serait étonnant si nous pouvions prouver que les artefacts téléchargés ont été construits avec le logiciel officiel. pipelines. Ceci n’est qu’un exemple de ce que l’on pourrait appeler des « points de falsification », mais il pourrait y en avoir bien d’autres.
Comme vous pouvez le voir sur la photo ci-dessus, les points de falsification sont multiples. De cette façon, le consommateur pipeline (Test CI dans notre exemple) doit évaluer la intégrité du processus de construction la intégrité de l'artefact lui-même.
Dans notre exemple, l'artefact empoisonné a été créé en introduisant un nouveau (empoisonné) pipeline qui altère le processus de construction. Mais l’utilisateur malveillant aurait pu :
- modifier le code après l'avoir extrait du SCM pour générer un binaire malveillant
- remplacer le bon binaire produit par la compilation par tout autre binaire malveillant
- compromettre le registre des artefacts et télécharger un artefact empoisonné construit de toute autre manière
- et ainsi de suite
Comme vous pouvez le constater, il peut y avoir plusieurs points de « falsification ».
Qu’est-ce qui est important ici ? Évidemment pour protéger tous ces points de « falsification ». Mais en fin de compte, ce qui est le plus important, c'est que le « consommateur » de l’artefact peut évaluer l’intégrité de l’artefact et décider d’aller de l’avant ou non.
Nous pouvons évaluer l'intégrité d'un artefact de deux façons.
La première consiste à évaluer provenance de l'artefact.
En générant un Attestation de provenance, nous fournissons des métadonnées utiles (correctement authentifiées et non répudiées) sur l'artefact. Dans les exemples suivants, nous utiliserons SEL Xygeni (Software Attestations Layer for Trust), le composant permettant de générer, d'enregistrer et de vérifier les attestations logicielles.
- name: Building ...
run: |
# mvn will compile and create target/MyApp.war
mvn clean package
- name: Generating provenance
run: |
#!/usr/bin/env bash
shopt -s expand_aliases
alias salt=$PWD/salt_pro/xygeni_salt/salt
echo " "
echo "-----------"
echo "Generating Provenance with CLI ..."
salt at slsa \
--basedir ${GITHUB_WORKSPACE}/target \
--key="${PRIVATE_KEY}" \
--public-key=${GITHUB_WORKSPACE}/Test1_public.pem \
--key-password=${KEY_PASSWD} \
--output-unsigned=${GITHUB_WORKSPACE}/cli_provenance_${PIPELINE}_unsigned.json \
--pipeline ${PIPELINE} --pretty-print \
--file ./MyApp.war
Dans le code ci-dessus, vous pouvez voir qu'il y a une étape qui construit le fichier war et une deuxième étape qui génère le fichier war. Attestation de provenance. Pour ce faire, le pipeline utilise la clé privée et inclut également la clé publique dans l'attestation.
Dans les coulisses, Xygeni de sel La commande stocke l'attestation dans un grand livre (c'est-à-dire un registre d'attestation, record dans notre cas mais vous pouvez en utiliser un autre). Cela fait, le consommateur pipeline peut inclure Xygeni Moteur de vérification pour vérifier la provenance de l’artefact et évaluer l’intégrité de l’artefact.
- name: 'Verifying the attestation'
run: |
#!/usr/bin/bash
echo " "
echo "-------"
# Calculate sha256sum for the artifact
SHA_SUM=$(sha256sum ./MyApp.war | cut -f1 -d ' ')
# Recover the attestation Id from the sha256sum
ATT_ID=$(echo $(salt -q registry search --digest sha256:$SHA_SUM --format json) | jq -r .[-1].gitoidSha256)
echo " "
echo "-------"
# Download the provenance attestation
echo "Downloading the provenance attestation ..."
salt -q reg get --id=$ATT_ID --format=json > ${GITHUB_WORKSPACE}/provenance_kk.signed.json
echo " "
echo "-------"
echo "Verifying provenance ..."
salt verify \
--basedir ${GITHUB_WORKSPACE} \
--attestation=${GITHUB_WORKSPACE}/provenance_kk.signed.json \
--public-key=${GITHUB_WORKSPACE}/Test1_public.pem \
--file ./MyApp.war
Le processus de vérification évalue :
- Le l'artefact sha256sum est valide (c'est-à-dire qu'il y a une attestation sur ce « sujet »), et
- Le l'attestation est correctement authentifiée (il a été généré en utilisant la clé privée adéquate)
Ce processus de vérification peut alors évaluer que l'artefact et l'attestation sont valides.
Mais comme vous vous en souvenez, dans notre cas, l’artefact a été généré par un logiciel « malveillant ». pipeline (c'est-à-dire pas l'original par un modifié pipeline). Ensuite, nous devons aller de l'avant et vérifier un autre aspect : celui l’artefact a été généré par « l’original » pipeline, pas n'importe quel autre.
Pour ce faire, incluez simplement une ligne simple pour vérifier cette condition, par exemple :
echo " "
echo "-------"
# Download the provenance attestation
echo "Downloading the provenance attestation ..."
salt -q reg get --id=$ATT_ID --format=json > ${GITHUB_WORKSPACE}/provenance_kk.signed.json
WFR=$(jq -r .payload ${GITHUB_WORKSPACE}/provenance_kk.signed.json |base64 -d | jq -r .predicate.buildDefinition.internalParameters.environment.GITHUB_WORKFLOW_REF)
echo $WFR | grep cicd_top10_3_salt\/.github\/workflows\/build.yml
Cette vérification supplémentaire échouera si l'artefact n'a pas été généré par notre « coffre-fort » pipeline.
Si l'artefact a été généré par notre original pipeline (cicd_top10_3_salt/.github/workflows/build.yml), la commande grep réussira, sinon elle échouera, brisant le pipeline et abandonner toute autre étape.
Le constructeur" pipeline n'est qu'un point de falsification à vérifier mais, comme mentionné précédemment, il y a d'autres points de falsification que nous devrions vérifier.
Par exemple, Que se passe-t-il si le code source a été falsifié après l'extraction du dépôt et avant la commande build ? Dans ce cas, le code à construire n'est pas le même que celui stocké dans le SCM.
Vérifier ce point de falsification est aussi simple que de vérifier les hachages du matériel à chaque étape.
SHA_ATT_MATERIAL=$(jq -r .payload ${GITHUB_WORKSPACE}/provenance_kk.signed.json | base64 -d | jq -r .predicate.attestations[0].predicate.materials[].digest[])
SHA_STEP_MATERIAL=$(jq -r .payload ${GITHUB_WORKSPACE}/provenance_kk.signed.json | base64 -d | jq -r .predicate.attestations[3].predicate.materials[0].digest[])
Conclusions
En résumé, un Attestation de logiciel est une assertion faite à propos d'un morceau de logiciel, c'est-à-dire une déclaration authentifiée (métadonnées) sur un artefact logiciel ou une collection d'artefacts logiciels.
Les attestations logicielles sont une généralisation de la signature brute d’artefacts/codes. L'attestation est un document signé (dans un format donné, généralement basé sur JSON) qui associe des métadonnées à un artefact. Ils représentent des preuves reliant les entrées (matériaux) et les sorties (artefacts produits) à chaque étape de construction.
Les attestations fournissent un enregistrement vérifiable des étapes effectuées pour créer les artefacts logiciels finaux, y compris les éléments d'entrée pour chaque étape et l'exécution des commandes de construction.
En conclusion, les attestations logicielles constituent un excellent mécanisme pour vérifier de nombreux aspects d’intégrité de notre processus de construction.
Vous avez fini la série ? Ne t'inquiète pas! N'hésitez pas à revenir à 'Empoisonné Pipeline Exécution (EPI)' ou tout autre post qui suscite à nouveau votre intérêt !
Restez à l'écoute, nous allons approfondir les attestations de logiciels et build security dans d'autres articles de blog.





