Den 15 juli 2026 upptäckte säkerhetsforskare att fem paketversioner i det populära AsyncAPI-ekosystemet på npm hade bytts ut mot skadlig kod. Enligt Microsofts säkerhetsblogg exponerade en felkonfigurerad GitHub Actions-workflow med pull_request_target en personlig åtkomsttoken som angriparna sedan använde för att publicera egna versioner rakt in i tusentals byggpipelines. Mindre än en månad tidigare, den 12 maj, beskrev Orca Security en liknande kampanj mot över 160 paket i npm och PyPI, däribland bibliotek kopplade till TanStack, Mistral AI och UiPath, där cachningen i GitHub Actions förgiftades för att stjäla tokens i bulk. Det är två exempel av flera under 2026 på samma mönster: angripare siktar inte längre bara på applikationskoden, utan på själva vägen mellan utvecklare och produktion.

Den här guiden visar hur du stänger ett av de mest utnyttjade hålen i den vägen: containerimages som saknar spårbar, verifierbar signatur. Med Sigstore-projektets verktyg cosign kan du signera images utan att hantera hemliga nycklar, låsa upp verifiering till specifika byggpipelines och koppla signaturen till en offentlig transparenslogg. Du får 15 konkreta steg, färdiga kommandon, en komplett GitHub Actions-pipeline och en Kubernetes-policy som blockerar allt som inte är signerat. Målet är att du efter genomgången kan svara ja på frågan “kan vi bevisa var den här imagen kom ifrån?” för varje enda deploy.

Signera containerimages med cosign är i grunden inte en komplicerad teknisk uppgift, men det kräver att du förstår varför varje steg finns innan du automatiserar bort det. En pipeline som blint kör cosign sign utan att någon senare verifierar identiteten ger dig papperssäkerhet, inte faktisk säkerhet. Guiden går därför igenom både hur du signerar och, minst lika viktigt, hur du tvingar fram verifiering innan en image tillåts köra.

Vad Sigstore och cosign faktiskt löser

Sigstore är ett öppen källkods-projekt som numera ligger under Linux Foundations paraply, och det beskriver sig självt som ett initiativ för att förbättra säkerheten i mjukvarans leveranskedja genom att göra det enkelt att signera och verifiera artefakter som releasefiler, containerimages, binärer och SBOM:er. Projektet består av tre delar som samverkar. Cosign hanterar själva signeringen och verifieringen av images. Fulcio agerar certifikatutfärdare och skapar kortlivade certifikat kopplade till en identitet, till exempel din GitHub- eller Google-inloggning. Rekor är en manipuleringssäker transparenslogg där varje signatur registreras offentligt, ungefär som Certificate Transparency fungerar för TLS-certifikat.

Den stora skillnaden mot äldre signeringslösningar som Docker Content Trust eller manuellt hanterade GPG-nycklar är att cosign stödjer keylös signering. I stället för att en utvecklare eller byggserver behöver skydda en privat nyckel i flera år, autentiserar cosign mot en OIDC-leverantör (till exempel GitHub Actions inbyggda identitetstoken), får ett certifikat som gäller i tio minuter från Fulcio, signerar imagen och kastar sedan bort nyckeln. Signaturen och certifikatet laddas upp till Rekor, och den offentliga loggen blir beviset senare, även efter att certifikatet har slutat gälla. Enligt Sigstores egen dokumentation lagras signaturen och certifikatet i Rekors transparenslogg och laddas samtidigt upp till OCI-registret bredvid imagen som signeras, vilket gör att verifiering fungerar utan separat infrastruktur.

Den senaste bekräftade stabila versionen av cosign vid den här artikelns publicering, tidigt sensommaren 2026, är v3.0.6, släppt i april 2026. Sigstores eget projektblogginlägg i juni 2026 noterade att cosign 2.6.0 tidigare hade lagt till stöd för att ladda upp och verifiera mot Rekor v2, vilket är relevant bakgrund om du stöter på äldre installationer i din organisation. Rekor-repositoriet visade version 1.5.1 som senaste utgåva i mars 2026, och Rekor v1 beskrivs numera som i underhållsläge medan API:et förblir stabilt från 1.0.0 och framåt.

Fulcio, Rekor och OIDC i praktiken

Det som förvirrar flest nybörjare är hur lite som faktiskt sparas lokalt. När du kör en signeringskommando skapar cosign ett nytt nyckelpar direkt i minnet, skickar den publika halvan tillsammans med din OIDC-token till Fulcio, och får tillbaka ett kortlivat certifikat som binder nyckeln till din identitet under några minuter. Den privata nyckeln används en enda gång för att skapa signaturen och kastas sedan, den lagras aldrig på disk och behöver därför aldrig backas upp, roteras eller skyddas mot stöld på samma sätt som traditionella signeringsnycklar. Det är en medveten designprincip snarare än en genväg: risken flyttas från “skydda en hemlighet i flera år” till “skydda inloggningen till din identitetsleverantör under några sekunder”, vilket för de flesta organisationer redan är bättre bevakat genom multifaktorautentisering och conditional access-policyer.

