CI/CD

Pipelinesäkerhet

Så skyddar du automationen som bygger och släpper mjukvara från credential-missbruk, komprometterade runners och manipulation.

CI/CD-pipelinen är ett av de mest värdefulla målen i en supply chain-attack mot programvara. En komprometterad pipeline kan injicera skadlig kod i varje artefakt den bygger, stjäla produktionsautentiseringsuppgifter eller ersätta en legitim release med en bakdörrad , allt utan att röra applikationskällkoden. Säkerhet i pipelinen innebär att behandla automationslagret som ett högt värderat mål med sin egen hotmodell.

Lärandemål

Det här ska du kunna efter genomläsning.
  • Identifiera de viktigaste förtroendegränserna i en leveranspipeline.
  • Förklara hur secrets, behörigheter och runner-isolering minskar risk.
  • Känna igen vanliga sätt som pipelines missbrukas eller manipuleras på.

I korthet

En snabb mental modell innan du går på djupet.
Förtroendegränser
  • Secrets
  • Runners
  • Behörigheter
Ändringskontroll
  • Branchskydd
  • PR-granskning
  • Godkännanden
Säkrare mönster
  • OIDC
  • Minsta privilegium
  • Byggisolering

Kärnidén

En CI/CD-pipeline håller vanligtvis nycklarna till riket. Autentiseringsuppgifter för molnmiljöer, push-åtkomst till containerregistryn, driftsättningsbehörigheter, signeringsnycklar. Om en angripare kan påverka vad pipelinen kör eller vad den gör med sina autentiseringsuppgifter, kan de påverka allt nedströms. Detta är ett mer attraktivt mål än att kompromittera enskilda applikationsinstanser.

Attackytan i supply chain sträcker sig bortom själva pipelinen. GitHub Actions från tredje part, npm-paket, pip-paket och bascontainerimages är alla indata till bygget. Skadliga eller komprometterade indata från tredje part kan sätta in kod i artefakter utan att pipeline-operatörens vetskap.

Den rätta mentala modellen är att behandla varje extern indata till pipelinen som opålitlig tills den verifierats. Kod från bidragsgivare utanför organisationen, tredjepartsåtgärder pinnade till muterbara taggar och obekräftade byggverktyg är alla potentiella injektionspunkter.

Separation av bekymmer är den organisatoriska principen för pipelinesäkerhet. Opålitliga bidragsgivardrivna steg (bygga och testa en PR från en fork) ska aldrig ha åtkomst till produktionshemligheter, signeringsnycklar eller driftsättningsbehörigheter.

Tillitsmodell

  • Avgränsa autentiseringsuppgifter till det minsta möjliga jobbet, miljön och tidsfönstret.
  • Separera bygg- och teststegen (som körs på potentiellt opålitlig kod) från signerings-, publicerings- och driftsättningsstegen (som kräver betrodda autentiseringsuppgifter).
  • Behandla grensskydd på release- och main-grenar som en säkerhetskontroll, inte bara ett samarbetsarbetsflöde.

Basnivå

  • Granska ändringar av pipelinekonfiguration med samma noggrannhet som ändringar av applikationskod. En enda skadlig rad i en workflow-fil kan exfiltrera alla pipelinehemligheter.
  • Pinna alla åtgärder från tredje part, basimages och externa verktyg till specifika versioner eller digests, inte till muterbara taggar som 'latest'.
  • Föredra kortlivade, avgränsade autentiseringsuppgifter (OIDC-baserade tokens) framför långlivade statiska hemligheter lagrade i pipelinekonfiguration.

Signaler att bevaka

Mönster som är värda att undersöka vidare.
  • Byggloggar avslöjar secrets, tokens eller interna endpoints.
  • En pull request kan påverka privilegierade jobb utan granskning.
  • En runner har bredare åtkomst än jobbet faktiskt behöver.

FÖRDJUPNING

Hemligheter i pipelines

