Hoppa till huvudinnehållet

Skanning av container-images

Skanning av container-images svarar på frågan vad i den här imagen är sårbart, som ett komplement till SBOM:ens vad finns i den här imagen. Fynden kommer från två källor, och båda visas bredvid den image eller commit de beskriver.

Så fungerar det

Den dagliga genomsökningen av registryt

fremforge skannar själv container-imagerna i din organisations paketregistry. Du behöver inte lägga till något i dina arbetsflöden.

  • Vad som skannas. Varje tagg på varje container-image. Varje tagg löses upp till sin manifest-digest, och imagen skannas med trivy image efter sårbarheter och läckta hemligheter, inklusive OS-paket och språkberoenden i varje lager.
  • När. En gång om dagen, efter att Trivys sårbarhetsdatabas har uppdaterats. En digest som redan har skannats mot samma databasversion hoppas över, så en nypublicerad CVE tas upp mot en image som inte har ändrats.
  • Var fynden sparas. Med image-digesten som nyckel (frem.sh/<org>/<image>@sha256:<digest>). Avfärdanden följer med när en image skannas om.
  • Begränsningar. För en image med flera arkitekturer skannas bara varianten linux/amd64. En image som är större än 2 GiB (summan av dess lager som de lagras i registryt) hämtas inte, så den skannas inte.

Samma genomsökning skannar också varje repos standardbranch (trivy fs och trivy config).

Samma pull av imagen matchas också mot OSV:s lista över skadliga paket. Den kontrollen beskrivs i Skadliga paket; en pull av en image med ett öppet fynd nekas, oavsett blockeringsåtgärden nedan. Sedan 2026-10-11 gäller samma sak för images som cachas genom beroendeproxyn (se nedan).

Images som cachas genom beroendeproxyn

Images som din organisation hämtar genom beroendeproxyn skannas på samma sätt som de images du pushar.

  • När. En image köas för sin första skanning när din organisation cachar den första gången, och skannas normalt inom 15 minuter. Därefter skannas den om varje gång Trivys sårbarhetsdatabas ändras, i samma dagliga genomsökning som dina egna images, så länge den finns kvar i din cache.
  • Vad som skannas. Den image för en enda plattform som din klient hämtade (för en tagg med flera arkitekturer, den variant du hämtade), med trivy image efter sårbarheter och läckta hemligheter.
  • Var fynden sparas. Med nyckeln frem.sh/<org>/dependency-proxy/<upstream>/<repository>@sha256:<digest>, till exempel .../dependency-proxy/docker.io/library/alpine@sha256:…, bredvid dina egna images under Organisationens administration → Säkerhet › Fynd › Container-images och i Findings API. Avfärdanden följer med när imagen skannas om.
  • Blockeringsåtgärd. block_pull gäller även images via proxyn: en pull genom proxyn av en image med ett fynd på high eller critical som inte har avfärdats nekas med 403 DENIED.
  • Skadliga paket. Språkpaketen i en cachad image matchas mot OSV:s advisories om skadliga paket, precis som för pushade images, och en träff blir ett fynd på fliken Skadlig kod. Sedan 2026-10-11 nekas en pull av en cachad image med ett öppet fynd, precis som för en pushad image; se Beroendeproxy.
  • Delade skanningar. En image identifieras av sin digest, så när flera organisationer cachar samma image skannas den en gång, och varje organisation får sin egen kopia av fynden. Du ser bara fynd för images i din egen cache.
  • När en image lämnar din cache. Dess fynd finns kvar så länge imagen fortfarande används: hämtad genom proxyn av din organisation, eller angiven i någon av dina driftsättningar, under de senaste 30 dagarna (åtkomstloggen för registryt och driftsättningsposterna visar vilka). Därefter tas de bort vid nästa genomsökning. En image som hämtas igen efter att dess fynd har tagits bort får tillbaka dem vid nästa genomsökning, från skanningen av dess digest.

Images som dina Helm-charts driftsätter