Rekor fyller en annan funktion. Även om certifikatet från Fulcio slutar gälla efter tio minuter, förblir beviset för att signeringen skedde permanent synligt i transparensloggen. Var och en kan i efterhand fråga Rekor “visa mig alla signaturer kopplade till den här imagens digest” och få tillbaka ett kryptografiskt bevisbart svar, utan att behöva lita på ett enskilt företag eller en enskild server. Den offentligheten är samma princip som redan används för Certificate Transparency inom TLS, tillämpad på mjukvaruartefakter i stället för webbcertifikat.

Verkliga attacker som visar varför detta spelar roll

Leveranskedjeattacker mot paketregister och byggpipelines har gått från undantag till återkommande rubriker under 2025 och 2026. Tabellen nedan listar fem dokumenterade incidenter som alla hade kunnat upptäckas snabbare, eller stoppats helt, om konsumenter av paketen och images hade krävt verifierbar signering och granskat ursprunget innan installation.

IncidentDatum 2026EkosystemVad hände
AsyncAPI-kompromettering15 julinpmFem paketversioner ersattes efter att en felkonfigurerad GitHub Actions-workflow läckte en åtkomsttoken
TanStack/160+ paket12 majnpm och PyPICacheförgiftning i GitHub Actions ledde till tokenstöld i över 160 paket, enligt Orca Security
Typosquattade npm-paket28 majnpmFalska paketnamn användes för att stjäla moln- och CI/CD-hemligheter, enligt Microsoft Security
elementary-dataslutet av aprilPyPI och GHCRSkriptinjektion i GitHub Actions förfalskade en release som spreds till både PyPI och containerregistret
Npm-mask som utnyttjade transparensloggar5 augustinpmEn självspridande mask kompromitterade populära paket, dokumenterad av Datadog Security Labs med referenser till Rekor-poster

Ett mönster går igen i nästan alla dessa fall: angriparen kom in via CI/CD-pipelinen, inte via applikationens källkod. Det är exakt den ytan som keylös signering med cosign är byggd för att skydda, eftersom varje signatur binds till en specifik identitet i en specifik workflow-körning, inte till en delad hemlighet som kan läcka och återanvändas i månader.

Värt att notera är att ingen av incidenterna i tabellen stoppades av traditionell antivirus- eller sårbarhetsskanning, eftersom den skadliga koden i sig ofta var relativt enkel. Det som saknades var ett steg där konsumenten av paketet eller imagen kunde fråga “kommer den här artefakten verkligen från den pipeline jag litar på, signerad med en identitet jag känner igen?” och få ett kryptografiskt bevisbart svar innan installation eller deploy. Det är precis det steget resten av den här guiden bygger upp, från första signering till en policy som automatiskt blockerar allt som inte klarar kontrollen.

Förkunskaper och exakta versioner du behöver

Innan du börjar, se till att du har följande på plats. Guiden är testad mot de här versionerna, och äldre versioner kan sakna flaggor som används i kommandona nedan.

Guiden riktar sig till dig som redan bygger och driftsätter containerimages regelbundet, oavsett om det sker mot ett internt Kubernetes-kluster eller mot en molnleverantörs container-tjänst. Du behöver inte kunna kryptografi på djupet för att följa stegen, men grundläggande förståelse för hur OCI-register, taggar och digest fungerar gör det betydligt lättare att felsöka när något går fel.

  • Cosign v3.0.6 eller senare (installeras i steg 1)
  • Docker Engine 29.7.2 eller Podman 6.1.0, för att bygga och pusha images
  • Ett konto hos ett OCI-register som stödjer OCI-artefakter, till exempel GitHub Container Registry, Docker Hub eller Amazon ECR
  • Git och ett GitHub-konto, för keylös autentisering via OIDC och för CI/CD-delen
  • kubectl v1.36.1 om du vill följa Kubernetes-policydelen mot ett testkluster
  • Grundläggande vana vid terminalen och miljövariabler i bash eller zsh
VerktygVersion i denna guideSenast bekräftad
cosignv3.0.6April 2026
Rekorv1.5.1 (v1, underhållsläge)Mars 2026
Docker Engine29.7.25 augusti 2026
Podman6.1.012 augusti 2026
kubectlv1.36.1Maj 2026
SLSA-specifikationv1.2 (build-nivåer refererade i v1.1)2026

