Dependency-proxy
De dependency-proxy is een pull-through-cache voor publieke registries, per organisatie. Je richt
docker, npm, pip, uv, dnf, Maven, NuGet, go, helm of cargo op het proxypad van je organisatie op frem.sh, en fremforge haalt
namens jou op uit de publieke registry:
- De eerste pull van een imagelaag of pakketbestand wordt bij de upstream opgehaald en gecontroleerd tegen de eigen hash van de upstream. Zet je organisatie malwarescanning aan, dan wordt het bestand ook met ClamAV gescand terwijl het naar je toe streamt. Een bestand dat een controle niet doorstaat, wordt nooit geleverd en nooit opgeslagen.
- Latere pulls worden geleverd uit de opslag van fremforge in de EU, voor elk lid van je organisatie.
- Is de upstream onbereikbaar, dan wordt de laatste goede kopie geleverd. Tags, npm-packuments, PyPI-indexen,
RPM-
repomd.xml, Maven-maven-metadata.xml, versielijsten en registraties van NuGet, versielijsten en@latestvan Go, Helm-index.yaml-bestanden en indexbestanden van Cargo worden beantwoord vanuit de laatste goede kopie, met de responsheaderX-Fremforge-Proxy: stale. Zie Storingen bij de upstream. - Het pakketbeleid van je organisatie en de controles op kwaadaardige pakketten worden toegepast op pakketten en images via de proxy, en elke pull wordt vastgelegd in je registertoegangslog. Sinds 2026-10-11 wordt een bekend kwaadaardig pakket of image voor elke organisatie geweigerd, en een beleid in de modus Afdwingen weigert wat ertegen ingaat; zie Wat vandaag wordt afgedwongen.
De proxy is alleen-lezen. Je kunt er niet naar pushen.
Beschikbaarheid en inschakelen
De proxy is beschikbaar in elk abonnement en staat voor elke organisatie standaard aan. Een
eigenaar van de organisatie kan hem uitzetten of de instellingen wijzigen onder Bouwen en uitrollen › Proxy voor
afhankelijkheden of via de API (een token met de scope policy:write):
curl -X PUT -H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
-d '{"enabled": true, "malware_scan": true}' \
https://frem.sh/_app/api/v1/orgs/<org>/dependency-proxyEen organisatie die deze instellingen nooit heeft opgeslagen, heeft de standaard: de proxy aan, en gehoste runners die erdoorheen ophalen (zie Gehoste runners). Zodra een eigenaar ze opslaat, houdt de organisatie precies wat er is opgeslagen.
Malwarescanning (malware_scan) staat standaard uit. Staat het aan, dan wordt elke imagelaag,
elk pakketbestand en elke chart die je organisatie via de proxy ophaalt met ClamAV gescand, ook
als een andere organisatie het eerder zonder scan heeft gecachet: die kopie wordt één keer gescand, de
eerste keer dat een organisatie die scant hem gebruikt, en het oordeel geldt daarna voor iedereen. Pakketbestanden
en charts worden gescand voordat ze worden geleverd; voor imagelagen, zie
Containerimages. Bekende kwaadaardige pakketten (OSV-advisories MAL-*) worden voor elke organisatie gematcht,
wat deze instelling ook zegt. Dezelfde pagina en hetzelfde endpoint stellen block_until_scanned in voor
containerimages, waarvoor malwarescanning aan moet staan (zie
Containerimages), en retention_days (7 tot 365, standaard 90; zie
Bewaartermijn). Een GET op het endpoint toont of de proxy aan staat, je gebruik en
je limiet.
Authenticatie
Gebruik dezelfde inloggegevens als voor het pakketregister:
- Mensen: een persoonlijk toegangstoken met
read:package(of het kortlevende token datfremforge authaan je tools geeft). Je moet lid zijn van de organisatie. - CI: het jobtoken van Forgejo Actions. Een jobtoken haalt alleen op via de organisatie van zijn eigen repository; de proxy van elke andere organisatie weigert het. Jobs uit pull requests van forks mogen ophalen, maar nooit via een upstream die de eigen inloggegevens van je organisatie gebruikt.
- Externe CI, buildhosts en pull secrets: een registryrobot
met leestoegang. Zijn token is een
read:package-credential zoals elk ander. - De dependency-scan van fremforge: de bereikbaarheidsanalyse leest npm-tarballs, PyPI-wheels en Maven-JAR’s via de proxy van je organisatie, via een interne route die alleen de scandienst bereikt. De licentiecontrole, de controle op de leeftijd van de release en de modulegraaf van Go lezen registrymetadata (npm, PyPI, Go, Maven Central, RubyGems en Packagist) op dezelfde manier. Dit is alleen-lezen, kan niet van buiten fremforge worden gebruikt, en krijgt je pakketbeleid, cache en opslaglimiet zoals elke andere pull.
Gehoste runners
Standaard installeren jobs op door fremforge gehoste runners via de proxy van je organisatie
(runner_pull_through, standaard aan). Bij de start van elke job richt de runner npm, pip en uv op
de proxy, en ook Go, Maven, NuGet en de kwetsbaarheidsdatabase van Trivy voor de ecosystemen
in runner_pull_through_ecosystems (standaard alle vier). De job authenticeert met
zijn eigen jobtoken, dus elke installatie doorloopt je pakketbeleid en malwarecontroles en staat in
je toegangslog met de repository van de job. Is de proxy bij de start van de job niet bereikbaar,
dan installeert de job in plaats daarvan uit de publieke registries via de egressproxy van fremforge, en de
terugval wordt gelogd. Zet runner_pull_through op false om dit uit te zetten. Zie ook
Pakketcaches.
Containerimages. Voor dezelfde jobs haalt ook de Docker-daemon van de job containerimages
via de proxy van je organisatie op: docker pull, docker run, de FROM van een Dockerfile, en de
job- en services:-containers die de runner start. In de workflow verandert niets; de imagenamen
blijven zoals ze zijn (ghcr.io/..., quay.io/...) en elke pull wordt voor je
organisatie gecachet en in je toegangslog vastgelegd.
- Voor elke organisatie:
ghcr.io,quay.io,mcr.microsoft.com,registry.k8s.io,public.ecr.awsenregistry.access.redhat.com. - Alleen met de eigen inloggegevens van je organisatie:
docker.io,registry.redhat.ioenregistry.connect.redhat.comgaan pas via de proxy wanneer een eigenaar de inloggegevens van je organisatie voor die registry heeft toegevoegd onder Upstream-inloggegevens. Jobs uit pull requests van forks gebruiken ze nooit, dus hun pulls uit deze registries gaan rechtstreeks naar de registry. Zonder inloggegevens zijn pulls van Docker Hub anoniem en vallen ze onder de rate limits van Docker Hub. - Terugval: de proxy wordt aan het begin van elke job gecontroleerd. Is hij niet bereikbaar, dan haalt de job elk image rechtstreeks uit de registry, zoals voorheen, en de terugval wordt gelogd. Een enkele pull die de proxy niet kan leveren, valt ook terug op de registry.
- Een cache, geen poort: voor images op dit pad valt een pull die je pakketbeleid of de malwarecontrole
weigert ook terug op de registry. Moet een weigering de pull tegenhouden, haal dan expliciet op uit
frem.sh/<org>/dependency-proxy/<registry>/<image>(hieronder). - Niet gedekt: een
docker buildx-builder die de driverdocker-containergebruikt, draait zijn eigen BuildKit en haalt rechtstreeks op. De standaarddriverdockergaat via de proxy.
Containerimages
docker login frem.sh # a token with read:package, as for the registry
docker pull frem.sh/<org>/dependency-proxy/<upstream>/<image>:<tag>Bijvoorbeeld:
docker pull frem.sh/acme/dependency-proxy/quay.io/prometheus/busybox:latestIn CI:
echo "$GITHUB_TOKEN" | docker login frem.sh -u x --password-stdinDe upstreams waaruit je kunt ophalen:
| Upstream | Inloggegevens | Status |
|---|---|---|
docker.io | De eigen Docker Hub-inloggegevens van je organisatie, verplicht (hieronder) | End-to-end geverifieerd |
registry.k8s.io, mcr.microsoft.com, public.ecr.aws, registry.access.redhat.com | Geen | End-to-end geverifieerd |
ghcr.io, quay.io | Geen voor publieke images. De eigen inloggegevens van je organisatie, optioneel, voor privé-images (hieronder) | Publieke images: end-to-end geverifieerd. Privé-images met je inloggegevens: ondersteund, nog niet geverifieerd |
registry.redhat.io, registry.connect.redhat.com | Het serviceaccount van je organisatie voor de Red Hat-registry, verplicht | Ondersteund, nog niet geverifieerd: daarvoor is een Red Hat-account nodig, en fremforge heeft er geen om mee te testen |
Elke andere host wordt geweigerd: de proxy haalt nooit een vrij opgegeven URL op.
De proxy toont de tags van een image niet. Gehoste Renovate stelt nog steeds updates voor van een image
waarnaar je via dit pad verwijst, zoals een Dockerfile-FROM frem.sh/<org>/dependency-proxy/docker.io/library/python:3.14-slim.
Renovate zoekt nieuwe tags en digests op bij de upstream-registry en schrijft ze in je
verwijzing, die het proxypad behoudt. Je builds blijven via de proxy ophalen, dus de
pull-controles hieronder blijven gelden.
Helm-charts die als OCI-artefacten op deze upstreams staan, komen via hetzelfde pad (Helm 3.8 of later):
echo "$FREMFORGE_TOKEN" | helm registry login frem.sh -u <user or robot name> --password-stdin
helm pull oci://frem.sh/<org>/dependency-proxy/ghcr.io/prometheus-community/charts/prometheus --version 29.36.1Voor charts in een klassieke Helm-repository (index.yaml), zie Helm-charts.
Een tag wordt hoogstens één keer per minuut opnieuw bij de upstream gecontroleerd, met een HEAD-verzoek, dat
Docker Hub niet meetelt voor zijn pull-limiet. Imagelagen doorlopen dezelfde pull-controles als images die naar
je register zijn gepusht: met malwarescanning aan worden geïnfecteerde of onscanbare lagen geweigerd, en ook images boven je CVE-drempel
als je block_pull instelt. Kwaadaardige pakketten in een image worden
hieronder behandeld. Standaard
wordt een image geleverd terwijl zijn lagen worden gescand. Met block_until_scanned antwoordt de
eerste pull van een nog niet gescand image, of van een laag op digest, 503 met
Retry-After totdat de scan klaar is, meestal binnen enkele seconden. Een laag die bij een scan
geïnfecteerd bleek, wordt aan elke organisatie geweigerd.
Terwijl één verzoek een laag ophaalt en scant, wachten andere pulls van dezelfde laag daarop.
Duurt dat langer dan ongeveer vier minuten, dan krijgen ze 503 met Retry-After: 30
(this layer is still being fetched and malware-scanned by another request), en een nieuwe poging wordt
geleverd zodra de laag is opgeslagen. Een scan die door zijn tijd heen raakt, is geen oordeel: de laag wordt
achtergehouden, zoals een onscanbare, maar er wordt geen resultaat vastgelegd. Ze wordt in de wachtrij gezet voor de
laagscanner van fremforge op de achtergrond, die meer tijd heeft, en een latere pull wordt geleverd zodra die
scan slaagt.
Een pakketbestand waarvoor de scantijd opraakt (npm, PyPI, RPM, Maven, NuGet, Go, Cargo of een Helm-chart), wordt op dezelfde manier behandeld: dat verzoek wordt geweigerd, er wordt geen resultaat vastgelegd en het bestand wordt in de wachtrij gezet voor dezelfde achtergrondscanner. Een later verzoek wordt geleverd zodra die scan slaagt, of geweigerd als die het bestand geïnfecteerd vindt. Een RPM-pakket blijft van je organisatie zolang het wacht: het wordt alleen in de eigen ruimte van je organisatie opgeslagen en gescand, en een andere organisatie die hetzelfde RPM-pakket ophaalt, haalt een eigen kopie op en scant die.
Groottelimieten. De proxy levert geen laag of bestand groter dan 10 GiB (403). ClamAV leest
hoogstens 4 GiB van één bestand, dus met malwarescanning aan kan een grotere laag of een groter bestand niet volledig
worden gescand en wordt het achtergehouden, behalve een modellaag in safetensors of GGUF die de formaatcontrole doorstaat
(zie Modelscanning).
Kwaadaardige pakketten in gecachete images
De taalpakketten in elk image dat je organisatie cachet (npm-, PyPI-, Maven-, Go-, crates-,
RubyGems-, NuGet-, Packagist-, Pub- en Hex-pakketten) worden gematcht tegen de OSV-advisories voor kwaadaardige pakketten
(MAL-*), dezelfde controle die draait op de images die je pusht:
- nadat het image voor het eerst is gecachet, meestal binnen de volgende scancyclus (ongeveer 15 minuten), en
- daarna elke dag opnieuw, zodat een advisory die is gepubliceerd nadat je het image ophaalde toch wordt gevonden.
Een match is een kritieke bevinding onder Beveiliging › Bevindingen › Afhankelijkheden › Malware, vermeld als
een image met de naam <org>/dependency-proxy/<upstream>/<repository> en de digest die het
bevat, en ze wordt gestuurd naar de mensen die je beveiligingsmeldingen ontvangen. Afwijzen werkt zoals bij
elke malwarebevinding, met een reden en een optionele einddatum. De bevinding sluit vanzelf
zodra je organisatie dat image niet meer cachet, bijvoorbeeld nadat de bewaartermijn het heeft verwijderd.
Een pull van een image met een openstaande, niet-afgewezen bevinding wordt geweigerd met 403 DENIED, zoals bij
gepushte images, en in je toegangslog vastgelegd als blocked met de reden image_malware.
Geweigerd sinds 2026-10-11; daarvoor werd zo’n pull geleverd en vastgelegd als would_block.
Upstream-inloggegevens
Docker Hub (docker.io) en de Red Hat-registries (registry.redhat.io en
registry.connect.redhat.com, de gecertificeerde partnerimages van Red Hat) worden alleen via de
dependency-proxy opgehaald met het eigen account van je organisatie. Voor GitHub (ghcr.io) en Quay
(quay.io) zijn inloggegevens optioneel: zonder worden ze anoniem opgehaald, wat
publieke images levert; voeg ze toe om je privé-images op te halen. Een eigenaar van de organisatie voegt de inloggegevens toe
onder Bouwen en uitrollen › Proxy voor afhankelijkheden › Upstream-inloggegevens, of via de API op
/_app/api/v1/orgs/<org>/dependency-proxy/upstreams. Geaccepteerde vormen:
- Docker Hub: je gebruikersnaam plus een persoonlijk toegangstoken, of een organisatietoegangstoken met de naam van de Docker-organisatie als gebruikersnaam.
- Red Hat: een registry-serviceaccount (een gebruikersnaam zoals
1234567|ci, plus het token), of het bijbehorende OpenShift-pull secret. Voeg het één keer toe per Red Hat-registry waaruit je ophaalt; elke registry bewaart alleen zijn eigen deel van het pull secret. - GitHub (
ghcr.io): je GitHub-gebruikersnaam plus een persoonlijk toegangstoken (classic) metread:packages. - Quay (
quay.io): een robotaccount (organisation+robot) plus het token, of hetquay.io-deel van een Red Hat-pull secret.
De Red Hat-registries met je inloggegevens, en privé-images op ghcr.io en quay.io, worden
ondersteund maar zijn nog niet end-to-end geverifieerd: fremforge heeft ze getest tegen de
tokenflow van de registries, maar heeft geen account om mee op te halen.
Zodra inloggegevens voor ghcr.io of quay.io zijn opgeslagen, gebruikt elke pull uit die registry ze,
ook voor publieke images, en wordt alles alleen voor je organisatie gecachet. Jobs uit pull requests van forks
gebruiken ze nooit: zij halen anoniem op uit die twee registries, en krijgen dus alleen publieke images.
Het secret wordt versleuteld opgeslagen en alleen door de dependency-proxy gebruikt, voor de pulls van je eigen organisatie. Het wordt nooit meer getoond; je ziet in plaats daarvan een fingerprint. Verbinding testen controleert het en toont voor Docker Hub hoeveel pulls er nog over zijn in je huidige limietvenster.
Images die met je inloggegevens zijn opgehaald, worden alleen voor je organisatie gecachet en nooit aan een andere organisatie geleverd. Jobs uit pull requests van forks kunnen niet ophalen via een registry die je inloggegevens vereist. Verlopen de inloggegevens, dan worden al gecachete images nog steeds geleverd en toont de status Geweigerd door het register. Zonder inloggegevens wordt een pull van Docker Hub geweigerd met een melding die dat zegt.
Kubernetes en OpenShift
Richt een mirror op de proxy. containerd, in /etc/containerd/certs.d/quay.io/hosts.toml:
server = "https://quay.io"
[host."https://frem.sh/v2/<org>/dependency-proxy/quay.io"]
capabilities = ["pull", "resolve"]
override_path = trueOpenShift, met een ImageTagMirrorSet (en een ImageDigestMirrorSet voor digests):
apiVersion: config.openshift.io/v1
kind: ImageTagMirrorSet
metadata:
name: frem-sh-dependency-proxy
spec:
imageTagMirrors:
- source: quay.io
mirrors:
- frem.sh/<org>/dependency-proxy/quay.ioHet pull secret van het cluster heeft een frem.sh-token met read:package nodig.
npm
.npmrc in je project of je homedirectory:
registry=https://frem.sh/_app/proxy/<org>/npm/
//frem.sh/_app/proxy/<org>/npm/:_authToken=${FREMFORGE_TOKEN}Gebruik daarna npm, pnpm of yarn zoals gewoonlijk. Pakketten komen van registry.npmjs.org, inclusief
pakketten met een scope. Elke tarball moet overeenkomen met de integrity (sha512) die de npm-registry
ervoor publiceert, voordat hij wordt geleverd.
npm audit en pnpm audit werken tegen de proxy. Ze worden beantwoord vanuit de eigen
kopie van fremforge van de OSV-advisorydatabase, dus je lijst met dependencies wordt niet naar een
advisorydienst van derden gestuurd. Ondersteunde clients en het antwoordformaat staan beschreven onder
npm audit en pnpm audit via de dependency-proxy.
Om de proxy te combineren met pakketten die je organisatie in haar eigen register publiceert, stuur je je scope naar het register en al het andere naar de proxy:
registry=https://frem.sh/_app/proxy/<org>/npm/
@<your-scope>:registry=https://frem.sh/api/packages/<org>/npm/
//frem.sh/_app/proxy/<org>/npm/:_authToken=${FREMFORGE_TOKEN}
//frem.sh/api/packages/<org>/npm/:_authToken=${FREMFORGE_TOKEN}PyPI
pip install --index-url "https://<user>:${FREMFORGE_TOKEN}@frem.sh/_app/proxy/<org>/pypi/simple/" requests
uv pip install --index-url "https://<user>:${FREMFORGE_TOKEN}@frem.sh/_app/proxy/<org>/pypi/simple/" requestsOf in pip.conf / uv.toml, met de inloggegevens in een netrc-bestand of keyring in plaats van in de
URL. De index wordt geleverd in beide formaten die installers gebruiken (PEP 503 HTML en PEP 691 JSON), met
voor elk bestand de sha256, requires-python, de yank-status en de PEP 658-metadata. Elk bestand moet
overeenkomen met de sha256 die PyPI ervoor vermeldt, voordat het wordt geleverd.
Gebruik de proxy als je enige index. Voeg hem niet toe met --extra-index-url (of
PIP_EXTRA_INDEX_URL, UV_EXTRA_INDEX_URL) naast een andere index, en ook geen andere index naast hem:
het mengen van indexen maakt dependency-confusion-aanvallen mogelijk, omdat de installer een
naam neemt van welke index hem ook aanbiedt. Om pakketten te installeren die je organisatie in haar eigen register publiceert,
voer je een aparte installatie uit met dat register als enige index en --no-deps, of pin je met uv
elk van die pakketten op naam aan dat register vast (explicit = true en [tool.uv.sources]).
RPM (dnf en yum)
Elke repository is bereikbaar op
https://frem.sh/_app/proxy/<org>/rpm/<upstream>/<repository path>Op dit moment is de upstream cdn-ubi.redhat.com, de Universal Base Image-repositories van Red Hat
(UBI 8, 9 en 10: BaseOS, AppStream en CodeReady Builder, voor elke architectuur die Red Hat
publiceert), onder content/public/ubi/. Daarvoor is geen Red Hat-account nodig. Een .repo-bestand voor UBI 9
op x86_64:
[ubi-9-baseos-fremforge]
name=UBI 9 BaseOS through fremforge
baseurl=https://frem.sh/_app/proxy/<org>/rpm/cdn-ubi.redhat.com/content/public/ubi/dist/ubi9/9/x86_64/baseos/os
username=<user or robot name>
password=<token with read:package>
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
[ubi-9-appstream-fremforge]
name=UBI 9 AppStream through fremforge
baseurl=https://frem.sh/_app/proxy/<org>/rpm/cdn-ubi.redhat.com/content/public/ubi/dist/ubi9/9/x86_64/appstream/os
username=<user or robot name>
password=<token with read:package>
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-releasednf stuurt username en password als HTTP Basic-authenticatie. Gebruik een
registryrobot voor buildhosts en imagebuilds, en maak
het bestand alleen leesbaar voor root (chmod 600), omdat het het token bevat. Schakel in een containerbuild
de eigen repositories van het image uit voor de installatie (dnf --disablerepo='*' --enablerepo='*-fremforge' install …), zodat niets buiten de proxy om wordt opgehaald.
Wat de proxy doet:
repodata/repomd.xmlwordt hoogstens elke 5 minuten opnieuw bij de upstream gecontroleerd en precies zo geleverd als de upstream het publiceerde. Een nieuwerepomd.xmlwordt pas geaccepteerd wanneer deprimary.xmldie erin wordt genoemd, is gedownload en overeenkomt met de sha256 en grootte dierepomd.xmlervoor opgeeft. Tot dan, en zolang de upstream onbereikbaar is, wordt de vorige geleverd.- Bestanden met repositorymetadata (
primary,filelists,other,updateinfo,modules,compsen de sqlite-varianten) moeten overeenkomen met de sha256 en grootte inrepomd.xml. - Pakketten moeten overeenkomen met de sha256 en grootte in
primary.xml. Met malwarescanning aan wordt elk pakket ook in zijn gecomprimeerde payload gescand, niet alleen als bestand, en worden ook de installatiescripts gescand. Een pakket dat de scanner niet kan openen, wordt dan geweigerd en niet ongescand geleverd. - Pakkethandtekeningen worden door dnf zelf gecontroleerd (
gpgcheck=1), tegen de sleutel van Red Hat, precies zoals zonder de proxy. De proxy wijzigt nooit een pakket of de repositorymetadata. - RPM-inhoud wordt alleen voor je organisatie gecachet. Een andere organisatie die hetzelfde pakket ophaalt, haalt een eigen kopie op en slaat die op. Zo kan hetzelfde codepad later Red Hat-inhoud leveren die met je eigen Red Hat-abonnement is opgehaald, en die mag nooit bij een andere klant terechtkomen.
Een repository die checksums gebruikt met iets anders dan sha256, wordt niet geleverd. Het proxyen van cdn.redhat.com
met je Red Hat-entitlementcertificaat is gepland en nog niet beschikbaar.
Maven
Maven Central is bereikbaar op
https://frem.sh/_app/proxy/<org>/maven/central/Maak er de mirror van voor elke repository in ~/.m2/settings.xml (of de settings.xml die je
build gebruikt), met de inloggegevens in een <server> met dezelfde id:
<settings>
<servers>
<server>
<id>fremforge-proxy</id>
<username><user or robot name></username>
<password>${env.FREMFORGE_TOKEN}</password>
</server>
</servers>
<mirrors>
<mirror>
<id>fremforge-proxy</id>
<name>Maven Central through fremforge</name>
<url>https://frem.sh/_app/proxy/<org>/maven/central/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
</settings>Maven stuurt de gebruikersnaam en het wachtwoord als HTTP Basic-authenticatie wanneer de proxy erom
vraagt. Om de proxy samen te gebruiken met pakketten die je organisatie in haar eigen register publiceert, schrijf je
<mirrorOf>*,!fremforge</mirrorOf> en declareer je je register
(https://frem.sh/api/packages/<org>/maven) als repository fremforge met een eigen <server>.
Gradle (settings.gradle.kts):
dependencyResolutionManagement {
repositories {
maven {
url = uri("https://frem.sh/_app/proxy/<org>/maven/central/")
credentials {
username = providers.environmentVariable("FREMFORGE_USER").get()
password = providers.environmentVariable("FREMFORGE_TOKEN").get()
}
}
}
}Wat de proxy doet:
maven-metadata.xmlwordt hoogstens elke 5 minuten opnieuw bij Maven Central gecontroleerd. Een nieuwe kopie wordt alleen geaccepteerd als die overeenkomt met de eigen.sha1ervan van Maven Central. Tot dan, en zolang Maven Central onbereikbaar is, wordt de vorige kopie geleverd. De.sha1,.md5,.sha256en.sha512ervan worden berekend uit de kopie die je krijgt, zodat ze er altijd mee overeenkomen.- Artefacten (jars, POM’s,
.module-bestanden en elk ander bestand van een release) moeten overeenkomen met de.sha1van Maven Central en, wanneer Maven Central er een publiceert, met de.sha256. Een bestand zonder een van beide checksums wordt niet opgehaald. Met malwarescanning aan wordt elk bestand gescand terwijl het naar je toe streamt. Een jar wordt ook geopend: een entry die de scanner zelf niet kan uitpakken (zstd), wordt ervoor uitgepakt, en een jar met een entry die geen van beide kan openen (bijvoorbeeld LZMA), wordt geweigerd in plaats van ongescand geleverd. Last-Modifiedis het moment waarop Maven Central het bestand publiceerde, ook wanneer het uit de cache komt, zodat de minimale releaseleeftijd van Renovate en andere tools die het lezen het echte releasemoment zien. Een bestand dat Maven Central zonder deze header stuurde, krijgt helemaal geenLast-Modified, nooit het moment waarop fremforge het cachete. EenHEADop een gecachet bestand antwoordt200met deContent-Lengthen dezeLast-Modified.- Checksumbestanden (
.sha1,.sha256, …) en handtekeningen (.asc) van artefacten worden ongewijzigd doorgegeven. Controleer handtekeningen met de PGP-plugin van je build, zoals je zonder de proxy zou doen. - Snapshots worden niet geleverd. Maven Central publiceert er geen, en een snapshot kan onder
dezelfde versie veranderen. Een
-SNAPSHOT-verzoek wordt beantwoord met404, zodat je build doorgaat naar de repository die hem wel heeft.
Voor het pakketbeleid heet een Maven-pakket groupId:artifactId. Het releasemoment is het moment waarop
Maven Central het bestand publiceerde, en de licentie is de <licenses> die de POM declareert. Een licentie
die van een parent-POM wordt geërfd, wordt niet opgezocht en telt dus als niet beoordeeld.
NuGet
De pakketbron is de service-index van de proxy:
https://frem.sh/_app/proxy/<org>/nuget/v3/index.jsonnuget.config naast je solution:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="fremforge" value="https://frem.sh/_app/proxy/<org>/nuget/v3/index.json" />
</packageSources>
<packageSourceCredentials>
<fremforge>
<add key="Username" value="<user or robot name>" />
<add key="ClearTextPassword" value="%FREMFORGE_TOKEN%" />
</fremforge>
</packageSourceCredentials>
</configuration><clear /> maakt de proxy de enige bron, zodat geen pakket buiten de proxy om wordt opgehaald. NuGet vult
%FREMFORGE_TOKEN% in vanuit de omgeving, dus het token hoeft niet in het bestand te staan. Gebruik daarna
dotnet restore, dotnet add package <id> --version <version> of nuget install zoals gewoonlijk.
Wat de proxy doet:
- De service-index vermeldt alleen resources op
frem.sh: de pakketinhoud (flat container) en de pakketregistratie. Zoeken wordt niet geboden, omdat restore en install het niet nodig hebben.dotnet add packagezonder--versionheeft zoeken nodig, dus geef de versie op. - Versielijsten en registratie worden hoogstens elke 5 minuten opnieuw bij nuget.org gecontroleerd, en de laatste goede kopie wordt geleverd zolang nuget.org onbereikbaar is.
- Pakketten (
.nupkg) moeten overeenkomen met de SHA-512 en grootte die de catalog van nuget.org voor de release vastlegt, voordat ze worden geleverd. Een release waarvan de catalog-entry geen hash bevat, wordt niet opgehaald. Met malwarescanning aan wordt elk pakket gescand terwijl het naar je toe streamt, zowel de inhoud van het pakket als het bestand zelf. - Pakkethandtekeningen worden door de NuGet-client zelf gecontroleerd, precies zoals zonder de proxy. De proxy wijzigt nooit een pakket.
Voor het pakketbeleid heet een NuGet-pakket naar zijn id in kleine letters. Het releasemoment en de
licentie zijn de published-datum van nuget.org en de gedeclareerde licentie-expressie van het pakket. Een
pakket dat zijn licentie als bestand of URL declareert, telt als niet beoordeeld.
Go-modules
export GOPROXY=https://frem.sh/_app/proxy/<org>/go
export GOSUMDB=sum.golang.org # the default; keep it onAuthenticatie komt uit ~/.netrc (_netrc op Windows), dat het go-commando leest voor
frem.sh. Maak het bestand alleen voor jezelf leesbaar (chmod 600 ~/.netrc):
machine frem.sh
login <user or robot name>
password <token with read:package>Gebruik GOPROXY=https://frem.sh/_app/proxy/<org>/go zonder ,direct toe te voegen: met direct
wordt een module die de proxy niet levert buiten de proxy om uit de bronrepository opgehaald.
Wat de proxy doet:
@v/listen@latestworden hoogstens elke 5 minuten opnieuw bijproxy.golang.orggecontroleerd, en de laatste goede kopie wordt geleverd zolang die onbereikbaar is..moden.zipmoeten overeenkomen met deh1:-hashes die de Go-checksumdatabase (sum.golang.org) voor die moduleversie heeft ondertekend. De proxy verifieert de handtekening van de database met dezelfde sleutel die in het go-commando is ingebouwd. Een module-zip wordt uitgepakt en gehasht zoals het go-commando dat doet, voordat hij wordt geleverd. Een module die de checksumdatabase niet kent, wordt niet geleverd. Met malwarescanning aan wordt elke zip gescand terwijl hij naar je toe streamt.- Ook de checksumdatabase wordt via de proxy bereikt. Het go-commando vraagt de proxy
of hij
sum.golang.orglevert, en haalt daarna elke lookup en tile via de proxy op. Zo blijftGOSUMDBaan en doet het nog steeds zijn eigen volledige verificatie, inclusief de bewijzen die de proxy zelf niet herhaalt, en je machine heeft geen directe toegang totsum.golang.orgnodig. - Privémodules worden niet geleverd:
proxy.golang.orgkan ze niet ophalen, en de checksumdatabase kent ze niet. Sluit ze uit metGOPRIVATE(ofGONOPROXYenGONOSUMDB), en het go-commando haalt ze zoals voorheen op uit je eigen Git-hosting. - Modules die op frem.sh worden gehost, worden nooit bij Google opgevraagd. Een verzoek om een module onder
frem.sh(of een subdomein) wordt met404geweigerd voordat de proxy iemand benadert, omdat het verzoek zelfproxy.golang.orgensum.golang.orghet pad van de module zou vertellen. Zetfrem.shinGOPRIVATE, zodat het go-commando die modules rechtstreeks van frem.sh ophaalt.
Wat Google ontvangt voor publieke modules
De proxy haalt publieke Go-modules op uit de modulemirror van Google (proxy.golang.org) en controleert
ze tegen de checksumdatabase van Google (sum.golang.org). Wanneer een module of versie nog niet
gecachet is, ontvangt Google daarom:
- het modulepad en de versie die worden opgehaald (bijvoorbeeld
github.com/gorilla/websocket@v1.5.0), en de lookups in de checksumdatabase daarvoor; - verzoeken vanaf de egressadressen van fremforge, niet vanaf je machines, zonder de naam van je organisatie, gebruiker, token of repository.
Google ontvangt niet je code, je go.mod, de namen van je repositories of welke
organisatie het vroeg. Een module die al gecachet is, wordt geleverd zonder Google te benaderen. Hetzelfde
geldt voor de beveiligingsscanners: ze lezen publieke Go-modules via deze proxy, en vragen
nooit om een module die volgens de regels hieronder privé is.
Voor het pakketbeleid heet een Go-module naar zijn modulepad. Het releasemoment is het moment dat
proxy.golang.org voor de versie vastlegt. Go-modules declareren geen licentie die de proxy kan lezen,
dus licentieregels gelden er niet voor.
Helm-charts
Klassieke Helm-repositories (een index.yaml en chartarchieven) worden geleverd uit een vaste lijst:
| Repositorynaam | Upstream |
|---|---|
prometheus-community | https://prometheus-community.github.io/helm-charts |
grafana | https://grafana.github.io/helm-charts |
jetstack | https://charts.jetstack.io (cert-manager) |
ingress-nginx | https://kubernetes.github.io/ingress-nginx |
Voeg een repository toe met de URL van de proxy en inloggegevens met read:package:
helm repo add prometheus-community https://frem.sh/_app/proxy/<org>/helm/prometheus-community \
--username <user or robot name> --password-stdin <<< "$FREMFORGE_TOKEN"
helm search repo prometheus-community/prometheus
helm pull prometheus-community/prometheus --version 29.36.1
helm install my-prometheus prometheus-community/prometheus --version 29.36.1Elke chart-URL in de index verwijst terug naar frem.sh, dus Helm stuurt je inloggegevens mee bij elke
chartdownload en --pass-credentials is niet nodig.
Wat de proxy doet:
index.yamlwordt hoogstens elke 5 minuten opnieuw bij de repository gecontroleerd, en de laatste goede kopie wordt geleverd zolang de repository onbereikbaar is of iets antwoordt dat geen Helm-index is. De proxy geeft hem terug als JSON, wat Helm als YAML leest.- Charts moeten overeenkomen met de
digest(sha256) die de index van de repository voor die versie vastlegt, voordat ze worden geleverd. Een versie waarvan de indexentry geen digest heeft, of waarvan de chart niet op de eigen hosts van de repository staat (bijvoorbeeld eenoci://-URL), wordt weggelaten uit de index die je krijgt. Met malwarescanning aan wordt elke chart gescand terwijl hij naar je toe streamt. - Provenance-bestanden (
.prov) worden ongewijzigd doorgegeven, zodathelm pull --verifyenhelm install --verifywerken met de publieke sleutel van de uitgever van de chart, bijvoorbeeld voor cert-manager:helm pull jetstack/cert-manager --version v1.21.2 --verify --keyring cert-manager-keyring.gpg. Een provenance-bestand moet de chart noemen met de digest uit de index, anders wordt het niet geleverd. Van de vier repositories publiceren jetstack en prometheus-community provenance-bestanden; voor een chart zonder zo’n bestand mislukt--verifymetfailed to fetch provenance(404). - De dependencies van een chart worden door Helm opgelost uit de repositories die de
Chart.yamlnoemt. Eenhelm dependency updatebereikt die repositories rechtstreeks, tenzij je ze ook via de proxy toevoegt.
De klassieke repository van Bitnami staat niet op de lijst: de huidige chartversies daarvan zijn OCI-artefacten op
Docker Hub. Haal ze op via het containerpad,
oci://frem.sh/<org>/dependency-proxy/docker.io/bitnamicharts/<chart>, dat de eigen
Docker Hub-inloggegevens van je organisatie gebruikt (hierboven).
Voor het pakketbeleid heet een chart naar zijn chartnaam. Het releasemoment is de created-datum
in de index, en de licentie de annotatie artifacthub.io/license, als de chart die heeft.
Cargo (crates.io)
De proxy is een sparse registry
voor crates.io. Hij vereist Cargo 1.74 of later. Vervang crates-io erdoor in .cargo/config.toml,
in je project, of in ~/.cargo/config.toml voor elk project:
[source.crates-io]
replace-with = "fremforge"
[registries.fremforge]
index = "sparse+https://frem.sh/_app/proxy/<org>/cargo/index/"
credential-provider = "cargo:token"Cargo stuurt het token als de volledige Authorization-header, dus geef het het voorvoegsel Bearer. Houd
het buiten het bestand, in de omgeving:
export CARGO_REGISTRIES_FREMFORGE_TOKEN="Bearer $FREMFORGE_TOKEN"
cargo fetch
cargo build --lockedMet de bronvervanging komt elke crate van crates.io via de proxy, inclusief de
crates die een bestaande Cargo.lock vastpint, en wordt geen crate buiten de proxy om opgehaald.
Wat de proxy doet:
config.jsonis van de proxy zelf. Het verwijst crate-downloads terug naar het pad van je organisatie opfrem.shen vertelt Cargo dat de registry authenticatie vereist, zodat Cargo het token meestuurt bij elk index- en downloadverzoek.- Indexbestanden komen van
index.crates.io. Ze worden hoogstens elke 5 minuten opnieuw gecontroleerd, en de laatste goede kopie wordt geleverd zolang crates.io onbereikbaar is. Elk bestand is dat van crates.io zelf, versie voor versie. Ge-yankte versies blijven erin staan, gemarkeerd als yanked: Cargo gebruikt er nog een die jeCargo.lockvastpint, en kiest er geen voor een nieuwe resolutie. - Crates (
.crate) komen vanstatic.crates.ioen moeten overeenkomen met decksum(sha256) in hun indexentry, voordat ze worden geleverd. Een versie waarvan de indexentry geen checksum heeft, wordt weggelaten. Met malwarescanning aan wordt elke crate gescand terwijl hij naar je toe streamt, ook de inhoud van het archief. Cargo controleert dezelfde checksum aan zijn kant nog eens. - Zoeken, publiceren, yanken en eigenaren worden niet geboden:
cargo searchantwoordt404encargo publishwordt geweigerd met405. Publiceer je eigen crates in het Cargo-register van je organisatie.
Voor het pakketbeleid heet een crate naar zijn naam zoals crates.io die publiceert, en het releasemoment
is de pubtime in de indexentry. De index bevat geen licentie, dus licentieregels gelden niet
voor crates. Kwetsbaarheden en kwaadaardige crates komen uit de crates.io-gegevens van OSV: de
RustSec-advisories en de MAL-*-records.
Terraform- en OpenTofu-modules
De proxy levert publieke modules uit de moduleregistries en uit publieke git-repositories, zodat
tofu init en terraform init ze uit de cache van fremforge halen in plaats van van het internet. Hij
dekt:
- Registrymodules van
registry.opentofu.orgenregistry.terraform.io, bijvoorbeeldterraform-aws-modules/vpc/awsof de Azure Verified Modules (Azure/avm-*). - Git-bronnen op github.com en gitlab.com op een tag of een commit, bijvoorbeeld
git::https://github.com/<owner>/<repo>.git?ref=v1.2.3ofgithub.com/<owner>/<repo>?ref=v1.2.3.
Een branch wordt geweigerd: een gecachete module moet hetzelfde blijven, dus noem een tag of een commit. Privé-repositories, andere hosts en SSH-bronnen worden niet geleverd.
De IaC-controle leest modules via deze
cache voor elke organisatie, ook voor een organisatie waarvan de dependency-proxy uit staat. De modulecachesleutel,
die je eigen CI nodig heeft, kan voorlopig alleen worden aangemaakt in de interne organisaties van fremforge:
voor elke andere organisatie wordt het consolegedeelte niet getoond en antwoordt de API 404.
De modulecachesleutel
OpenTofu en Terraform bereiken de cache via de modulecachesleutel van je organisatie, die in de URL staat. Een eigenaar van de organisatie maakt hem aan onder Bouwen en uitrollen › Proxy voor afhankelijkheden › Terraform- en OpenTofu-modules. De sleutel wordt één keer getoond, als kant-en-klare configuratie voor OpenTofu en een voor Terraform. Daarna toont de pagina alleen de eerste tekens, de dag waarop hij voor het laatst is gebruikt, en een knop Roteren. Na een rotatie blijft de vorige sleutel 24 uur werken, zodat lopende pipelines kunnen afronden; daarna heeft elke CI-configuratie de nieuwe nodig. Het aanmaken en roteren van een sleutel wordt vastgelegd in het auditlog en komt net als andere auditgebeurtenissen in je SIEM terecht.
De sleutel kan ook via de API worden aangemaakt en geroteerd, met een token dat policy:write heeft:
GET /orgs/{org}/dependency-proxy/module-key toont het voorvoegsel en de datums (nooit de sleutel), en
POST /orgs/{org}/dependency-proxy/module-key met {"expect": "<current prefix>"} (of "" als
er geen is) geeft de nieuwe sleutel één keer terug. Is er intussen een andere sleutel actief geworden, dan is het antwoord
409 module-key-stale en verandert er niets.
Met de sleutel kun je publieke modules lezen als je organisatie, en verder niets. Behandel hem als een wachtwoord: bewaar hem in je CI-secrets, niet in een repository.
Registrymodules: geen wijziging aan je bronnen
Richt de registry van OpenTofu op de cache met een
CLI-configuratiebestand (~/.tofurc, of het
bestand dat TF_CLI_CONFIG_FILE noemt). Je source- en version-regels blijven zoals ze zijn:
host "registry.opentofu.org" {
services = {
"modules.v1" = "https://frem.sh/_app/proxy/<org>/terraform/k/<module cache key>/registry/registry.opentofu.org/v1/modules/"
"providers.v1" = "https://registry.opentofu.org/v1/providers/"
}
}- Houd beide regels. Het
host-blok vervangt alles wat OpenTofu over de registry weet. Zonderproviders.v1mislukt elke providerinstallatie met “does not offer a OpenTofu provider registry”. - Voeg geen
credentials-blok toe. OpenTofu en Terraform koppelen inloggegevens aan de hostnaam van de registry, dus een token daarin zou ook naar de publieke registry worden gestuurd: bij elk providerverzoek, en bij elk verzoek op een machine waar hethost-blok ontbreekt. De modulecachesleutel heeft geen credentials-blok nodig. - Terraform: schrijf
registry.terraform.ioin plaats vanregistry.opentofu.orgop alle drie de plekken. We hebben deze configuratie geverifieerd op OpenTofu 1.13.1, met een sleutel en met een verkeerde (403 Forbidden). Terraform documenteert hetzelfde gedrag voor host en inloggegevens; dat hebben we niet gemeten.
Om te controleren dat de cache wordt gebruikt, voer je TF_LOG=debug tofu init uit en zoek je naar regels
GET https://frem.sh/_app/proxy/<org>/terraform/... voor je modules.
Git-bronnen
Geef het archief van de proxy voor de tag of commit op als HTTPS-bron. //* selecteert de moduleroot in
het archief, en een subdirectory volgt daarna:
module "network" {
source = "https://frem.sh/_app/proxy/<org>/terraform/k/<module cache key>/git/github.com/<owner>/<repo>/v1.2.3.tar.gz//*/modules/network"
}Naast de modulecachesleutel in de URL zijn geen inloggegevens nodig.
Wat de proxy doet
- Een versie wordt bij de eerste fetch vastgepind. De proxy zet de tag om naar een commit uit de
eigen lijst met git-refs van de repository (wat
git ls-remoteleest), haalt het archief van die commit op, en legt de commit en de SHA-256 van het archief vast. Elk later verzoek, van welke organisatie ook, krijgt precies die bytes. Een versie van een registrymodule wordt vastgepind op de commit die de tag noemde. - Een verplaatste tag verandert je module niet. De proxy controleert vastgepinde tags hoogstens elke 6 uur opnieuw. Noemt een tag nu een andere commit, dan blijft de proxy de vastgepinde leveren en legt hij vast dat de upstream-tag is verplaatst. Alleen een operator van fremforge kan een module opnieuw vastpinnen.
- Waartegen dit beschermt, en waartegen niet. Registries en git-hosts publiceren geen checksum voor modulearchieven, dus de eerste fetch wordt vertrouwd. Niets wat daarna upstream verandert, bereikt jou: een omgezette tag of een opnieuw gegenereerd archief wordt niet geleverd. Een versie die kwaadaardig was toen hij voor het eerst werd gepubliceerd, wordt geleverd zoals hij was.
- Archieven worden gecontroleerd voordat ze worden geleverd. Een archief groter dan 50 MiB, dat uitpakt tot
meer dan 512 MiB of 20.000 entries, of dat een absoluut pad, een
..-pad, een devicebestand of een link naar buiten het archief bevat, wordt geweigerd, en er wordt niets opgeslagen. - Malwarescanning geldt voor modulearchieven zoals voor andere bestanden wanneer je organisatie het aan heeft staan. OSV heeft geen Terraform-ecosysteem, dus er geldt geen lijst met bekende kwaadaardige modules, en de licentie- en releaseleeftijdsregels van het pakketbeleid worden er niet op toegepast.
- Gedeeld, per organisatie gelogd. Een publieke module wordt één keer voor iedereen opgeslagen. De fetches van elke
organisatie worden in haar eigen toegangslog vastgelegd, met als actor
module-cache-key. De modulecachesleutel zelf wordt nooit naar een log geschreven.
Pakketbeleid en kwaadaardige pakketten
Het pakketbeleid van je organisatie wordt toegepast op npm-, PyPI-, RPM-, Maven-, NuGet-, Go- en Cargo-pakketten en Helm-charts die via de proxy worden opgehaald, met dezelfde regels als voor pakketten in je register:
- Licentie-lijsten voor toestaan, weigeren en waarschuwen, toegepast op de gedeclareerde licentie van de versie.
- Kwetsbaarheden op of boven je drempel voor ernst of CVSS, uit de OSV-database.
- Weiger- en toestaanlijsten op pakketnaam en versiebereik.
- Minimale releaseleeftijd, vanaf het publicatiemoment bij de upstream.
- Kwaadaardige pakketten (OSV-advisories
MAL-*) worden altijd gecontroleerd, wat het beleid ook zegt.
Voor RPM-pakketten is de versie [epoch:]version-release, de licentie het veld License van het pakket,
en de releaseleeftijd het moment waarop het pakket in de repository kwam. OSV heeft geen
gegevens over kwaadaardige pakketten of kwetsbaarheden voor RPM-pakketten, dus die twee controles gelden niet voor
RPM’s in de proxy. Kwetsbaarheden in RPM-pakketten worden gevonden wanneer de images die ermee zijn gebouwd
worden gescand. Hetzelfde geldt voor Helm-charts: OSV heeft geen gegevens
voor charts, dus licentie, weigerlijsten en releaseleeftijd gelden, en de images die een chart uitrolt, worden
gescand waar ze worden opgehaald. Zodra weigeren aan staat, blijft een geblokkeerde chartversie in
de Helm-index staan en wordt de download ervan geweigerd met 403.
Weigeren staat aan sinds 2026-10-11. Een beleid in de modus Afdwingen haalt een geblokkeerde versie uit
het npm-packument of de PyPI-index, zodat je resolver een toegestane versie kiest, en een directe download
ervan wordt geweigerd met 403 met de naam van de regel. Een beleid in de modus Schaduw, de standaard, levert
het pakket nog steeds en legt de pull in het toegangslog vast als would_block met de regel die
matchte. Kwaadaardige pakketten worden geweigerd, wat de modus van je beleid ook is, Schaduw en Uit
inbegrepen, en weggelaten uit de pakketmetadata die de proxy levert.
Zolang de proxy geen antwoord over het beleid van fremforge kan krijgen (na een paar seconden opnieuw proberen, en
zonder recent antwoord voor hetzelfde pakket om op terug te vallen), weigert hij de download met
503 in plaats van een versie te leveren die hij niet op malware kon controleren. Later opnieuw proberen lukt zodra
het antwoord er weer is.
Advisorygegevens worden meerdere keren per dag vernieuwd uit de OSV-mirror van fremforge, en een beleidswijziging geldt vanaf de volgende pull. Er hoeft niets opnieuw te worden gescand.
Wat vandaag wordt afgedwongen
| Controle | Geldt voor | Vandaag |
|---|---|---|
Checksum van de upstream (imagedigest, npm-integrity, PyPI-sha256, sha256 en grootte van RPM-repomd.xml en primary.xml, Maven-.sha1 en .sha256, SHA-512 en grootte uit de NuGet-catalog, Go-h1: ondertekend door de checksumdatabase, Helm-index.yaml-digest, Cargo-index-cksum) | Elke laag, elk pakket en elk bestand met repositorymetadata | Geweigerd bij een afwijking; er wordt niets opgeslagen |
Antivirus (ClamAV) terwijl het bestand naar je toe streamt, als je organisatie malwarescanning heeft aangezet (malware_scan, standaard uit) | Elke laag, elk pakketbestand en elke chart; RPM-payloads uitgepakt; entries in jar, nupkg en module-zip die de scanner zelf niet kan openen, uitgepakt of geweigerd | Geweigerd: een geïnfecteerd bestand wordt vóór de laatste byte afgebroken en nooit opgeslagen |
| Scanresultaat van een laag, geïnfecteerd of onscanbaar (met malwarescanning aan) | Containerimages | Geweigerd, zoals bij images die je pusht |
Kwetsbaarheden-block_pull, als je organisatie het heeft ingesteld | Containerimages | Geweigerd met 403 DENIED; zie Imagescanning |
Kwaadaardige pakketten (OSV MAL-*) in het image | Containerimages | Geweigerd, zoals bij images die je pusht; een bevinding op het tabblad Malware |
Kwaadaardige pakketten (OSV MAL-*) | npm, PyPI, Maven, NuGet, Go, Cargo | Geweigerd met 403, wat de modus van je beleid ook is |
| Pakketbeleid: licentie, kwetsbaarheden, weigerlijst, releaseleeftijd | npm, PyPI, Maven, NuGet, Go en Cargo (geen licentie voor Go en Cargo) | Geweigerd wanneer je beleid in de modus Afdwingen staat; vastgelegd (would_block) in de modus Schaduw |
| Pakketbeleid: licentie, weigerlijst, releaseleeftijd | RPM, Helm-charts | Geweigerd wanneer je beleid in de modus Afdwingen staat; vastgelegd (would_block) in de modus Schaduw |
| Bekend misbruikte kwetsbaarheid met een gerepareerde versie (ENISA EUVD, CISA KEV) | npm, PyPI, Maven, NuGet, Go, Cargo | Geweigerd met 403, wat de modus van je beleid ook is (zie hieronder) |
Gecachete images worden ook op kwetsbaarheden en gelekte secrets gescand, net als de images die je pusht; zie Imagescanning.
Bekend misbruikte kwetsbaarheden
Sinds 2026-10-13 controleert fremforge elke pakketversie via de proxy tegen de kwetsbaarheden waarvan bekend is dat ze actief worden misbruikt: eerst de EU Vulnerability Database (EUVD) van ENISA, met daarbovenop de Known Exploited Vulnerabilities-catalogus van CISA. Een versie telt alleen mee wanneer zo’n kwetsbaarheid haar treft en er een gerepareerde versie bestaat, zodat er altijd een versie is om naar over te stappen. Dit is de regel die fremforge al op zijn eigen runner-images toepast.
Sinds 31-10-2026 wordt zo’n versie geweigerd. Een download antwoordt 403 met een melding
die de CVE’s noemt en je vraagt te upgraden, en het antwoord draagt
x-fremforge-proxy-policy: blocked;package_policy:known_exploited. De versie wordt ook
weggelaten uit de pakketmetadata die de proxy serveert, zodat een versiebereik een andere
versie in het bereik kiest; alleen een lockbestand of buildbestand dat de getroffen versie
vastpint, faalt. De weigering wordt zoals elke andere beleidsweigering vastgelegd in je
toegangslog.
Dit is een platformregel, net als bij kwaadaardige pakketten: hij geldt ongeacht de modus van je beleid, en de uitzonderingen van je beleid heffen hem niet op. De bot voor afhankelijkheidsupdates van je organisatie ziet deze versies nog steeds in de metadata, zodat hij de upgrade kan voorstellen. De pull-request-scanners van fremforge lezen ze ook nog steeds, zodat een bekend misbruikte afhankelijkheid als bevinding blijft verschijnen in plaats van uit de scan te verdwijnen.
Als een build erop faalt, stap over op de gerepareerde versie: een pull request met een beveiligingsfix staat misschien al open. Gemeten van 13-10-2026 tot 31-10-2026, vóór de omschakeling, heeft geen klantorganisatie zo’n versie gedownload.
Dezelfde feed laat een versie die een bekend misbruikte kwetsbaarheid repareert al de minimale releaseleeftijd van je beleid overslaan.
Opslag, limieten en facturatie
Gecachete bestanden tellen met hun volledige grootte mee voor de pakketopslag van je organisatie, alsof ze in je eigen register stonden. Een containerlaag of npm- of PyPI-bestand dat door meerdere organisaties wordt opgehaald, wordt één keer opgeslagen, maar telt mee voor het gebruik van elke organisatie. RPM-inhoud wordt per organisatie opgeslagen (zie RPM).
- Betaalde abonnementen: gecachete bestanden delen één opslagpool voor pakketten met je eigen pakketten. Met
overschrijding uit mag de proxy gebruiken wat je eigen pakketten van de pool overlaten. Is er niets meer
over, dan worden nieuwe fetches geweigerd met
403(dependency proxy storage cap reached), en wat al gecachet is, wordt nog steeds geleverd. Met overschrijding aan is er geen proxylimiet, en opslag boven de pool wordt gefactureerd tegen het overschrijdingstarief voor pakketten. - Proefperiodes: een vaste 5 GB aan gecachete bestanden.
De pagina Proxy voor afhankelijkheden toont je gebruik en je limiet. Het cijfer voor je eigen pakketten waarop de limiet wordt gebaseerd, wordt één keer per dag vernieuwd.
Bewaartermijn
Een gecachet bestand dat je organisatie gedurende retention_days (standaard 90, van 7 tot 365) niet heeft opgehaald,
wordt uit je cache verwijderd, samen met de tags die ernaar verwijzen, en telt niet meer mee voor
je opslag. De controle draait elk uur. Zodra geen enkele organisatie meer naar een bestand verwijst, wordt het
24 uur later uit de opslag van fremforge verwijderd. Opnieuw ophalen haalt het weer bij de upstream op.
Pakketversies die nog in gebruik zijn, blijven bewaard. Een pakketbestand (npm, PyPI, Maven, NuGet, Go, Cargo, Helm of RPM) wordt niet verwijderd, hoe lang geleden het ook voor het laatst is opgehaald, zolang dezelfde pakketversie een actuele component is in de componenteninventaris van je organisatie: in de actuele SBOM van de standaardbranch van een repository, de laatste release ervan, een actueel image, een live registerpakket of een geüploade SBOM. Een dependency die in een lockfile is vastgepind maar maar twee keer per jaar wordt gebouwd, blijft daardoor gecachet. Ze telt nog steeds mee voor je opslag. Zodra de versie uit elke actuele SBOM verdwijnt, geldt bij de volgende controle per uur weer de normale regel.
Basisimages die je huidige builds gebruiken, blijven bewaard. Een gecachet containerimage wordt niet verwijderd, hoe lang geleden het ook voor het laatst is opgehaald, zolang een van de huidige images van je organisatie erop is gebouwd: elke laag van het gecachete image is ook een laag van een image dat nog onder een tag in het register van je organisatie is gepubliceerd. Het manifest van het image, de configuratie en alle lagen blijven samen bewaard, zodat een pull ervan blijft werken, en dat geldt ook voor een multi-platformindex waarvan je op een platformimage bouwt. Een image dat alleen een laag deelt met je builds (bijvoorbeeld een ander image op dezelfde distributie), wordt door deze regel niet bewaard. Het telt nog steeds mee voor je opslag. Zodra er geen huidig image meer op is gebouwd, geldt weer de normale regel. Elk ander gecachet image houdt de regel van de laatste pull. Twee gevallen worden niet herkend en houden de regel van de laatste pull: een basisimage dat alleen wordt gebruikt voor een ander platform dan linux/amd64, en een build die de lagen van het basisimage opnieuw comprimeert in plaats van ze te hergebruiken.
Storingen bij de upstream
Wanneer een upstream-registry onbereikbaar of traag is of weigert, blijven builds werken voor alles wat je organisatie eerder heeft opgehaald:
- Bestanden die je eerder hebt opgehaald (imagelagen,
.tgz, wheels,.jar,.nupkg, Go-.zipen.mod, Helm-charts, crates) worden geleverd uit de opslag van fremforge. Het leveren ervan wacht nooit op de upstream. - Indexen en tags (imagetags, npm-packuments, PyPI-indexen, RPM-
repomd.xml, Maven-maven-metadata.xml, versielijsten en registraties van NuGet, Go-@v/listen@latest, Helm-index.yaml, indexbestanden van Cargo) worden beantwoord vanuit de laatste goede kopie. Het antwoord bevat danX-Fremforge-Proxy: stale, dus een nieuwe release die tijdens de storing is gepubliceerd, is pas zichtbaar wanneer de upstream terug is. - Imagetags die een andere organisatie heeft gecachet, worden ook vanuit de laatste goede kopie geleverd wanneer je organisatie die tag nooit heeft opgehaald: alleen voor publieke images die zonder inloggegevens zijn opgehaald, en alleen uit de gedeelde opslag van fremforge, nooit uit inhoud die een andere organisatie met haar eigen registry-inloggegevens heeft opgehaald. Docker Hub-images worden altijd met de eigen inloggegevens van je organisatie opgehaald en worden niet op deze manier gedeeld.
- Alles wat nooit eerder is opgehaald, antwoordt
502, omdat er niets te leveren is.
Is de eigen aanmeld- of autorisatiedienst van fremforge kort niet beschikbaar, dan blijven verzoeken die in de laatste 15 minuten zijn toegestaan uit de cache geleverd (alleen lezen). Een ingetrokken token of een verwijderd lidmaatschap gaat nog steeds in zodra fremforge het kan controleren.
Wat een storing overleeft, wordt begrensd door de bewaartermijn. Een bestand dat je organisatie
gedurende retention_days (standaard 90) niet heeft opgehaald, wordt verwijderd. Daarna moet het opnieuw bij de
upstream worden opgehaald, wat niet kan zolang de upstream onbereikbaar is. Pakketversies in je
componenteninventaris, en de basisimages waarop je huidige images zijn gebouwd, blijven hoe dan ook bewaard
(zie Bewaartermijn). Voor al het andere dat een lange storing moet
overleven: haal het minstens één keer binnen je bewaartermijn op, of verhoog
retention_days.
Toegangslog
Elke pull via de proxy verschijnt in het registertoegangslog van je organisatie met herkomst proxy,
behalve twee soorten routinematig CI-verkeer: de toegestane metadataleesacties van een CI-job (pakketindexen en
versielijsten) worden sinds 2026-10-12 niet opgeslagen, en de downloads van een CI-job die de proxy
uit zijn cache levert, worden sinds 2026-10-13 per dag, versie, repository en run geteld in de
pull-telling. De downloads van een CI-job die bij de upstream-registry worden opgehaald, de
weigeringen en de fouten zijn nog steeds gebeurtenissen.
Het log legt het pakket, de versie en het bestand vast, wie het ophaalde (een gebruiker, of voor CI de repository van de
job), de uitkomst en een eventuele beleidsbeslissing. Een pull via frem.sh die uit de cache wordt geleverd,
wordt door de proxy geleverd (200); die van een CI-job is een redirect naar objectopslag (307), behalve voor Maven-bestanden tot 1 MiB. Hoe dan ook wordt
de grootte vastgelegd. Een HEAD-verzoek via frem.sh wordt vastgelegd als GET,
omdat het CDN HEAD-verzoeken als GET naar fremforge doorstuurt.
De eigen leesacties van de dependency-scan (hierboven) gaan niet via het CDN of de uploadproxy, dus ze staan
niet in het toegangslog; fremforge logt ze als aantallen per scan.
Wat de upstream ziet
fremforge benadert namens jou de upstream die je hebt gekozen. De upstream ontvangt het IP-adres van fremforge
en de naam van het image of pakket. Voor docker.io, de Red Hat-registries, en
ghcr.io of quay.io wanneer je er inloggegevens voor hebt opgeslagen, ontvangt hij ook de eigen
inloggegevens van je organisatie, zodat de pull daar meetelt voor je account.
Hij ontvangt niets over je gebruikers. De meeste van deze registries worden beheerd door bedrijven buiten
de EU. Na de
eerste fetch worden pulls geleverd uit de EU-opslag van fremforge zonder de upstream opnieuw te benaderen,
behalve om tags, npm- en PyPI-metadata, RPM-repomd.xml, Maven-maven-metadata.xml en versielijsten
en registratie van NuGet, versielijsten van Go, Helm-index.yaml-bestanden en indexbestanden van Cargo opnieuw te controleren (hoogstens elke 5 minuten). De checksumdatabase van Go wordt
ook via de proxy bereikt, namens het go-commando.
Fouten
| Status | Betekenis |
|---|---|
401 | Geen inloggegevens, of frem.sh accepteerde ze niet. |
403 | Geen lid, de proxy staat uit voor de organisatie, de inloggegevens missen read:package, een jobtoken voor een andere organisatie, de opslaglimiet van je organisatie is bereikt, of een weigering door een controle (de melding noemt die). |
404 | De upstream heeft het niet, of de upstream-host is niet beschikbaar via de proxy. |
405 | Een schrijfactie. De proxy is alleen-lezen. |
429 | De limiet voor upstream-fetches van je organisatie is bereikt. Probeer het opnieuw na het aantal seconden in Retry-After. |
502 | De upstream is niet beschikbaar en er is niets gecachet voor dit verzoek. |
503 | Een afhankelijke dienst (malwarescanner, beleidscontrole) is niet beschikbaar; de proxy is bezet; of een ander verzoek is nog bezig met het ophalen en scannen van dezelfde laag. Probeer het opnieuw na Retry-After. |