De images som ett Helm-chart i ditt repo driftsätter skannas efter sårbarheter, och fynden rapporteras i repots kontroll fremforge/image-scan.

  • Vad som läses. Varje chart i repot, det vill säga varje katalog med en Chart.yaml. I values.yaml: en image: med en referens (image: nginx:1.25.3), och den uppdelade form som charts oftast använder (image: med registry, repository, tag och digest under sig). En uppdelad image utan tagg, eller med tag: "", är chartets appVersion, vilket är vad {{ .Values.image.tag | default .Chart.AppVersion }} driftsätter. I templates/: en image:-rad med en literal referens. Nycklar som initImage eller sidecarImage räknas också; imagePullPolicy och imagePullSecrets gör det inte.
  • Vad som inte läses. Mallar renderas inte och ingen chart-kod körs, så en image som sätts ihop av mallogik, andra values-filer än values.yaml (en overlay du väljer vid installationen) och beroende charts som inte finns i repot täcks inte. En referens utan registry är Docker Hub (nginx är docker.io/library/nginx), och en utan tagg är latest.
  • Hur imagen hämtas. Genom din organisations beroendeproxy, på samma sätt som en pull av dig skulle göras: dina inloggningsuppgifter för upstream, paketpolicy, skanning efter skadlig kod och cache gäller. Om din organisation inte har någon beroendeproxy hämtar fremforges egen proxy den, anonymt och bara från register som tillåter det (till exempel ghcr.io, quay.io, registry.k8s.io). En image som din proxy nekar (till exempel en som din policy blockerar) skannas inte. Imagen för linux/amd64 skannas med trivy image, efter sårbarheter.
  • Docker Hub kräver dina egna inloggningsuppgifter. Images från Docker Hub hämtas bara med din organisations egna inloggningsuppgifter för Docker Hub, aldrig anonymt och aldrig med ett fremforge-konto. Utan dem skannas inte en Docker Hub-image i ett chart: statusen fremforge/image-scan säger det (“N Docker Hub image(s) in Helm charts not scanned: add your Docker Hub credential”), och Säkerhet › Fynd › Container-images listar imagerna med en länk för att lägga till inloggningsuppgifterna under Inloggningsuppgifter för upstream. Imagerna skannas när du har lagt till dem, från repots nästa skanning; fynd som skannats för en annan organisation visas aldrig för din.
  • När. En image köas första gången en skanning nämner den, och skannas normalt inom 15 till 30 minuter; dess fynd visas vid repots nästa skanning. En image som fortfarande nämns skannas igen med några dagars mellanrum, eftersom en tagg kan flyttas och nya advisories publiceras.
  • Hur ett fynd ser ut. Målet är chart-filen och imagen, till exempel charts/web/values.yaml: docker.io/library/nginx:1.19.0, med paketet, dess version och den åtgärdade versionen. Fynden går genom tröskeln och avfärdandena för image-skanningen, och en pull request blockeras bara av fynd som den själv lägger till.

Nyare taggar för upstream-images

En image som du hämtar från upstream har ingen egen Dockerfile som du kan åtgärda, så fremforge letar efter en nyare tagg som åtgärdar dess fynd. För varje cachad image med öppna fynd på high eller critical, högst en gång om dagen:

  1. Taggen du hämtade. Digesten matchas mot den tagg din organisation hämtade den med, via indexet för flera arkitekturer när det finns ett.
  2. Kandidaten. Det här är den nyaste taggen i samma serie, som har samma form och samma siffror utom den sista: 3.12.4-slim till 3.12.10-slim, eller 16.4 till 16.10. Det är aldrig en annan major- eller minor-version, eftersom det är en migrering snarare än en åtgärd. En tagg utan en sådan serie, som 3.12-slim, 16 eller pg17, kontrolleras i stället för en ombyggnad: samma tagg, ombyggd upstream sedan du hämtade den.
  3. Vad den åtgärdar. Kandidaten hämtas och skannas med samma skanner. Varje öppet fynd hos dig som kandidaten inte längre har räknas som åtgärdat.

Fyndet säger sedan något av följande:

VisasBetydelse
Nyare tagg <tag> åtgärdar N av imagens fyndByt till den taggen. Öppna PR med <tag> öppnar pull requesten nedan
Ombyggd upstream: hämta <tag> igen så åtgärdas N av imagens fyndSamma tagg är nyare upstream. Hämta den igen; inget ändras i ditt repo om inte en referens fäster en digest
Upstream-image, ingen nyare åtgärdad taggIngen tagg i samma serie, och ingen ombyggnad, har färre av de här fynden
Upstream-image: nyare taggar har inte kontrollerats änInte kontrollerad än, eller så är registryt inte ett som fremforge läser taggar från (Docker Hub, GHCR, Quay, MCR, ECR Public och registry.k8s.io är det)

Samma sak finns i Findings API som upstream_update.

Pull requesten. Öppna PR med <tag>, eller POST /orgs/{org}/dependency-updates/security-fixes/image-ref-requests med image_finding_id, söker i din organisations repon efter referenser till imagen med den tagg du hämtade. Det omfattar docker compose-filer, Kubernetes-manifest, Helm-values med repository: och tag: på separata rader, och CI-posterna image: och container:, under vilket som helst av de namn imagen har:

  • frem.sh/<org>/dependency-proxy/docker.io/library/python:3.12.4-slim
  • docker.io/library/python:3.12.4-slim
  • python:3.12.4-slim

