W naszym poprzednim poście o CI/CD Pipelines, widzieliśmy jak zhakować CI/CD scenariusz, który prawdopodobnie był chroniony.
Przypomnijmy sobie, o czym mówiliśmy w poprzednim poście: zaczęliśmy od czegoś pipeline który był podatny na Pośrednio zatruty Pipeline Egzekucja (I-PPE) i aby to naprawić, postanowiliśmy rozdzielić pipeline na dwa:
- 1 pipeline (Build CI), bezpieczny dla D-PPE i I-PPE, pobierze kod PR, wykona kompilację i wygeneruje artefakt
- 2nd pipeline (Test CI), również bezpieczny dla D-PPE i I-PPE, pobierze kod bazowy (aby uniknąć modyfikacji skryptu powłoki) i wykona oryginalne skrypty na artefakcie.
- Aby zsynchronizować test CI pipeline uruchomić PO kompilacji CI pipeline, użyliśmy uruchomienie przepływu pracy wyzwalacz.
Nazwaliśmy to Scenariuszem nr 3.

Chociaż, jak wspomnieliśmy w tym poście, istnieją inne rozwiązania, zdecydowaliśmy się wdrożyć to „rozwiązanie” ze względów pedagogicznych, abyśmy mogli głębiej zanurzyć się w podatności CI/CD pipelines.
Później zobaczyliśmy, jak zhakować ten scenariusz, zatrucie artefaktu. To jest to, co nazywamy Zatrucie artefaktem, czyli możliwość modyfikacji (hakowania) pipeline logika poprzez modyfikację pipeline artefakt.
Jaki jest problem z tym podejściem? Widzieliśmy, że problem pojawia się, gdy użytkownik „tworzy” nowy pipeline.
Jeżeli użytkownik otworzy PR zawierający nowy pipelineGitHub to wykona pipeline (biorąc pod uwagę pewne warunki, jak widzieliśmy w poście).
Następnie użytkownik może utworzyć nowy pipeline o tej samej nazwie co Build CI!! Tak, to zaskakujące, ale GitHub pozwala na utworzenie dwóch pipelineo tej samej nazwie!!
Gdy użytkownik otworzy PR z tymi zmianami, Nowa" pipeline zostanie wykonany (przesyłając zatruty artefakt) i wdrożenie CI pipeline zostanie wykonany później, co spowoduje, że „zmodyfikowany” skrypt powłoki nadpisze „oryginalny” skrypt powłoki znajdujący się w pipeline miejsce pracy. Zatem to „rozwiązanie” nie eliminuje podatności na zagrożenia związane z I-PPE (jak widać poniżej)

Jakie są problemy? Przynajmniej kilka:
- Po pierwsze, Jak mieć pewność, że proces kompilacji nie został naruszony? W tym scenariuszu złośliwy użytkownik był w stanie zmodyfikować zamierzony proces kompilacji, korzystając z własnych pipeline aby stworzyć zatruty artefakt.
- Po drugie, Jak możemy ocenić pochodzenie artefaktu?
Te pytania rzucają nas w ramiona Atesty oprogramowania domena!!
Atesty oprogramowania
An zaświadczenie jest kawałkiem dane reprezentowanie dowód zdarzeniaW świecie rzeczywistym zazwyczaj nazywamy je certyfikaty.
Na przykład, gdy laboratorium bada Twoją krew, dane dotyczące badania są rejestrowane i certyfikowane. Wyniki badania krwi są sprawdzalny oraz identyfikowalny.

Bliżej naszej dziedziny IT, można by się domyślić, jak wyglądałoby tłumaczenie tego procesu na przykład na proces kompilacji.

Częścią takiego poświadczenia będą informacje o środowisku serwera kompilacji i narzędziach, materiałach (kodzie źródłowym) i produktach/artefaktach (kodzie binarnym).
Oczywiste jest, że aby poświadczenie było wiarygodne, musi zostać wystawione przez upoważnioną osobę wystawiającą poświadczenie (uwierzytelnioną i niepodważalną).
Prawdopodobnie niektórzy z Was pomyślą sobie... a co to jest? różnica między podpisami a poświadczeniami?
Podpisy i poświadczenia kodu
Na wysokim poziomie, podpis jest tworzony przy użyciu pary kluczy i artefaktu. Para kluczy składa się z klucza publicznego i klucza prywatnego.