Pipelinehemligheter är autentiseringsuppgifter med högt värde och hög risk. De inkluderar vanligtvis molnleverantörers autentiseringsuppgifter, push-tokens för containerregistryn, signeringsnycklar, driftsättningstoken och API-nycklar. Målet är att göra hemligheter tillgängliga för de specifika jobb som behöver dem samtidigt som man förhindrar att jobb som inte ska ha dem ser dem.

I GitHub Actions kan hemligheter avgränsas på repositorys-, miljö- eller organisationsnivå. Miljöavgränsade hemligheter är bara tillgängliga för jobb som specificerar den miljön, och miljöer kan kräva godkännande innan de nås. Det innebär att en driftsättningshemlighet bara är tillgänglig efter att en människa har granskat och godkänt driftsättningen.

Logmaskering är ett viktigt men otillräckligt försvar. De flesta CI-system maskerar automatiskt kända hemliga värden i loggutdata och ersätter dem med asterisker. Men maskering fungerar bara för exakta matchningar. En hemlighet som är base64-kodad eller inbäddad i en längre sträng kanske inte maskeras.

Efter att en hemlighet misstänks vara exponerad, oavsett om det är via en logg, en artefakt eller en komprometterad pipeline, är det korrekta svaret omedelbar rotation, inte övervakning för att se om den missbrukats. Rotation ogiltigförklarar den exponerade autentiseringsuppgiften och ersätter den med en ny.

Behörigheter

Pipeline-behörigheter definierar vad det automatiserade jobbet är tillåtet att göra. I GitHub Actions deklareras arbetsflödesbehörigheter som ett överordnat behörighetsblock och kan inkludera skrivåtkomst till repositoryinnehåll, paket, säkerhetshändelser och andra resurser. Principen om minsta privilegium innebär att bara ange de behörigheter varje jobb faktiskt behöver.

GITHUB_TOKEN är en automatiskt genererad token avgränsad till repositoryt för varje arbetsflödeskörning. Dess standardbehörigheter varierar beroende på organisationsinställning, vilket är varför det är viktigt att explicit deklarera behörighetsblocket i arbetsflödesfiler. Det gör de faktiska behörigheterna synliga och granskningsbara oavsett organisationens standardinställning.

Distinktionen mellan vad en bidragsgivare kan göra i GitHub UI och vad ett arbetsflöde de utlöser kan göra med GITHUB_TOKEN är subtil men viktig. En bidragsgivare med 'read'-åtkomst till ett repository kan fortfarande utlösa ett arbetsflöde på deras fork. Om det arbetsflödet har skrivbehörigheter kan det utföra åtgärder som bidragsgivaren inte kunde utföra direkt.

Minsta-privilegiepipeline-behörigheter är särskilt viktiga för release- och driftsättningssteg. Ett jobb som publicerar en containerimage till ett registry bör ha exakt de behörigheter som krävs för den operationen. Inget bredare. Tidsbegränsade autentiseringsuppgifter minskar fönstret under vilket en läckt autentiseringsuppgift kan missbrukas.

Byggisolering

Byggisolering säkerställer att vad som händer i ett byggjobb inte kontaminerar ett annat. Utan isolering kan ett skadligt byggsteg lämna efter sig modifierade filer, miljövariabler eller cachad data som påverkar efterföljande jobb. Isolering uppnås genom engångsmiljöer. Idealiskt körs varje jobb i en färsk container eller VM som kasseras efter att jobbet slutförs.

Caching är en prestandaoptimering som direkt konfliktar med isolering. En cache som delas mellan jobb minskar byggtider men skapar också en kanal för ett jobb att påverka ett annat. Cacheminnen bör avgränsas till specifika nycklar och bör behandlas som opålitliga indata.