Nyckelbaserad signering: när det fortfarande är rätt val

Keylös signering passar de flesta team, men den förutsätter uppkoppling mot internet och tillgång till en OIDC-leverantör vid varje signeringstillfälle. Det håller inte alltid. Flera svenska myndigheter och industriaktörer kör isolerade eller så kallade air-gapped byggmiljöer där ingen utgående trafik tillåts, och där måste cosign fortfarande gå att använda utan att ringa hem till Fulcio och Rekor. Lösningen är klassisk nyckelbaserad signering, som cosign stödjer sida vid sida med det keylösa läget.

cosign generate-key-pair
# Skapar cosign.key (privat, lösenordsskyddad) och cosign.pub (publik)

cosign sign --key cosign.key ghcr.io/dittteam/webbapp@sha256:7c2e9a1b4f...
cosign verify --key cosign.pub ghcr.io/dittteam/webbapp@sha256:7c2e9a1b4f...

Nackdelen är uppenbar: du är tillbaka i samma nyckelhanteringsproblem som Sigstore ursprungligen ville lösa. Den privata nyckeln måste förvaras i ett hemlighetsvalv, till exempel HashiCorp Vault eller en molnleverantörs KMS-tjänst, roteras enligt en fastställd policy och aldrig checkas in i ett repository. Om nyckeln läcker gäller den tills du aktivt hinner återkalla den och signera om alla berörda images, till skillnad från keylös signering där varje enskilt certifikat i praktiken redan är förbrukat efter tio minuter.

Hybridupplägg för reglerade miljöer

I praktiken landar många reglerade organisationer i en hybrid. Interna, isolerade byggsteg signerar med en hanterad nyckel i en KMS-tjänst, medan allt som lämnar den kontrollerade miljön och passerar genom en publik pipeline, till exempel en release till ett offentligt register, signeras keylöst för att dra nytta av transparensloggen. Cosign hanterar båda flödena med samma kommandostruktur, vilket gör att teamet inte behöver lära sig två helt olika verktyg, bara två olika flaggor beroende på var i kedjan signeringen sker.

Om ni redan har en äldre GPG- eller nyckelbaserad signeringsprocess och vill flytta till keylöst, behöver ni inte göra bytet på en gång för hela organisationen. Ett vanligt upplägg är att börja med ett enda, mindre kritiskt repository, köra keylös signering parallellt med den gamla processen under några veckor, och jämföra att verifieringsresultaten stämmer överens innan ni stänger av den gamla nyckelhanteringen helt. Det ger teamet tid att bygga rutiner för att läsa Rekor-loggen och felsöka OIDC-relaterade problem innan det påverkar en produktionskritisk release.

Steg 1-3: Installera cosign och kontrollera miljön

Första delen handlar om att få verktygen på plats och verifiera att allt pratar med varandra innan du signerar något på riktigt. Hoppa inte över verifieringssteget, det sparar dig felsökning längre fram. Att signera containerimages med cosign kräver ingen tung infrastruktur på egen hand, men de tre installationsstegen nedan lägger grunden för resten av guiden.

Steg 1. Installera cosign. På Linux hämtar du binären direkt från GitHub-releasen, på macOS går det snabbare via Homebrew.

# Linux (x86_64)
curl -O -L "https://github.com/sigstore/cosign/releases/download/v3.0.6/cosign-linux-amd64"
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
sudo chmod +x /usr/local/bin/cosign

# macOS
brew install cosign

Steg 2. Bekräfta versionen. Kommandot nedan ska matcha den version du hämtade i steg 1.

cosign version

Förväntad utdata ser ut ungefär så här:

____
GitVersion:    v3.0.6
GitCommit:     a1f4e92
GitTreeState:  clean
BuildDate:     2026-04-06T14:02:11Z
GoVersion:     go1.24.2
Compiler:      gc
Platform:      linux/amd64

Steg 3. Kontrollera att din containerruntime är igång och att du är inloggad mot registret du tänker pusha till, till exempel GitHub Container Registry.

docker version --format '{{.Server.Version}}'
echo "$GITHUB_TOKEN" | docker login ghcr.io -u DITT_ANVANDARNAMN --password-stdin

Steg 4-6: Bygg imagen och signera den keylöst

Det här är kärnan i hela guiden. Här går du från en vanlig, osignerad build till en image med ett kryptografiskt bevis kopplat till exakt vilken kod och vilken identitet som skapade den. Tre kommandon räcker, men ordningen mellan dem spelar roll.

Steg 4. Bygg och tagga imagen. Använd ett tydligt versionsnummer, inte bara latest, eftersom taggar är föränderliga och kan skrivas över senare.

