In ons vorige bericht over CI/CD Pipelines, we zagen hoe je een CI/CD scenario dat vermoedelijk werd beschermd.
Laten we ons punt uit het vorige bericht onthouden: we zijn met een paar begonnen pipeline waarvoor kwetsbaar was Indirect vergiftigd Pipeline Uitvoering (I-PPE) en om het probleem op te lossen, hebben we besloten de pipeline in twee:
- de 1st pipeline (Build CI), veilig voor D-PPE en I-PPE, zou de PR-code afrekenen, de build maken en een artefact genereren
- De 2nd pipeline (Test CI), ook veilig voor D-PPE en I-PPE, zou de basiscode uitchecken (om wijziging van het shell-script te voorkomen) en de originele scripts op het artefact uitvoeren.
- Om het TestCI te synchroniseren pipeline om NA het Build CI uit te voeren pipeline, we gebruikten workflow_run aansteken, veroorzaken.
We noemden dit scenario #3.
Hoewel er, zoals we in dat bericht al aangaven, andere oplossingen zijn, hebben we besloten deze “oplossing” om pedagogische redenen te implementeren, zodat we dieper kunnen ingaan op de kwetsbaarheden van CI/CD pipelines.
Daarna zagen we hoe we dit scenario konden hacken het artefact vergiftigen. Dit is wat wij noemen Artefactvergiftiging, dat wil zeggen de mogelijkheid om het pipeline logica door het wijzigen van a pipeline artefact.
Wat is het probleem met deze aanpak? We hebben gezien dat het probleem zich voordoet wanneer een gebruiker een nieuwe ‘creëert’ pipeline.
Als een gebruiker een PR opent met daarin een nieuwe pipeline, GitHub zal dat uitvoeren pipeline (onder bepaalde voorwaarden, zoals we zagen bij de post).
De gebruiker kan dan een nieuw aanmaken pipeline met dezelfde naam als Build CI !! Ja, het is verrassend, maar met GitHub kun je er twee maken pipelines met dezelfde naam!!
Wanneer de gebruiker een PR opent met deze wijzigingen, de nieuwe" pipeline zal worden uitgevoerd (een vergiftigd artefact uploaden) en het implementatie-CI pipeline wordt daarna uitgevoerd, wat ertoe leidt dat het “gewijzigde” shellscript het “originele” shellscript in het pipeline werkruimte. Deze “oplossing” vermijdt dus niet de I-PPE-kwetsbaarheid (zoals we hieronder kunnen zien)
Wat zijn de problemen? Er zijn tenminste een paar problemen:
- Eerste, Hoe weet je zeker dat er niet met het bouwproces is geknoeid? In dit scenario heeft de kwaadwillende gebruiker het beoogde bouwproces kunnen wijzigen met behulp van hun pipeline om een vergiftigd artefact te creëren.
- Tweede Hoe kunnen we de herkomst van een artefact beoordelen?
Deze vragen werpen ons in de armen van de Softwareattesten domein!!
Softwareattesten
An getuigenis is een stuk van gegevens vertegenwoordigen bewijs van een gebeurtenis. In de echte wereld noemen we dit meestal certificeringen.
Wanneer een laboratorium bijvoorbeeld uw bloed test, worden gegevens over de test geregistreerd en gecertificeerd. De uitslag van het bloedonderzoek is te verifiëren en traceerbaar.
Dichter bij ons IT-domein kun je raden wat een vertaling van dit proces naar bijvoorbeeld een compilatieproces zou zijn.
Informatie over de compilatieserveromgeving en -tools, de materialen (de broncode) en de producten/artefacten (de binaire code) zouden deel uitmaken van een dergelijke attestering.
Het is duidelijk dat de attest moet worden gegenereerd door een geautoriseerde attestor (geauthenticeerd en niet-weerlegbaar) om geloofwaardigheid te bieden.
Waarschijnlijk denken sommigen van jullie... en wat is de verschil tussen handtekeningen en attesten?
Codehandtekeningen en attesten
Op een hoog niveau, a handtekening wordt gemaakt met behulp van een sleutelpaar en een artefact. Het sleutelpaar bestaat uit een publieke sleutel en een private sleutel.
De gebruiker ondertekent een artefact met behulp van de privésleutel, en anderen kunnen de handtekening vervolgens verifiëren met behulp van de openbare sleutel. De privésleutel moet geheim worden gehouden, maar de publieke sleutel wordt wijd verspreid.
Handtekeningen kunnen worden gebruikt om te bewijzen dat de houder van de privésleutel de privésleutel heeft gebruikt om het artefact te ondertekenen.
handtekeningen bewijs niet
- Die van de gebruiker bedoeling om het artefact te signeren (ze kunnen zijn misleid), of
- De intentie van de gebruiker om er een te maken specifieke bewering over het artefact
Met Attesten, in plaats van een artefact rechtstreeks te ondertekenen, creëren gebruikers een soort document uit die legt hun bedoeling vast achter het ondertekenen van het artefact en eventuele andere specifieke beweringen gemaakt als onderdeel van deze handtekening.
In-toto Attestation-framework
Het meest voorkomende raamwerk is het in-toto Attestation Framework
- definieert een standard formaat voor attestaties die onderwerpen, de artefacten die worden beschreven, binden aan geverifieerde metadata over het artefact
- biedt een set van vooraf gedefinieerde predikaten voor het communiceren van geauthenticeerde metadata binnen en tussen softwaretoeleveringsketens
Laten we wat dieper ingaan op het attestformaat.
An getuigenis is een digitaal ondertekend document dat bevat Verklaringen.
De Statement is de middelste laag van het attest en bindt het aan een bepaald gegeven Onderwerp en het ondubbelzinnig identificeren van de typen Predikaat:
- Onderwerp: The cryptografisch veilige verwijzing naar het artefact (meestal via een hash), en
- predikaten: een reeks specifieke vorderingen over dat artefact wordt een Verklaring genoemd. Deze beweringen kunnen worden gebruikt om alles uit te drukken (en later te bewijzen) wat je maar kunt bedenken! Ze kunnen handmatige goedkeuring, herkomst van artefacten, geautomatiseerde testresultaten, een audittrail of meer vertegenwoordigen!
Wanneer deze Verklaring cryptografisch is ondertekend, wordt er naar verwezen als een getuigenis
Op deze manier maakt Alice bijvoorbeeld een verklaring over een artefact en ondertekent deze met haar privésleutel, waardoor een attest ontstaat.
- Bob kan het dan wel verifieer de handtekening in dat attest, waardoor hij dat toestaat om de beweringen te vertrouwen binnen.
Bob kan die claims vervolgens gebruiken beslissen of dit artefact wel of niet mag worden gebruikt.
Kunnen attesten helpen bij het oplossen van artefactvergiftiging?
Laten we na deze inleiding tot Attestations teruggaan naar ons probleem. Hoe kunnen attestaties ons helpen ons probleem op te lossen, dwz artefactvergiftiging te voorkomen?
De kwaadwillende gebruiker kon een artefact creëren waarbij hij het “officiële” mechanisme omzeilde, dat wil zeggen door zijn/haar eigen mechanisme te gebruiken pipeline om het artefact te genereren.
Het zou verbazingwekkend zijn als we konden bewijzen dat de artefacten die worden gedownload, samen met de ambtenaar zijn gebouwd pipelineS. Dit is slechts één voorbeeld van wat we ‘manipulatiepunten’ zouden kunnen noemen, maar er kunnen er nog veel meer zijn.
Zoals u op de bovenstaande afbeelding kunt zien, zijn er meerdere knoeipunten. Op deze manier de consument pipeline (Test CI in ons voorbeeld) moet de integriteit van het bouwproces alsmede de integriteit van het artefact zelf.
In ons voorbeeld is het vergiftigde artefact gecreëerd door het introduceren van een nieuw (vergiftigd) artefact. pipeline dat knoeit met het bouwproces. Maar de kwaadwillende gebruiker had het volgende kunnen doen:
- de code wijzigen nadat deze is uitgecheckt bij de SCM om een kwaadaardig binair bestand te genereren
- vervang het juiste binaire bestand dat door de compilatie wordt geproduceerd door een ander kwaadaardig binair bestand
- breng het Artefact Registry in gevaar en upload een vergiftigd artefact dat op een andere manier is gebouwd
- enz.
Zoals u kunt zien, kunnen er meerdere ‘manipulatiepunten’ zijn.
Wat is hier belangrijk? Uiteraard om al die “manipulatiepunten” te beschermen. Maar uiteindelijk is dat het allerbelangrijkste dat de ‘consument’ van het artefact de integriteit van het artefact kan beoordelen en kan beslissen of hij ermee doorgaat of niet.
We kunnen de integriteit van een artefact beoordelen op twee manieren.
Eén daarvan is door het beoordelen van de herkomst van het artefact.
Door het genereren van een Herkomst attest, bieden we nuttige metagegevens (op de juiste manier geverifieerd en niet-weerlegd) over het artefact. In de volgende voorbeelden zullen we gebruiken Xygeni-ZOUT (Software Attestations Layer for Trust), de component voor het genereren, registreren en verifiëren van softwareattesten.
- 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
In de bovenstaande code kun je zien dat er een stap is die het oorlogsbestand bouwt en een tweede stap die het Herkomst attest. Om dit te doen, de pipeline gebruikt de privésleutel en neemt ook de publieke sleutel op in het attest.
Achter de schermen, bij Xygeni zout commando slaat het attest op in a kasboek (ook bekend als een attestregister, record in ons geval, maar u kunt ook andere gebruiken). Klaar, de consument pipeline kan Xygeni's omvatten Verificatie-engine om de herkomst van het artefact te verifiëren en de integriteit van het artefact te beoordelen.
- 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
Het verificatieproces beoordeelt:
- De artefact sha256sum is geldig (dwz er is een attestatie over dat “onderwerp”), en
- De attest correct is geverifieerd (deze is gegenereerd met behulp van de juiste privésleutel)
Dit verificatieproces kan vervolgens beoordelen of zowel het artefact als de attest geldig zijn.
Maar zoals u zich herinnert, werd het artefact in ons geval gegenereerd door een ‘kwaadwillige’ pipeline (dat wil zeggen niet het origineel door een gewijzigde pipeline). Dan moeten we doorgaan en een ander aspect controleren: dat het artefact is gegenereerd door het ‘origineel’ pipeline, en geen andere.
Om dat te doen, voegt u gewoon een eenvoudige regel toe om op die voorwaarde te controleren, bijvoorbeeld:
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
Deze extra controle zal mislukken als het artefact niet is gegenereerd door onze “veilige” pipeline.
Als het artefact is gegenereerd door ons origineel pipeline (cicd_top10_3_salt/.github/workflows/build.yml), zal het grep-commando slagen, anders zal het mislukken, waardoor de pipeline en het afbreken van eventuele verdere stappen.
De bouwer" pipeline is slechts één knoeipunt dat we moeten controleren, maar zoals eerder vermeld zijn er nog enkele andere knoeipunten die we moeten controleren.
Bijvoorbeeld wat als er met de broncode is geknoeid na het uitchecken van de repo en vóór het build-commando? In dit geval is de te bouwen code niet dezelfde als die welke in de SCM.
Het controleren van dit knoeipunt is zo eenvoudig dat u bij elke stap de hashes van het materiaal kunt controleren.
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[])
Conclusies
Samenvattend: een Softwareattest is een bewering over een stukje software, dat wil zeggen een geauthenticeerde verklaring (metadata) over een softwareartefact of een verzameling softwareartefacten.
Softwareattesten zijn een generalisatie van onbewerkte artefact-/codeondertekening. Het attest is een ondertekend document (in een bepaald formaat, meestal gebaseerd op JSON) dat metagegevens aan een artefact koppelt. Ze vertegenwoordigen bewijsmateriaal dat input (materialen) en output (geproduceerde artefacten) bij elke bouwstap met elkaar verbindt.
Attesten bieden een verifieerbaar overzicht van de stappen die zijn uitgevoerd voor het bouwen van de uiteindelijke softwareartefacten, inclusief invoermateriaal voor elke stap en de uitgevoerde build-opdrachten.
Kortom, Software Attestations zijn een geweldig mechanisme om veel verschillende integriteitsaspecten van ons bouwproces te controleren.
De serie voltooid? Maak je geen zorgen! Spring gerust terug naar 'vergiftigde Pipeline Uitvoering (PPE)' of een ander bericht dat uw interesse weer wekt!
Blijf op de hoogte, we duiken dieper in software-attestaties en build security in volgende blogberichten.