Varje repo som har en referens får en pull request med en säkerhetsfix som flyttar alla dess referenser. En fäst digest flyttas till kandidatens digest. Den har den vanliga branchen, etiketten, gränserna och merge-inställningen. En FROM i en Dockerfile ändras inte här: det är åtgärden för bas-imagen. När inget repo refererar till imagen öppnas ingenting, och fyndet fortsätter att visa den tagg som åtgärdar det. Upp till 60 repon och 400 YAML-filer läses per begäran.

Skanna från ditt eget arbetsflöde

Du kan också skanna i CI och skicka in resultaten. fremforges runner-image levereras med Trivy. Det här exemplet skannar repots filsystem (trivy fs — beroenden + läckta hemligheter) och IaC-konfigurationen (trivy config — Dockerfiles, Compose-filer), och skickar sedan fynden med POST:

- name: Scan + push findings
  run: |
    trivy fs --format json --output trivy-fs.json .
    trivy config --format json --output trivy-config.json .
    curl -sS --fail \
      -H "Authorization: Bearer ${{ secrets.FREMFORGE_API_TOKEN }}" \
      -H 'Content-Type: application/json' \
      -d @<(jq -c '{
        image_ref: "'"${GITHUB_REPOSITORY}@${GITHUB_SHA}"'",
        commit_sha: "'"${GITHUB_SHA}"'",
        repo_full_name: "'"${GITHUB_REPOSITORY}"'",
        findings: [.Results[].Vulnerabilities[] | {
          cve_id: .VulnerabilityID,
          severity: (.Severity|ascii_downcase),
          package_name: .PkgName,
          installed_version: .InstalledVersion,
          fixed_version: .FixedVersion,
          title: .Title,
          target: .PkgPath
        }]
      }' trivy-fs.json) \
      "https://frem.sh/_app/api/v1/image-scans/findings"

PAT:en behöver behörigheten findings:write.

Policyinställningar

Säkerhet › Policyer › Image-policyer innehåller de här inställningarna (fram till 2026-10-15 låg de under Fynd › Container-images):

  • Aktiverad — när den är av svarar inläsningen 202 {accepted: 0, status: 'disabled'} (resultatet tolkas fortfarande, men kastas). Användbart för team före lansering som vill att skanningen körs men inte blockerar.
  • Blockeringsåtgärd — none | warn | block_pull:
    • none — sparar fynd, postar ingen commit-status. Bara upptäckt på byggsidan. Pulls kontrolleras inte.
    • warn — sparar fynd, postar commit-statusen success med en beskrivning som anger antalet. Merge av pull requests blockeras inte. Pulls kontrolleras men nekas aldrig: en pull som block_pull skulle neka levereras och registreras som would_block i åtkomstloggen för registry och som granskningshändelsen registry.pull.would_block (se Granskningslogg och SIEM).
    • block_pull — sparar fynd, postar commit-statusen failure när det finns minst ett fynd som inte har avfärdats på eller över din blockeringströskel. På en pull request räknas bara fynd som pull requesten inför (se Pull requests: bara nya fynd blockerar). Branch-skydd med den obligatoriska statuskontrollen fremforge/image-scan blockerar sedan merge. Den blockerar också pulls: en docker pull (med tagg eller digest) av en image med ett sådant fynd nekas med 403 DENIED, och meddelandet anger tröskeln och länkar till fynden. Avfärda eller åtgärda fynden för att häva blockeringen. Varje nekande är granskningshändelsen registry.pull.blocked.
  • Kräv signerade images — när den är på tar inläsningen också emot fältet signature_status (signed / unsigned / unknown). Osignerade images (eller signerade images från en utfärdare som inte finns på listan över tillåtna) får ett syntetiskt critical-fynd, så att samma väg för att blockera pull upprätthåller signeringspolicyn. Se Cosign för signeringssidan.

Blockeringströskel

De fynd som blockerar är de som ligger på eller över en allvarlighetsgrad, som ställs in per organisation. Det är block_severity i posten image_scan i din organisationsövergripande skanningspolicy, samma inställning för merge och för pulls:

block_severityBlockerar vid
criticalcritical
high (standard)high och critical
mediummedium, high och critical
lowalla fynd

Ställ in den med PUT /_app/api/v1/orgs/<org>/policy:

curl -X PUT -H "Authorization: Bearer ${FREMFORGE_PAT}" -H 'Content-Type: application/json' \
  -d '{"scan_policy": {"image_scan": {"mode": "enforce", "block_severity": "critical"}}}' \
  "https://frem.sh/_app/api/v1/orgs/acme/policy"

eller i konfiguration som kod som scan_policy = { image_scan = { mode = "enforce", block_severity = "critical" } }. null, eller ingen post image_scan, betyder high, vilket är vad alla organisationer hade innan tröskeln gick att ställa in. Alla andra värden avvisas med 400. Token behöver policy:write. Konsolen har ingen kontroll för det än.