docker build -t ghcr.io/dittteam/webbapp:1.4.0 .
docker push ghcr.io/dittteam/webbapp:1.4.0

Steg 5. Hämta digestet för imagen du precis pushade. Det är digestet, inte taggen, som du ska signera i nästa steg, eftersom en tagg kan peka på en annan image i morgon.

docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/dittteam/webbapp:1.4.0

Steg 6. Signera imagen med keylös signering. Kommandot öppnar en webbläsare där du loggar in med din OIDC-identitet (GitHub, Google eller Microsoft), och cosign hanterar resten automatiskt.

cosign sign ghcr.io/dittteam/webbapp@sha256:7c2e9a1b4f...

Du landar i webbläsaren, väljer identitetsleverantör, och terminalen svarar sedan med något i stil med detta:

Generating ephemeral keys...
Retrieving signed certificate...
Successfully verified SCT...
tlog entry created with index: 184920771
Pushing signature to: ghcr.io/dittteam/webbapp

Lägg märke till raden “Successfully verified SCT”, där SCT står för Signed Certificate Timestamp. Det är beviset från Fulcios egen transparenslogg för certifikat, ett separat lager utöver Rekor, som bekräftar att certifikatet som just utfärdades verkligen loggades korrekt innan det användes för att signera. Om det här steget skulle misslyckas avbryter cosign hela signeringen i stället för att fortsätta med ett certifikat som inte går att verifiera i efterhand, vilket är en medveten säkerhetsspärr snarare än ett irriterande extra steg.

Steg 7-9: Granska Rekor-loggen och verifiera signaturen

Nu när imagen är signerad är nästa del att bevisa att den faktiskt går att lita på, inte bara att signeringen tekniskt lyckades. Det är skillnaden mellan att någon skrivit under ett dokument och att du faktiskt kontrollerat vem som skrev under det.

Steg 7. Notera indexet från tlog-posten (i exemplet ovan 184920771). Det numret är ditt kvitto på att signaturen finns permanent registrerad i den offentliga transparensloggen, oavsett vad som händer med det kortlivade certifikatet.

Steg 8. Verifiera imagen. Det viktiga här är att du alltid låser verifieringen till en specifik identitet och en specifik OIDC-utfärdare. Att verifiera utan de flaggorna innebär bara att du kontrollerar att någon, vem som helst, har signerat imagen, vilket ger falsk trygghet.

cosign verify \
  --certificate-identity="https://github.com/dittteam/webbapp/.github/workflows/release.yml@refs/heads/main" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
  ghcr.io/dittteam/webbapp@sha256:7c2e9a1b4f...

Om allt stämmer får du ett JSON-svar där verified: true framgår tillsammans med certifikatets giltighetsperiod och OIDC-anspråken. Om identiteten eller utfärdaren inte matchar det du angav avbryter cosign direkt med ett tydligt felmeddelande, vilket är precis den strikta kontrollen du vill ha i en release-pipeline.

Steg 9. Lägg till en mjukvaruförteckning (SBOM) som en signerad attestation kopplad till samma image, så att den som konsumerar imagen både kan verifiera vem som byggde den och exakt vilka komponenter den innehåller.

syft ghcr.io/dittteam/webbapp@sha256:7c2e9a1b4f... -o spdx-json > sbom.json
cosign attest --predicate sbom.json --type spdxjson \
  ghcr.io/dittteam/webbapp@sha256:7c2e9a1b4f...

Steg 10-12: Bygg in signeringen i GitHub Actions

Manuell signering fungerar för att lära sig flödet, men i produktion vill du att pipelinen signerar automatiskt varje gång en release går ut, utan att en mänsklig operatör behöver logga in manuellt varje gång. Det är också här den verkliga säkerhetsvinsten uppstår, eftersom en automatiserad pipeline med begränsade behörigheter är en betydligt mindre attackyta än en delad nyckel som flera personer i teamet har åtkomst till. GitHub Actions är valt som exempel nedan eftersom det har inbyggt OIDC-stöd som gör integrationen enkel, men samma principer med kortlivade tokens gäller lika väl för GitLab CI, Azure Pipelines och andra plattformar som stödjer OIDC-federering mot Fulcio.

Steg 10. Ge workflowen rätt behörighet. GitHub Actions kan agera OIDC-identitet åt sig själv, men bara om jobbet uttryckligen får skriva id-tokens.

permissions:
  id-token: write
  contents: read
  packages: write

Steg 11. Lägg till bygg-, push- och signeringsstegen i workflow-filen.

name: build-and-sign
on:
  push:
    tags: ["v*"]

jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - uses: sigstore/cosign-installer@v3
      - name: Logga in i registret
        run: echo "$TOKEN" | docker login ghcr.io -u "$ACTOR" --password-stdin
      - name: Bygg och pusha
        run: |
          docker build -t ghcr.io/dittteam/webbapp:$TAG .
          docker push ghcr.io/dittteam/webbapp:$TAG
      - name: Signera keylöst
        run: |
          DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/dittteam/webbapp:$TAG)
          cosign sign --yes "$DIGEST"

Steg 12. Notera flaggan --yes i signeringssteget. Den behövs eftersom pipelinen körs utan interaktiv terminal, och cosign måste veta att det är avsiktligt att hoppa över den manuella bekräftelsen. Utan mänsklig inloggning autentiserar sig jobbet ändå mot Fulcio med GitHub Actions egen kortlivade OIDC-token, samma mekanism som exponerades i AsyncAPI-incidenten, fast här används den defensivt i stället för att kunna kapas.

Steg 13-15: SLSA-provenance och policykontroll

SBOM:en från steg 9 svarar på frågan vad imagen innehåller. Provenance svarar på en annan fråga: hur och var byggdes den. Många team hoppar över det här steget eftersom signering redan känns tillräckligt, men provenance är det som gör att en verifieringspolicy senare kan kräva inte bara “signerad av rätt identitet” utan även “byggd på ett godkänt sätt, från rätt källkodsrepository, utan manuella ändringar i sista sekunden”.

Steg 13. Generera byggprovenance enligt SLSA-ramverket. Provenance är ett dokument som beskriver exakt vilken källkod, vilket byggverktyg och vilken pipeline som producerade artefakten, signerat på samma sätt som SBOM:en i steg 9.

cosign attest --predicate provenance.json --type slsaprovenance \
  ghcr.io/dittteam/webbapp@sha256:7c2e9a1b4f...

Steg 14. Verifiera attestationen separat från signaturen, så att en deploy-pipeline kan kräva både bevisad identitet och bevisat ursprung innan den godkänner en image.

cosign verify-attestation \
  --type slsaprovenance \
  --certificate-identity="https://github.com/dittteam/webbapp/.github/workflows/build-and-sign.yml@refs/heads/main" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
  ghcr.io/dittteam/webbapp@sha256:7c2e9a1b4f...

Steg 15. Bestäm vilken SLSA build-nivå din pipeline faktiskt uppnår. Den officiella specifikationen definierar fyra nivåer i build-spåret, och du bör dokumentera vilken nivå du siktar på snarare än att bara säga “vi följer SLSA”.

NivåKravVad det skyddar mot
L0Ingen provenance krävsIngen extra skyddsnivå, baslinje
L1Provenance visar hur paketet byggdesEnkla misstag och oklarheter kring ursprung
L2Signerad provenance från en hostad byggplattformFörfalskad eller efterhandskonstruerad provenance
L3Härdad, isolerad byggplattformManipulation av byggmiljön under själva byggsteget

En pipeline i GitHub Actions som använder en hostad runner, kortlivade OIDC-tokens och signerad provenance enligt stegen ovan ligger normalt runt L2, medan L3 kräver ytterligare isolering av byggmiljön som de flesta team behöver bygga separat.

Vanliga fallgropar

De flesta problem vi har sett hos team som infört cosign handlar inte om verktyget i sig, utan om vanor som hänger kvar från äldre, nyckelbaserade processer eller om steg som glöms bort när en pipeline sätts upp i stress inför en release. Här är de vanligaste, i ungefärlig ordning efter hur ofta vi stöter på dem.

  • Signera taggen i stället för digestet. Taggar kan pekas om, vilket gör signaturen värdelös som bevis om någon senare pushar en annan image till samma tagg.
  • Verifiera utan att låsa identitet och utfärdare. Ett verify-anrop utan --certificate-identity och --certificate-oidc-issuer visar bara att någon har signerat, inte vem.
  • Behålla statiska nycklar av gammal vana. Om du migrerar från en äldre GPG-baserad process, städa bort de gamla nycklarna helt i stället för att köra båda systemen parallellt utan plan.
  • Glömma id-token: write i CI/CD. Utan den behörigheten kan workflowen aldrig hämta en OIDC-token, och signeringssteget faller med ett svårtolkat felmeddelande.
  • Bara signera i CI, aldrig verifiera i CD. Signering utan efterföljande verifiering vid deploy ger ingen faktisk säkerhetsvinst, bara en falsk känsla av kontroll.
  • Ge för breda scope till access tokens i workflows. Det var precis den typen av överexponerad token som gjorde AsyncAPI-kompromissen i juli 2026 möjlig.
  • Tro att signering ersätter sårbarhetsskanning. En signerad image kan fortfarande innehålla sårbara beroenden, signaturen bevisar ursprung, inte frånvaro av buggar.