Użytkownik podpisuje artefakt kluczem prywatnym, a inni mogą następnie zweryfikować podpis za pomocą klucza publicznego. Klucz prywatny musi być utrzymywany w tajemnicy, ale klucz publiczny jest szeroko rozpowszechniony.
Można używać podpisów aby udowodnić, że posiadacz klucza prywatnego użył klucza prywatnego do podpisania artefaktu.
Podpisy nie udowadniaj
- użytkownika intencja podpisać artefakt (mogli zostać oszukani) lub
- Zamiar użytkownika, aby dokonać jakichkolwiek konkretne twierdzenie dotyczące artefaktu
Z Atestyzamiast podpisywać artefakt bezpośrednio, użytkownicy tworzą pewnego rodzaju dokument że uchwyca ich intencję za podpisaniem artefaktu i wszelkich konkretne roszczenia tworzonych jako część tego podpisu.
Całkowita struktura atestacji
Najbardziej powszechną strukturą jest kompleksowa struktura atestacji
- definiuje standard format zaświadczeń które wiążą podmioty, opisywane artefakty, z uwierzytelnionymi metadanymi dotyczącymi artefaktu
- zapewnia zestaw predefiniowane predykaty do przekazywania uwierzytelnionych metadanych w obrębie łańcuchów dostaw oprogramowania
Przyjrzyjmy się bliżej formatowi poświadczenia.
An Zaświadczenie jest dokument podpisany cyfrowo który zawiera Sprawozdania.
Zestawienie sprzedaży jest środkową warstwą poświadczenia, wiążącą je z konkretnym Temat i jednoznacznie identyfikując typy Orzec:
- Temat: kryptograficznie bezpieczne odniesienie do artefaktu (zwykle za pomocą hasza) i
- Predykaty:zestaw konkretnych roszczenia Informacje dotyczące tego artefaktu nazywane są Oświadczeniem. Te oświadczenia mogą służyć do wyrażania (a później do udowodnienia) wszystkiego, co przyjdzie Ci do głowy! Mogą one reprezentować ręczne zatwierdzenie, pochodzenie artefaktu, wyniki testów automatycznych, ślad audytu i wiele więcej!
Jeżeli niniejsze Oświadczenie zostanie podpisane kryptograficznie, będzie ono dalej nazywane Zaświadczenie

W ten sposób Alicja na przykład tworzy Oświadczenie dotyczące artefaktu i podpisuje je swoim kluczem prywatnym, tworząc w ten sposób Poświadczenie.
- Bob może wtedy zweryfikuj podpis w tym zaświadczeniu, pozwalając mu ufać twierdzeniom wewnątrz.
Bob może następnie wykorzystać te roszczenia zdecydować czy zezwolić na użycie tego artefaktu.

Czy poświadczenia mogą pomóc rozwiązać problem zatrucia artefaktami?
Po tym wprowadzeniu do poświadczeń wróćmy do naszego problemu. W jaki sposób atesty mogą pomóc nam rozwiązać nasz problem, tj. uniknąć zatrucia artefaktami?
Użytkownikowi złośliwemu udało się stworzyć artefakt, omijając „oficjalny” mechanizm, czyli wykorzystując swój pipeline aby wygenerować artefakt.
Byłoby wspaniale, gdybyśmy mogli udowodnić, że pobierane artefakty zostały zbudowane przy użyciu oficjalnej wersji pipelines. To tylko jeden przykład tego, co moglibyśmy nazwać „punktami manipulacji”, ale może być ich o wiele więcej.

Jak widać na powyższym zdjęciu, punktów manipulacji jest wiele. W ten sposób konsument pipeline (Test CI w naszym przykładzie) musi ocenić integralność procesu kompilacji jak również integralność samego artefaktu.
W naszym przykładzie zatruty artefakt został stworzony poprzez wprowadzenie nowego (zatrutego) pipeline co ingeruje w proces kompilacji. Jednak złośliwy użytkownik mógł:
- zmodyfikuj kod po wyewidencjonowaniu z SCM aby wygenerować złośliwy plik binarny
- zastąp właściwy plik binarny wygenerowany przez kompilację dowolnym innym złośliwym plikiem binarnym
- skompromitować Rejestr Artefaktów i przesłać zatruty artefakt utworzony w inny sposób
- itd.
Jak widać, punktów „manipulacji” może być wiele.
Co jest tu ważne? Oczywiście ochrona wszystkich punktów „manipulacji”. Ale ostatecznie najważniejsze jest… że „konsument” artefaktu może ocenić jego integralność i podjąć decyzję, czy kontynuować jego użytkowanie, czy nie.
Możemy ocenić integralność artefaktu na dwa sposoby.
Jednym ze sposobów jest ocena pochodzenie artefaktu.
Generując Poświadczenie pochodzenia, dostarczamy przydatne metadane (odpowiednio uwierzytelnione i niezaprzeczone) dotyczące artefaktu. W poniższych przykładach użyjemy SÓL Xygeni (Software Attestations Layer for Trust), komponent służący do generowania, rejestrowania i weryfikowania poświadczeń oprogramowania.