Docker-in-Docker (DinD), att köra Docker-kommandon inne i en Docker-container, har två huvudvarianter med olika säkerhetsprofiler. Den privilegierade DinD-metoden kör den inre Docker-daemonen som en privilegierad container, vilket beviljar nästan värdnivåtillgång. Docker socket-monteringsmetoden monterar värdens Docker-socket i CI-containern, vilket tillåter CI-jobbet att kontrollera värdens Docker-daemon.

Runner-images som används av CI-jobb bör behandlas som produktionsinfrastruktur. De bör vara minimala, hållas uppdaterade och skannas för sårbarheter. Att använda versionshanterade, skannade, organisationskontrollerade runner-images snarare än de senaste offentliga minskar den betrodda databehandlingsbasen.

Runner-tillit

En CI-runner är maskinen eller containern som kör pipeline-jobb. Den har åtkomst till jobbets källkod, dess miljövariabler (inklusive hemligheter), dess artefakter och potentiellt andra jobb som körs på samma hårdvara. Säkerheten hos runnern är därför en del av säkerhetsgränsen för allt pipelinen gör.

Självhostade runners ger mer kontroll över runner-miljön men medför också mer risk. En självhostad runner som körs på plats eller i en moln-VM har beständigt tillstånd mellan jobb om det inte rensas explicit mellan körningar. Ett skadligt jobb kan lämna efter sig filer, modifiera systemkonfiguration eller installera beständigt verktyg som påverkar framtida jobb.

Delade runners (tillhandahållna av GitHub, GitLab eller andra CI-tjänster) isoleras per jobb i containeriserade eller VM-baserade miljöer som kasseras efter varje jobb. Detta eliminerar persistens mellan jobb och förhindrar de flesta korsjobbkontamineringar. Avvägningen är mindre kontroll över miljön.

Den farligaste konfigurationen är en självhostad runner som hanterar både opålitliga fork PR-byggen och privilegierade release-jobb. En skadlig fork PR kan köra kod på runnern, som kan ha åtkomst till organisationens produktionsautentiseringsuppgifter. Separata runner-pooler för opålitliga och betrodda arbetsflöden är en kritisk säkerhetskontroll.

Grensskydd

Grensskyddsregler tillämpar villkor som måste uppfyllas innan kod kan slås ihop med eller pushas till en skyddad gren. För main-grenen och release-grenar i ett CI/CD-sammanhang är de viktigaste skydden. Kräv pull request-granskningar innan sammanslagning, kräv att statuskontroller godkänns, begränsa vem som kan pusha direkt.

Grensskydd spelar roll för pipelinesäkerhet eftersom skyddade grenar vanligtvis är utlösarna för privilegierade pipelinesteg. En push till main kan utlösa en driftsättning till staging, en tagg på en release-gren kan utlösa en driftsättning till produktion. Om vem som helst kan pusha till dessa grenar utan granskning, kan de utlösa dessa privilegierade steg med godtycklig kod.

Signerade commits lägger till ett kryptografiskt lager till grensskyddet. När signerade commits krävs på en skyddad gren måste varje commit signeras av en nyckel associerad med den committande författaren. Detta förhindrar imitation och ger icke-avvisande.

Grensskyddsregler interagerar också med obligatoriska driftsättningsmiljöer. En driftsättningsmiljö kan kräva specifika granskare innan den aktiveras. Det innebär att även om ett pipeline-jobb begär åtkomst till produktionshemligheter, måste en människa godkänna den begäran innan hemligheterna görs tillgängliga.

Pull request-risker

Pull requests från externa bidragsgivare eller opålitliga forks representerar ett särskilt högriskscenario i CI/CD-pipelines. När en PR utlöser ett CI-jobb, kör det jobbet koden från PR:n. Som kan vara godtycklig kod skriven av en opålitlig författare. Om det jobbet har åtkomst till organisationshemligheter har angriparen uppnått kodexekvering i ett privilegierat sammanhang.