Felsökning: 9 vanliga fel och lösningar

De flesta fel du stöter på hör hemma i tre kategorier: nätverksbehörigheter mot Sigstores publika infrastruktur, felaktig identitetsmatchning vid verifiering, eller ett digest som inte längre stämmer med det som faktiskt signerades. Gå igenom listan nedan innan du börjar gräva djupare i loggar, den täcker de flesta fall vi sett i produktionsmiljöer.

“no matching signatures” vid verifiering. Kontrollera att digestet du verifierar är exakt samma som det du signerade, och att --certificate-identity matchar workflow-sökvägen exakt, inklusive gren.

“error: reading blob: unauthorized”. Din docker-inloggning mot registret har troligen gått ut eller saknar rätt scope. Logga in igen med en token som har både read och write mot paketregistret.

Rekor-uppladdningen hänger eller time-outar. Den publika Rekor-instansen kan tillfälligt vara hårt belastad. Testa igen efter någon minut, och om problemet kvarstår, kontrollera din organisations brandvägg mot rekor.sigstore.dev. I CI/CD-miljöer med aggressiva timeout-inställningar rekommenderas att sätta en explicit retry-logik runt signeringssteget snarare än att låta hela jobbet misslyckas vid en enstaka nätverksglitch.

OIDC-token hinner gå ut mitt i en lång pipeline. Flytta signeringssteget så nära push-steget som möjligt, och dela inte upp bygg och signering över flera separata jobb med långa väntetider emellan.

“certificate has expired” vid manuell verifiering långt efter signering. Det är förväntat, Fulcios certifikat är giltiga i cirka tio minuter. Verifiering ska ändå fungera eftersom cosign kontrollerar mot Rekor-loggen och tidsstämpeln vid signeringstillfället, inte mot nuvarande klocka.

GitHub Actions vägrar utfärda id-token. Dubbelkolla att permissions: id-token: write finns både på workflow-nivå och, om du kör återanvändbara workflows, på det anropande jobbet.

Fel digest signeras vid multi-arkitektur-byggen. Om du bygger för flera arkitekturer, signera manifest-listans digest, inte en enskild arkitekturs digest, annars verifierar klienter för andra plattformar aldrig korrekt.

Verifiering fungerar lokalt men inte bakom företagets brandvägg. Fulcio och Rekor är publika tjänster på internet. Om nätverkspolicyn blockerar utgående trafik behöver ni antingen öppna upp mot dessa domäner eller köra en privat Sigstore-instans, vilket större organisationer med strikta nätverkszoner ofta väljer för att slippa bero på en extern tjänst för varje deploy.

“no matching attestations” trots att SBOM:en pushades. Kontrollera att du använde exakt samma digest i attest-steget som i push-steget, och att --type matchar mellan attest och verify-attestation.

Avancerade tips för produktionsmiljöer

När grundflödet fungerar är nästa steg att göra signering obligatorisk, inte frivilligt. Det gör du genom att låta klustret själv vägra köra osignerade images, i stället för att förlita dig på att alla i teamet kommer ihåg att köra verify manuellt. Ett vanligt sätt är en admission controller i Kubernetes, till exempel Kyverno, som kontrollerar signaturen innan en pod ens tillåts starta.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: krav-pa-signerade-images
spec:
  validationFailureAction: Enforce
  rules:
    - name: verifiera-cosign-signatur
      match:
        any:
          - resources:
              kinds: ["Pod"]
      verifyImages:
        - imageReferences:
            - "ghcr.io/dittteam/*"
          attestors:
            - entries:
                - keyless:
                    subject: "https://github.com/dittteam/*/.github/workflows/*@refs/heads/main"
                    issuer: "https://token.actions.githubusercontent.com"

Andra saker värda att bygga in tidigt snarare än att lappa på i efterhand. Sätt en tydlig regel för hur ofta ni granskar vilka OIDC-identiteter som faktiskt får signera mot produktionsregister, och ta bort gamla workflow-sökvägar från policyn så fort ett repo döps om eller flyttas. Om ni har regulatoriska krav på spårbarhet, exportera Rekor-loggposter kopplade till era images till er egen loggning, så att revisionen inte är beroende av att den publika loggen alltid är nåbar. Testa slutligen själva verifieringssteget genom att medvetet försöka deploya en osignerad eller felsignerad image i en testmiljö, så att ni vet att policyn faktiskt stoppar den innan ni litar på den i produktion.

