Vuonna 2026 raportoitiin päivässä 131% enemmän CVE:itä kuin edellisenä vuonna.

Miksi CI

Miksi toimitusketjun tietoturva kuuluu CI-putkeesi

Toimittamasi ohjelmisto on se, minkä CI-buildisi tuotti siitä, mitä se sillä hetkellä latasi. Buildi on ainoa paikka, jossa näet, mitä sisään meni, päätät, mitä sisään saa tulla, ja kirjaat, mitä julkaisuun päätyi.

Päivitetty

What software supply chain security means

Esityksen työmääritelmä: ohjelmistosi on oma koodisi ja kaikki, mistä se riippuu, ja toimitusketju on jokainen vaihe, joka vie nämä osat julkaisuun.

Petteri Pulkkinen ja Erika Marttinen, Kubernetes Community Days Helsinki 2026, 2:35–4:28 videosta SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains.

Tuotantobuildisi ei ole kannettavasi buildi

Useimmat tiimit olettavat, että paikallisesti testattu koodi on sama koodi, joka toimitetaan. Lähdekoodi on sama, mutta ohjelmisto ei usein ole. Buildi on lähdekoodi sekä kaikki, mitä se hakee, ja kaikki sen ympärillä ajohetkellä, ja siitä hyvin vähän on kiinteää.

Kiinnittämättömät riippuvuudet ratkeavat eri tavoin

Riippuvuuksien versiovälit ovat normi. npm:ssä ^1.0.4 hyväksyy minkä tahansa myöhemmän 1.x-julkaisun, joten sama package.json asentaa eri päivinä eri versiot. Lukitustiedosto kiinnittää ne, mutta vain jos se on commitoitu ja buildi noudattaa sitä: npm ci epäonnistuu, kun lukitustiedosto ja package.json ovat ristiriidassa, kun taas npm install voi hiljaa päivittää lukitustiedoston. Monet projektit eivät commitoi sitä lainkaan. Laajasti käytetty web-sovelluskehys Express 5.2.1 ei commitoi.

Kiinnitettykin versio on nimi, ei tiedosto. pipin dokumentaatio selittää, että pelkkä versiokiinnitys ei estä pakettihakemistoa tarjoamasta eri tiedostoja samalle versiolle, ja siksi pip tarjoaa tiivisteiden tarkistustilan.

Aika muuttaa syötteitä

Rekisterit muuttuvat buildien välillä. Uusia versioita julkaistaan, vanhoja vedetään pois, ja versioväli, joka ratkesi maanantaina turvallisesti, voi tiistaina poimia vaarantuneen julkaisun. Myös konttikuvien tagit liikkuvat: Dockerin oma dokumentaatio varoittaa, että ”kuvien tagit ovat muuttuvia, eli julkaisija voi päivittää tagin osoittamaan uuteen kuvaan”, joten FROM node:20 ei ole sama peruskuva kuukaudesta toiseen, ellet kiinnitä sitä tiivisteellä.

Aika päätyy myös tulokseen. Reproducible Builds -projekti kutsuu aikaleimoja ”suurimmaksi toistettavuusongelmien lähteeksi”, koska niin monet työkalut kirjaavat nykyisen päivämäärän ja kellonajan siihen, mitä ne buildaavat.

Ympäristö on erilainen

  • Käyttöjärjestelmä ja arkkitehtuuri. macOS- ja ARM-kannettava ja Linux- ja x86-64-CI-runneri asentavat samasta paketista eri valmiiksi käännetyt binäärit. Monet npm-työkalut toimitetaan nykyään alustakohtaisina paketteina, jotka käärivät käännetyn binäärin.
  • Työkaluketjut. Kääntäjän, ajoympäristön ja paketinhallinnan versiot ajautuvat koneiden välillä erilleen, ellei jokaista niistä ole kiinnitetty.
  • Välimuistit. Koneesi ja CI:si palauttavat eri välimuistit, jotka on rakennettu eri aikoina eri ratkaisuista.
  • Asennusskriptit ja build-vaiheet. Asennuksen jälkeiset koukut, setup-actionit ja build-skriptit lataavat työkaluja ja dataa buildin aikana. Mitään siitä ei näy manifestissa.
  • Konfiguraatio. Ympäristömuuttujat, build-liput ja salaisuudet ovat olemassa CI:ssä eivätkä missään muualla.