I GitHub Actions utlöser pull_request-händelsen arbetsflöden med begränsade behörigheter (ingen åtkomst till hemligheter, skrivskyddad GITHUB_TOKEN) när PR:n kommer från en fork. pull_request_target-händelsen utlöser arbetsflöden med fullständiga repositorybehörigheter, inklusive åtkomst till hemligheter, även för PR:er från forks. Alla arbetsflöden som använder pull_request_target och också checkar ut eller kör kod från PR:n skapar en kritisk säkerhetsbristerbarhet.

Godkännandeportar för förstagångsbidragsgivare lägger till en manuell kontrollpunkt innan CI körs på en PR från en förstagångsbidragsgivare. GitHub Actions har en inställning som förhindrar automatiserade arbetsflöden från att köras tills en underhållare explicit godkänner.

Det säkra mönstret för att hantera PR:er från forks är. Kör opålitlig kod i ett begränsat sammanhang (pull_request, inte pull_request_target, inga hemligheter, inga driftsättningsbehörigheter), samla artefakter och testresultat, kör sedan eventuella privilegierade steg i ett separat arbetsflöde som utlöses av en granskares godkännande.

OIDC

OpenID Connect (OIDC) är ett tillitsutbytesprotokoll som gör att en CI/CD-pipeline kan erhålla kortlivade autentiseringsuppgifter från en molnleverantör utan att lagra långlivade statiska hemligheter i pipelinekonfigurationen. Istället för en IAM-åtkomstnyckel lagrad i en repositoryhemlighet begär pipelinen en JWT-token från CI-leverantörens tokenslutpunkt.

OIDC-flödet fungerar enligt följande. CI-jobbet begär en signerad JWT från CI-leverantörens tokenslutpunkt, innehållande anspråk om arbetsflödets identitet (repositoryns namn, gren, miljö, aktör). Molnleverantörens identitetssystem validerar JWT:ns signatur och kontrollerar anspråken mot en konfigurerad tillitspolicy.

OIDC eliminerar flera hela klasser av hemlighetshantingsproblem. Det finns inga långlivade autentiseringsuppgifter att rotera, lagra säkert eller av misstag exponera i ett commit. En stulen OIDC-token är värdelös utanför den ursprungliga arbetsflödeskörningens sammanhang.

Anspråksbaserad åtkomstkontroll med OIDC kan vara mycket detaljerad. En tillitspolicy kan kräva att arbetsflödet körs på en specifik gren, från ett specifikt repository, i en specifik miljö, utlöst av en specifik händelse. Det innebär att fork PR-arbetsflöden inte kan anta produktions-IAM-rollen, eftersom deras anspråk inte matchar policyn.

Artefakttampering

Artefakttampering är modifieringen av en byggutdata efter att den lämnat den betrodda byggmiljön. En angripare som kan ersätta en containerimage i ett registry med en skadlig kan orsaka att ett nedströms driftsättningssystem kör angriparkontrollerad kod. Denna attack är specifikt utformad för att kringgå kodgranskning och testning.

Försvaret mot artefakttampering är integritetverifiering vid varje punkt där en artefakt överförs eller används. För containerimages innebär detta signering med Cosign och verifiering av signaturen före driftsättning. SLSA-proveniensintyg går längre. De registrerar inte bara att artefakten har en specifik checksum utan vem som byggde den, från vilken källa och med vilket byggsystem.

Driftsättningssteget är den sista verifieringspunkten. Innan ett driftsättningssystem hämtar en image och startar containrar bör det verifiera att imagens signatur matchar den förväntade signeringsnyckeln och att proveniensintyget registrerar det förväntade byggursprunget.

Risker för artefakttampering är högre i miljöer där artefakternas livscykel inte är välkontrollerad. Images pushade till delade namnrymder i registryn med svag åtkomstkontroll eller npm-paket publicerade från komprometterade underhållarkonton. Kombinationen av registryåtkomstkontroll, imagesignering och proveniensintyg skapar en supply chain-integritetsmodell som är robust mot de flesta tampering-scenarier.