Ett sista tips handlar om nyckelrotation för teamet självt, inte för imagen. Eftersom keylös signering bygger på OIDC-identiteter innebär det att när en utvecklare lämnar teamet eller byter roll, ska motsvarande behörighet i identitetsleverantören stängas av omedelbart, precis som med vilken annan produktionsåtkomst som helst. Cosign gör signeringen spårbar, men den kan inte kompensera för slarvig behörighetshantering i grunden.

Komplett exempel: från källkod till verifierad produktionsdeploy

Sätt ihop allt genom att följa hela kedjan för ett fiktivt team, “Nordvakt”, som bygger en API-tjänst. Flödet nedan binder samman stegen du gått igenom ovan till en enda sammanhängande process.

  1. Utvecklare pushar en release-tagg v2.3.0 till huvudgrenen.
  2. GitHub Actions-workflowen från steg 11 triggas, bygger imagen och pushar den till ghcr.io/nordvakt/api.
  3. Samma jobb hämtar digestet och kör cosign sign --yes med den inbyggda OIDC-token, utan mänsklig inblandning.
  4. Ett separat steg kör Syft för att generera en SBOM och bifogar den som attestation med cosign attest.
  5. Ett tredje steg genererar SLSA-provenance för byggmiljön och attesterar den på samma digest.
  6. Signaturen, SBOM-attestationen och provenance-attestationen registreras alla i Rekor under samma tlog-indexfamilj.
  7. Deploy-pipelinen mot produktionsklustret kör cosign verify och cosign verify-attestation innan den ens skickar manifestet till Kubernetes.
  8. Kyverno-policyn i klustret gör en andra, oberoende kontroll vid schemaläggning, som skyddsnät om deploy-pipelinen skulle förbigås.
  9. Om något steg misslyckas, till exempel att certifikatets identitet inte matchar det förväntade workflow-namnet, stoppas releasen automatiskt innan den når användare.
  10. Säkerhetsteamet får en export av veckans Rekor-poster kopplade till nordvakt/api för sin egen logg, som del av den kontinuerliga revisionen.

Resultatet är en kedja där varje länk, från källkod till körande pod, går att bevisa i efterhand. Om Nordvakt någon gång misstänker att en image manipulerats kan de peka på exakt tlog-index, exakt commit och exakt workflow-körning som producerade den, i stället för att gissa.

Notera också vad som inte krävdes för att bygga upp det här: ingen ny hemlig infrastruktur, inga nya nycklar att skydda, och inget extra godkännandesteg som en människa manuellt måste klicka igenom vid varje release. Hela kedjan bygger på identiteter som redan finns (GitHub-organisationens OIDC-federering) och infrastruktur som redan är publikt tillgänglig och gratis att använda (Fulcio och Rekor). Det gör det här mönstret ovanligt billigt att införa jämfört med hur mycket spårbarhet det ger tillbaka, vilket är en stor anledning till att allt fler open source-projekt och företag krävt signerade artefakter som standard under 2025 och 2026.

Läget i Sverige och Norden

MSB har i sitt material om digitala leveranskedjor uppmanat svenska organisationer att skaffa sig insyn och kontroll över sina digitala leveranskedjor, säkerställa kontinuitet och redundans, samt granska krav, säkerhetsarbete och incidentdelning hos sina leverantörer. CERT-SE:s veckobulletin i slutet av november 2025 flaggade specifikt för den npm-mask som fick namnet Shai-Hulud och som enligt rapportering påverkade över 26 000 repositorier, vilket visar att svenska myndigheter redan aktivt följer den här typen av ekosystemattacker snarare än att betrakta dem som ett amerikanskt problem.

Praktiskt sett betyder det att när ni ska signera containerimages med cosign i en svensk kontext bör ni koppla arbetet till samma dokumentation ni redan tar fram för andra leverantörskrav, i stället för att behandla det som ett fristående säkerhetsprojekt. Ett Rekor-loggindex och en verifierad SLSA-nivå kan gå rakt in i en leverantörsbedömning eller ett internrevisionsunderlag utan omskrivning, vilket sparar tid för både IT-säkerhet och de team som annars hade fått svara på samma fråga manuellt varje kvartal.

För nordiska team som levererar mot offentlig sektor eller kritisk infrastruktur blir signerade images och spårbar provenance därför inte bara en teknisk förbättring, utan ett konkret svar på frågor som redan ställs av upphandlare och tillsynsmyndigheter om hur man kan bevisa ursprunget på det man driftsätter. Att kunna visa upp en Rekor-logg och en verifierad SLSA-nivå väger betydligt tyngre än att svara “vi litar på vår leverantör”.