- 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
W powyższym kodzie widać, że jest krok, który buduje plik WAR i drugi krok, który generuje Poświadczenie pochodzeniaAby to zrobić, pipeline korzysta z klucza prywatnego i uwzględnia również klucz publiczny w poświadczeniu.
Za kulisami Xygeni sól polecenie przechowuje poświadczenie w księga główna (znany również jako rejestr poświadczeń, rekord w naszym przypadku, ale możesz użyć dowolnego innego). Zrobione, konsument pipeline może obejmować Xygeni Silnik weryfikacyjny w celu sprawdzenia pochodzenia artefaktu i oceny jego integralności.
- 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
Proces weryfikacji ocenia:
- artefakt sha256sum jest prawidłowy (tj. istnieje poświadczenie dotyczące tego „przedmiotu”), i
- poświadczenie jest prawidłowo uwierzytelnione (został wygenerowany przy użyciu odpowiedniego klucza prywatnego)
Proces weryfikacji pozwala ocenić, czy zarówno artefakt, jak i poświadczenie są ważne.
Ale jak pamiętacie, w naszym przypadku artefakt został wygenerowany przez „złośliwego” pipeline (tj. nie oryginał, lecz zmodyfikowana wersja pipeline). Następnie musimy przejść dalej i sprawdzić inny aspekt: to, że artefakt został wygenerowany przez „oryginał” pipeline, a nie żaden inny.
Aby to zrobić, wystarczy dodać prosty wiersz sprawdzający ten warunek, na przykład:
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
To dodatkowe sprawdzenie zakończy się niepowodzeniem, jeśli artefakt nie został wygenerowany przez nasz „bezpieczny” pipeline.
Jeśli artefakt został wygenerowany przez nasz oryginał pipeline (cicd_top10_3_salt/.github/workflows/build.yml), polecenie grep powiedzie się, w przeciwnym razie zakończy się niepowodzeniem, co spowoduje przerwanie działania pipeline i przerwanie dalszych kroków.
„Budowniczy” pipeline to tylko jeden z punktów, które należy sprawdzić pod kątem manipulacji, ale jak wspomniano wcześniej, jest kilka innych punktów, które powinniśmy sprawdzić pod kątem manipulacji.
Na przykład, co się stanie, jeśli kod źródłowy zostanie zmodyfikowany po pobraniu danych z repozytorium i przed poleceniem kompilacji? W tym przypadku kod, który ma zostać utworzony, nie jest taki sam, jak zapisany w SCM.
Sprawdzenie tego punktu manipulacji jest bardzo proste — wystarczy na każdym kroku sprawdzić skróty materiału.
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[])
wnioski
Podsumowując, Atestacja oprogramowania jest to stwierdzenie dotyczące oprogramowania, tj. uwierzytelnione oświadczenie (metadane) dotyczące artefaktu oprogramowania lub zbioru artefaktów oprogramowania.
Atesty oprogramowania to uogólnienie surowego podpisywania artefaktów/kodu. Atest to podpisany dokument (w określonym formacie, zazwyczaj opartym na JSON), który łączy metadane z artefaktem. Reprezentują one dowody łączące dane wejściowe (materiały) i wyjściowe (wytworzone artefakty) na każdym etapie kompilacji.
Atesty zapewniają weryfikowalny zapis kroków wykonanych w celu zbudowania finalnych artefaktów oprogramowania, obejmujący materiały wejściowe dla każdego kroku i uruchomione polecenia kompilacji.
Podsumowując, atesty oprogramowania stanowią doskonały mechanizm sprawdzania wielu różnych aspektów integralności naszego procesu kompilacji.
Skończyłeś serię? Nie martw się! Możesz wrócić do „Zatrute Pipeline Wykonanie (PPE)' lub jakikolwiek inny post, który ponownie Cię zainteresuje!
Bądźcie na bieżąco, zagłębimy się w atesty oprogramowania i build security w kolejnych wpisach na blogu.