Reproducible Builds -projekti määrittelee toistettavan buildin sellaiseksi, jossa ”samasta lähdekoodista, build-ympäristöstä ja build-ohjeista kuka tahansa voi luoda bitilleen identtiset kopiot kaikista määritetyistä artefakteista”. Määritelmä näyttää, kuinka paljon on pidettävä vakiona. Useimpien tiimien buildit eivät pääse siihen, ja ne, jotka pääsevät, ovat tehneet sen eteen kovasti töitä. Siihen asti ainoa luotettava kuvaus toimitetusta on se, joka kirjattiin toimitetun buildin ollessa käynnissä.

A software supply chain, walked end to end

Petteri Pulkkinen ja Erika Marttinen, Kubernetes Community Days Helsinki 2026, 15:20–16:38 videosta SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains.

Missä voit tarkistaa, ja mitä kukin paikka näkee

Tietoturvatarkistuksia voi ajaa neljässä paikassa. Jokaisella on tehtävänsä, mutta vain yksi niistä näkee buildin, joka todella tuotti julkaisusi.

Ominaisuus CI-buildissa Kehittäjän kone Repositorion skannaus Artefaktin skannaus
Näkee versiot, jotka tuotanto todella sai Kirjataan haettaessa Eri asennus Vain jos lukitustiedosto kiinnittää ne Mitä se tunnistaa
Näkee transitiiviset ja välimuistista palautetut paketit Oma välimuistinsa, ei CI:n Vain lukitustiedosto
Näkee, mitä asennusskriptit lataavat
Voi pysäyttää haitallisen lähtevän yhteyden Egress-käytäntö runnerilla
Havaitsee ongelmat ennen koodin pushaamista Pull requesteissa
  • Sisältyy
  • Osittain
  • Ei sisälly

Repositorion skannaus raportoi, mitä projekti ilmoittaa. Valmiin artefaktin skannaus raportoi, mitä se pystyy tunnistamaan sen sisältä. Kumpikaan ei nähnyt buildin tapahtuvan. Express 5.2.1 ei commitoi lukitustiedostoa, joten puhtaaseen checkoutiin osoitetulla skannerilla ei ole yhtään projektin npm-riippuvuutta ratkaistavana, ja se raportoi mitä tahansa muuta se tunnistaa. Osoita sama työkalu saman repositorion asennettuun kopioon, ja yksi katalogointilippu muuttaa vastauksen taas. Tulos riippuu siitä, mitä oli asennettu ennen skannausta, eli juuri siitä osasta, jota skannaus ei hallitse. Buildin aikana tallennettuja SBOM:eja käsittelevä sivu kertoo, miksi skannaukset ovat eri mieltä ja mitä buildin kirjaaminen muuttaa.

Putki on itsessään kohde

CI on paikka, jossa lähdekoodi, riippuvuudet ja salaisuudet kohtaavat, mikä tekee siitä hyökkäämisen arvoisen.

  • tj-actions/changed-files (2025). Laajasti käytetty GitHub Action vaarannettiin, ja se tulosti CI-salaisuuksia buildilokeihin.
  • Codecov Bash Uploader (2021). Muokattu skripti, jota ajettiin asiakkaiden CI:ssä, lähetti ympäristömuuttujat hyökkääjän palvelimelle.
  • Shai-Hulud-npm-mato (2025). Vaarantuneet paketit varastivat tunnistetietoja asennuksen yhteydessä ja julkaisivat niillä lisää vaarantuneita paketteja.
  • xz utils (2024). Takaovi oli piilotettu julkaisutarballeihin ja itse build-prosessiin, ei näkyvään lähdekoodiin.

Jokainen näistä ajoi koodia buildin tai asennuksen aikana. Ennen niitä ajettu repositorion skannaus tai niiden jälkeen ajettu artefaktin skannaus ei olisi nähnyt, mitä build-prosessi teki. Kontrollien, jotka tarkkailevat ja rajoittavat sitä, mihin jobi pääsee, on sijaittava siellä, missä jobi ajetaan. Sama pätee sisäisiin ja vähemmän näkyviin sovelluksiin: tällaiset hyökkäykset kohdistuvat putkeen ja paketteihin, jotka kaikki sovellukset jakavat, eivät siihen, mitä sovellus tekee. Katso toimitusketjun tietoturva sisäisille ja matalan riskin ohjelmistoille.