Ett annat skäl att prioritera detta nu snarare än om ett år är att kraven redan skärps i lagstiftningen. Sveriges cybersäkerhetslag trädde i kraft i januari 2026, och leveranskedjesäkerhet nämns uttryckligen som ett av de säkerhetsområden som berörda organisationer måste kunna redogöra för. Att redan ha en fungerande signeringskedja med loggbar historik, snarare än att börja bygga den när en tillsynsmyndighet efterfrågar den, sparar både tid och trovärdighet. Team som väntar tills kravet blir akut brukar upptäcka att det tar veckor att retroaktivt reda ut vilka byggpipelines som faktiskt producerade vilka images, medan de som redan kör cosign i sin release-process kan svara på samma fråga inom minuter.

Vanliga frågor

Vad är skillnaden mellan cosign och Docker Content Trust?
Docker Content Trust bygger på Notary och kräver att du själv hanterar och roterar långlivade nycklar. Cosign stödjer samma sak, men dess keylösa läge tar bort behovet av att lagra hemliga nycklar över huvud taget genom att använda kortlivade certifikat kopplade till en identitet.

Kostar det något att använda Sigstore och cosign?
Nej, den publika infrastrukturen (Fulcio och Rekor) drivs som ett fritt, allmännyttigt projekt under Linux Foundation, och cosign är öppen källkod. Stora företag kan välja att köra en privat instans internt, men det är valfritt.

Fungerar cosign med privata containerregister?
Ja, så länge registret stödjer OCI-artefakter och du är autentiserad mot det på samma sätt som du redan gör för push och pull av images. De flesta större register, inklusive GitHub Container Registry, Amazon ECR, Azure Container Registry och Google Artifact Registry, stödjer det här sedan flera år tillbaka.

Vad händer om jag förlorar min privata nyckel vid nyckelbaserad signering?
Du behöver återkalla den offentliga nyckeln överallt där den används för verifiering och signera om berörda images med en ny nyckel. Det är just den typen av administrativa börda som keylös signering är tänkt att eliminera helt.

Är keylös signering säker nog för produktionsmiljöer med höga krav?
Ja, förutsatt att verifieringen alltid låser identitet och utfärdare. Säkerheten flyttas från att skydda en hemlig nyckel till att skydda din OIDC-identitetsleverantör, vilket för de flesta organisationer redan är bättre skyddat och övervakat. Många team med särskilt höga krav väljer ändå att kombinera keylös signering med den policykontroll i klustret som beskrivs i avsnittet om avancerade tips, som ett andra oberoende skyddslager.

Måste hela teamet lära sig cosign-kommandon i vardagen?
Nej, signering och verifiering ska automatiseras i pipeline och admission controller. Utvecklare märker normalt bara av det när något stoppas och behöver felsökas. Det är ändå värt att någon i teamet, till exempel den som äger release-processen, känner till kommandona i den här guiden tillräckligt väl för att kunna felsöka utan att behöva googla från grunden mitt i en pågående incident.

Kan jag signera images retroaktivt, för sådant som redan ligger i registret?
Ja, cosign kan signera vilken existerande digest som helst i registret, men signaturen bevisar bara att signeringen skedde nu, inte att exakt den koden faktiskt byggdes av den angivna pipelinen historiskt.

Saktar signering ner byggtiden märkbart?
Normalt handlar det om några sekunder per signeringssteg, försumbart jämfört med den totala byggtiden för de flesta pipelines. Nätverksanropen mot Fulcio och Rekor är det som tar längst tid, och de körs parallellt med resten av bygget i en välkonfigurerad pipeline snarare än sekventiellt efter den.

Sammanfattningsvis handlar det här inte om ett enskilt verktyg, utan om att flytta tilliten från “vi antar att den här imagen är okej” till “vi kan bevisa exakt varifrån den kom”. Ingen av stegen i den här guiden kräver stora investeringar eller en omskriven arkitektur, de flesta team kan gå från noll till en fullt signerad och verifierad release-pipeline på en eller två arbetsdagar. Det som tar längre tid är att, som i Nordvakt-exemplet, koppla på policykontroll i klustret och bygga upp rutinerna för granskning av Rekor-loggen, men även det arbetet betalar sig snabbt tillbaka första gången ni behöver svara på en revisionsfråga om var en viss image kom ifrån.

Relaterat innehåll

Läs mer om angränsande ämnen i vår bevakning av cybersäkerhet:

Se även vår samlade bevakning på säkerhetssidan för fler analyser av sårbarheter och praktiska härdningsguider.

Källor och vidare läsning: Sigstores officiella översikt, cosigns dokumentation för containersignering, cosigns releaser på GitHub, SLSA:s build-nivåer och MSB:s vägledning om digitala leveranskedjor.