Bara den organisationsövergripande posten räknas. En åsidosättning av skanningspolicyn per repo kan innehålla en block_severity, men en pull av en image är inte knuten till ett repo, så image-spärrarna läser den inte.

Pull requests: bara nya fynd blockerar

Kontrollen fremforge/image-scan på en pull request underkänns bara av fynd som pull requesten inför. fremforge jämför pull requestens fynd på eller över din blockeringströskel med den senaste skanningen av den branch som den mergas in i. Ett fynd som den branchen redan har blockerar inte, så en pull request som inte ändrar något sårbart kan mergas i ett repo som har öppna fynd. Statusen lyder då till exempel No new high/critical findings; 7 already on main.

  • Ett fynd är detsamma när dess advisory, dess paket och dess fil är desamma, den identitet som ett avfärdande följer med på. Samma advisory i en annan fil är ett nytt fynd.
  • En pull request som lägger till ett nytt fynd på high i ett repo med många befintliga underkänns: 1 new high/critical finding(s) …; merge blocked; 30 already on main.
  • En pull request som åtgärdar några fynd och inte lägger till några godkänns.
  • Befintliga fynd döljs inte. De listas, räknas mot din SLA och spärrar pulls av images som tidigare.

Branchen skannas efter en push till din standardbranch, högst en gång i timmen, och den senaste pushen vinner. Ett fynd som har nått branchen sedan dess senaste skanning räknas därför fortfarande som pull requestens fram till nästa skanning. Det är aldrig tvärtom: ett nytt fynd tas aldrig för ett befintligt.

När det inte finns någon skanning av den branch som pull requesten mergas in i blockerar alla fynd på eller över tröskeln, som tidigare. För standardbranchen begär den pull requestens skanning också en skanning av branchen. När branchens första skanning har registrerats skannar fremforge, av sig själv, om de öppna pull requests mot den vars kontroll underkändes under tiden (högst 20 per repo, de senast uppdaterade), så att de blir gröna, eller förblir röda bara för det de lägger till, utan en ny körning eller en ny push. En pull request mot någon annan branch räknar alltid alla fynd.

Spärren för pull av images är oförändrad: en pull av en image med ett fynd som inte har avfärdats på eller över tröskeln nekas under block_pull, oavsett om fyndet är nytt eller inte.

Granskningslogg och SIEM

Varje pull-beslut från image-spärrarna skrivs till din granskningslogg och därifrån till ditt SIEM:

  • registry.pull.blocked — en pull nekades: av block_pull (spärren image_scan), av matchning mot skadlig kod (image_malware), av ett lager som ClamAV fann infekterat eller inte kunde skanna (registry_scan, eller registry_blob för ett lager som hämtats direkt via digest), eller av kontrollen av image-signaturer (signature).
  • registry.pull.would_block — en pull levererades som någon av de spärrarna skulle ha nekat: under din warn, eller medan en spärr körs i observationsläge.

Det finns en händelse per image-digest, spärr och beslut per timme; nästa händelse för samma digest bär föregående timmes antal.

Var fynden visas

Organisationens administration → Säkerhet › Fynd › Container-images listar skanningar efter image-referens + commit + PR. Varje rad visar:

  • Antal per allvarlighetsgrad (critical / high / medium / low)
  • Antal som går att åtgärda (fynd med en fixed_version som inte är null)
  • Status (success / failure / skipped) + den commit-status som postades
  • Länkar till advisories upstream (CVE, GHSA när den finns)

Hur ett fynd ser ut i databasen

Fält som sparas per fynd: cve_id, severity, package, installed_version, fixed_version, target (filsökvägen i imagen) och det scan_run_id som knyter ihop fynd från samma körning. Hela Trivy-utdata sparas INTE — bara raderna per fynd, vilket är den form som går att fråga mot.

Lagringstid

Fynd följer tenantens policy för lagringstid i granskningsloggen. Fynd som har passerat lagringstiden behåller sin hash i kedjan (manipuleringsskydd) men förlorar innehållet per rad.

Se även

  • Skadliga paket — samma pull av imagen matchas också mot OSV:s MAL-*-advisories; en pull av en image med ett öppet fynd nekas oavsett blockeringsåtgärden ovan.
  • Cosign — signering av images + policy för signerade images.
  • SBOM:er — paketinventering i imagen (oberoende av sårbarhetsläget).
  • OSV-rekommendationer — komplementet på källsidan (sårbarheter i dina beroenden innan de levereras).
  • API-referens — inläsningsendpointen POST /_app/api/v1/image-scans/findings (avgränsad per tenant via runnerns PAT).