Enemmän koodia, enemmän riippuvuuksia, vähemmän lukijoita

Tekoälypohjaiset koodausagentit kirjoittavat ja muuttavat koodia nopeammin kuin tiimit ehtivät tarkistaa jokaisen rivin, ja ne lisäävät riippuvuuksia samalla. Ne myös nimeävät paketteja, joita ei ole olemassa: USENIX Security 2025 -tutkimus, jossa tarkasteltiin 576 000 generoitua koodinäytettä, havaitsi hallusinoitujen pakettien osuudeksi vähintään 5,2 % kaupallisilla malleilla ja 21,7 % avoimen lähdekoodin malleilla. Hyökkääjä, joka rekisteröi yhden näistä nimistä, tulee asennetuksi seuraavassa buildissa, joka luottaa siihen.

Jokainen muutos, kirjoitti sen kuka tai mikä tahansa, kulkee buildin läpi matkalla tuotantoon. Siksi buildi on ainoa tarkistuspiste, joka ei riipu siitä, että joku on katsonut.

Näytön on kuvattava sitä, mitä toimitettiin

Sääntely ja asiakkaat vaativat todisteita, eivät aikomuksia. EU:n kyberkestävyyssäädös (Cyber Resilience Act, CRA) edellyttää, että valmistajat tunnistavat ja dokumentoivat tuotteidensa komponentit ja käsittelevät niiden haavoittuvuudet tuotteen tukiajan. Manifestista generoitu SBOM kuvaa, mitä projekti pyysi. Buildista tallennettu SBOM kuvaa, mitä päätyi julkaisuun, josta olet vastuussa. Kun uusi haavoittuvuus julkaistaan, jälkimmäinen kertoo, mihin julkaisuihin se vaikuttaa. Lue, mitä CRA vaatii.

Mitä ”CI:ssä” pitäisi tarkoittaa

Skannerin ajaminen CI-vaiheena on alku, mutta se katsoo silti tiedostoja niiden saavuttua. Kunnolla tehtynä CI:ssä tarkoittaa:

  1. Kirjaa, älä päättele. Tallenna jokainen paketti ja lataus, jonka jobi todella hakee, transitiiviset riippuvuudet ja välimuistista palautettu sisältö mukaan lukien.
  2. Kerro, kuinka kattava kirjaus on. SBOM:n pitäisi kertoa, kattaako se kaiken, mitä jobi haki, eikä vain luetella löytämäänsä.
  3. Hallitse lähtevää liikennettä. Päätä, mihin palvelimiin jobi saa ottaa yhteyttä, ja pysäytä loput ennen kuin vaarantunut riippuvuus pääsee soittamaan kotiin.
  4. Jatka seurantaa julkaisun jälkeen. Tarkista toimitettu uudelleen, kun uusia haavoittuvuuksia ilmenee, ja muuta löydökset korjauksiksi.

Tätä CRACI tekee. Se on GitHub Actions -jobiesi runneri, joten se kirjaa, mitä kukin buildi hakee, soveltaa egress-käytäntöä ja seuraa, mitä olet toimittanut. Työnkulun siirtäminen on yksi rivi: runs-on: craci. Katso, miten CRACI toimii.

Mitä CI ei korvaa

Toimitusketjun tietoturvan sijoittaminen buildiin ei tee muista kerroksista valinnaisia.

  • Kehittäjien koneilla on edelleen tunnistetietoja, ja niillä ajetaan asennusskriptejä. Suojaa nekin; vaarantunut kannettava voi puskea koodia ennen kuin yksikään buildi ajetaan.
  • Koodikatselmointi ja staattinen analyysi löytävät virheitä omasta koodistasi, mitä riippuvuuksien kirjaus ei tee.
  • Kiinnitykset, lukitustiedostot ja tiivisteet ovat edelleen hyvä käytäntö. Ne kaventavat buildien välistä eroa; buildin kirjaaminen kertoo silti, mitä tapahtui.

Buildi ei ole ainoa tarkistuspaikka. Se on ainoa paikka, joka näkee ohjelmiston, jonka todella toimitat.

Näe CRACI omassa putkessasi

Varaa demo, niin käymme läpi buildisi, SBOM:isi ja vaatimustenmukaisuuden näyttösi.

Varaa demo