Zum Hauptinhalt springen

Sicherheitsmodell der gehosteten Runner

Die gehosteten Runner von fremforge führen die Forgejo-Actions-Workflows von Kundinnen und Kunden auf virtuellen T-Cloud-Public-ECS-Maschinen pro Commit in der Region EU-DE aus. Ein Job in der Warteschlange, für dessen Commit keine freie VM bereitsteht, stellt eine neue VM mit eingebautem Docker bereit. Diese VM führt nur Jobs desselben Commits desselben Repositorys aus, einen nach dem anderen, wartet bis zu 60 Sekunden auf einen weiteren, schaltet sich dann ab und wird zerstört. Es gibt keinen dauerhaften Runner-Pool, und keine VM führt jemals Code aus zwei Commits, zwei Repositorys oder von zwei Kunden aus.

Diese Seite dokumentiert die Isolationsgarantien, die fremforge gibt, die Limits pro Mandant und das Bedrohungsmodell: was Kundencode tun kann, was nicht, und welche Entwurfsentscheidungen jemand, der Workflows schreibt, treffen sollte, um die eigenen Secrets zu schützen.

Wo Workflows laufen

KomponenteUmsetzung
RechenleistungVirtuelle Maschinen von T Cloud Public ECS (Elastic Cloud Server), Region eu-de, drei Verfügbarkeitszonen
LebenszyklusEine kurzlebige VM pro Commit. Die Plattform startet eine neue ECS-VM, wenn der erste Job eines Commits in die Warteschlange kommt, und zerstört sie, sobald die Jobs dieses Commits fertig sind. Zwei Kunden und zwei Commits teilen sich nie einen Kernel, vergleichbar mit den von GitHub und GitLab gehosteten Runnern, was die Trennung zwischen Mandanten angeht. Jobs desselben Commits können sich die VM teilen (zum Beispiel build und danach deploy), weshalb eine Pipeline als eine Vertrauensdomäne behandelt werden sollte; siehe Bedrohungsmodell. Kunden-Workflows teilen sich nie eine VM mit Plattform-Workloads. Es gibt keinen Warm-Pool (Ziel 0, aus Kostengründen), sodass jeder Commit den ECS-Start von ca. 40 s abwartet.
NetzwerkplatzierungJede VM erhält ein eigenes ENI in einem eigenen Runner-Subnetz, mit einer Security Group pro VM, die den ausgehenden Verkehr durchsetzt. Die VMs liegen in einem eigenen VPC-Subnetz, verteilt auf drei Verfügbarkeitszonen
VM-LaufzeitEine VM pro Commit; bereitgestellt, wenn der erste Job dieses Commits in die Warteschlange kommt, zerstört, wenn seine Jobs abgeschlossen sind. Die Obergrenze für die Laufzeit pro Job (standardmäßig 60 min, harte Obergrenze 360 min) wird auf dem Runner durchgesetzt
Reaper als RückfallebeneEin separater Reaper außerhalb des normalen Ablaufs löscht verwaiste VMs: Runner nie registriert, Runner beendet, aber das Löschen verpasst, VM älter als ihre Löschfrist, oder eine absolute Obergrenze von 6 h 10 min.
Runner-BinaryUpstream-forgejo-runner (act_runner) v13.2.0, kein Fork. Registriert sich kurzlebig mit --ephemeral, sodass eine Registrierung von einem Task verbraucht wird; der Agent registriert sich für jeden weiteren Task desselben Commits neu, und die Plattform zerstört die VM, sobald die Jobs dieses Commits fertig sind
VM-ImageDas Image der gehosteten Runner: Debian 13 (trixie) als Basis, mit Toolchains aus in der EU gecachten Binarys (keine direkten Upstream-Downloads beim Start). Das Image ist die Bootplatte der VM; der Docker-Daemon ist vorinstalliert und läuft nativ auf der VM (kein separater Sidecar). Der Kaltstart dauert bei jedem Commit ca. 40 s; das Ziel für den Warm-Pool ist aus Kostengründen 0, daher wird keine VM vorab bereitgestellt

Isolationsgarantien

Netzwerkisolation (pro VM)

Jede Runner-VM erhält ein eigenes ENI, das an eine Security Group pro VM gebunden ist. Die SG verweigert standardmäßig jeden Verkehr außer:

  • DNS (53/UDP, 53/TCP) zum internen DNS-Resolver der Plattform
  • Ausgehendem Verkehr über den Egress-Proxy der Runner, dem einzigen ausgehenden HTTP-Weg

Kundencode kann nicht erreichen:

  • die fremforge-API oder ihre private Datenbank
  • den internen Endpunkt von Forgejo (Runner-VMs sprechen mit Forgejo über die öffentliche, von Bunny vorgeschaltete Domain mit einem Runner-spezifischen Scope; der interne Endpunkt ist nicht erreichbar)
  • Plattformdienste von T Cloud Public (RDS, DCS, OBS, SFS-Turbo, IAM, KMS)
  • Runner-VMs anderer Mandanten
  • die Metadaten-IP des Clusters (169.254.169.254), ausdrücklich im SSRF-Schutz gesperrt
  • private Bereiche nach RFC1918 oder Loopback

Die Security Group wird bei der Bereitstellung der VM angewendet und kann aus der VM heraus nicht geändert werden: Der VM ist keine IAM-Agency zugeordnet, sodass die APIs zur Netzwerkkonfiguration über die aus den Metadaten abgeleitete Identität nicht erreichbar sind.

Ausgehender Verkehr

Workflow-Schritte, die das öffentliche Internet brauchen (ein öffentliches Repository klonen, ein Tool herunterladen, eine SaaS-API aufrufen), laufen über den Egress-Proxy der Runner, per HTTPS_PROXY, das in die VM injiziert wird. Dieser Proxy:

  • akzeptiert jede öffentliche Unicast-IP einschließlich Carrier-Grade NAT (entspricht dem Verhalten der von GitHub gehosteten Runner; nötig für Dienste von T Cloud Public selbst wie SWR, die im CGNAT liegen)
  • sperrt private Bereiche nach RFC1918, Link-Local, Loopback, Multicast, reservierte Bereiche und ausdrücklich die Cloud-Metadaten-IPs (169.254.169.254, 100.100.100.200 von T Cloud Public)
  • protokolliert jeden CONNECT-Tunnelversuch mit Hostnamen und aufgelöster IP für die Aufbewahrung im Audit

Der Proxy ist bewusst großzügig im Sinne der von GitHub gehosteten Runner: Kunden-Workflows können jeden öffentlichen Host erreichen, den sie brauchen. Die Grenze liegt beim SSRF-Schutz und der internen Plattform, nicht bei Allowlists für Anbieter.

Paket-Caches (souverän, in der EU)

Bevor ein Workflow das öffentliche Internet erreicht, werden Paketinstallationen und Image-Pulls über den eigenen Dependency-Proxy deiner Organisation geleitet, der in der EU in derselben Region wie die Runner-VMs liegt. Der gemeinsame Docker-Hub-Mirror und die Paket-Caches im VPC wurden im Oktober 2026 stillgelegt. Der Proxy jeder Organisation wendet ihre eigene Paketrichtlinie, ihre Upstream-Zugangsdaten, ihr Zugriffsprotokoll und ihre Speichergrenze an; eine öffentliche Datei, die mehrere Organisationen laden, wird einmal gespeichert, und Inhalte, die mit den eigenen Zugangsdaten einer Organisation geholt wurden, werden nie an eine andere ausgeliefert. Ist das Runner-Pull-through eingeschaltet (Standard für jede Organisation, die keine eigenen Einstellungen für den Dependency-Proxy gespeichert hat), wird jeder Job beim Start auf den Proxy ausgerichtet:

VerkehrInjiziert als
npm, pnpm, pip, uvdie npmrc des Jobs, PIP_INDEX_URL, UV_DEFAULT_INDEX
Go, Maven, NuGet, Trivy-Schwachstellendatenbank (jeweils wie in runner_pull_through_ecosystems aufgeführt, standardmäßig alle)GOPROXY, ein Maven-Mirror von Central, eine rechnerweite NuGet.Config, TRIVY_DB_REPOSITORY und TRIVY_JAVA_DB_REPOSITORY
Container-Images von ghcr.io, quay.io, mcr.microsoft.com, registry.k8s.io, public.ecr.aws, registry.access.redhat.com; sowie docker.io, registry.redhat.io, registry.connect.redhat.com nur mit eigenen Zugangsdaten der Organisation, nie für Pull Requests aus Forksdie Registry-Konfiguration des Docker-Daemons der VM

Der Job authentifiziert sich beim Proxy mit Zugangsdaten, die auf seine eigene Organisation und seinen Lauf beschränkt sind, sodass Paketinstallationen die Paketrichtlinie und die Malware-Prüfungen der Organisation durchlaufen und in ihrem Zugriffsprotokoll erscheinen. Für Container-Images auf diesem Weg ist der Proxy ein Cache, keine Sperre: Ein Pull, den er abweist, geht direkt an die Registry. Der Proxy wird zu Beginn jedes Jobs geprüft; ist er nicht erreichbar, installiert und lädt der Job über den Egress-Proxy aus den öffentlichen Registrys, und dieser Rückfall wird protokolliert. Siehe Gehostete Runner.

Im üblichen Fall (öffentliche Abhängigkeiten) ist das transparent; an deinem Workflow ändert sich nichts.

Wenn du einen privaten Index oder eine private Registry verwendest, beachte, dass der injizierte Wert der Standard ist und daher Vorrang vor einem Standard hat, der in einer committeten Konfigurationsdatei (pip.conf, .npmrc, go env) gesetzt ist. Gib deine private Quelle ausdrücklich an, damit sie gewinnt; wie das für jedes Werkzeug geht, steht unten.

Verwende einen Index pro Installation: den Proxy oder einen privaten Index, der selbst die öffentliche Registry spiegelt. Füge nie einen zweiten Index neben dem ersten hinzu (--extra-index-url, PIP_EXTRA_INDEX_URL, UV_EXTRA_INDEX_URL): Der Installer nimmt dann einen Paketnamen von dem Index, der ihn gerade anbietet, und genau so funktionieren Dependency-Confusion-Angriffe. Siehe die PyPI-Hinweise des Dependency-Proxys.

  • pip: pip install --index-url <your-private> ... (ein --index-url auf der Kommandozeile übersteuert das injizierte PIP_INDEX_URL) oder setze es im env: des Workflow-Schritts, wenn dieser private Index die öffentlichen Pakete spiegelt, die du brauchst. Um deine eigenen Pakete aus der Registry deiner Organisation zu installieren, während öffentliche über den Proxy kommen, verwende zwei getrennte Installationen mit jeweils einem eigenen Index: zuerst die öffentlichen Abhängigkeiten, dann deine Pakete mit --index-url https://frem.sh/api/packages/<org>/pypi/simple/ --no-deps.
  • uv: dieselbe Regel. Binde deine eigenen Pakete per Namen an deine Registry, mit einem Index, der als explicit = true markiert ist, und einem Eintrag in [tool.uv.sources] pro Paket, sodass kein Name aus beiden aufgelöst werden kann.
  • npm: Setze NPM_CONFIG_REGISTRY (und bei pnpm 11 PNPM_CONFIG_REGISTRY) im env: des Schritts auf eine Registry, die die öffentliche spiegelt, oder behalte den Proxy und leite nur deinen Scope an deine Registry (@<your-scope>:registry=…), was jeden Namen in diesem Scope an eine Registry bindet. Siehe Paket-Caches.
  • Go: Setze GOPRIVATE (z. B. GOPRIVATE=git.example.com/*), damit die Toolchain für deine privaten Modulpfade den Proxy und die Prüfsummen-Datenbank umgeht.

Isolation auf VM-Ebene

OberflächeDurchsetzung
ProzessWorkflow-Schritte laufen standardmäßig als Benutzer runner der VM; sudo ist verfügbar, damit Workflows apt install ausführen, Docker nutzen, Systemwerkzeuge konfigurieren usw. können (entspricht den Erwartungen an die von GitHub gehosteten Runner). Die Grenze ist der Hypervisor unter der VM, nicht User-Namespaces
ArbeitsbereichVM-lokaler Arbeitsbereich unter /workspace (und /tmp), zwischen Jobs geleert und mit der VM zerstört. Was zwischen Jobs eines Commits erhalten bleiben kann, steht unter Jobs, die sich eine VM teilen
IdentitätDer VM ist keine IAM-Agency zugeordnet. Abfragen an den Metadatendienst liefern nur die Netzwerkidentität, die für den Start nötig ist; kein Zugriff auf Plattform-APIs
RessourcengrenzenDer ECS-Flavor der VM setzt eine harte Obergrenze für CPU und Arbeitsspeicher. Ein außer Kontrolle geratener Kunde kann keine Kapazität über die Grenzen seiner eigenen VM hinaus verbrauchen. Ein globales Ausufern ist durch die gleichzeitige Obergrenze pro Mandant und die Rechenkapazität der Plattform begrenzt
Container-LaufzeitDocker (nativ): Der Daemon läuft auf dem VM-Host, nicht als Sidecar. docker build, docker compose, kind, testcontainers funktionieren direkt, ohne den Aufwand von DinD. Für Workflows, die zusätzliche Fähigkeiten der Container-Laufzeit brauchen, leitet das Label dind-privileged auf einen Flavor mit aktivierter KVM-Verschachtelung
HypervisorDer KVM-basierte ECS-Hypervisor von T Cloud Public, dieselbe mandantenfähige VM-Grenze, die für jede kommerzielle Kundin und jeden kommerziellen Kunden von T Cloud Public gilt, die ECS in der Region betreiben

Kernel-Isolation zwischen und innerhalb von Mandanten

Das ist die tragende Aussage des Modells der gehosteten Runner. Jede VM ist an einen Commit eines Repositorys gebunden: ein Linux-Gastkernel, der auf dem Hypervisor von T Cloud Public läuft. Sie führt die Jobs dieses Commits nacheinander aus, und die Plattform zerstört sie, wenn sie fertig sind. Ein Job aus einem anderen Commit, einem anderen Repository oder einer anderen Organisation bekommt immer eine andere VM mit einem anderen Kernel.

MechanismusWie
VM pro CommitDie Plattform startet eine VM für einen wartenden Job, wenn keine VM dieses Commits frei ist. Ein Ausbruch auf Kernel-Ebene (z. B. CVE-2024-1086 nf_tables) kompromittiert nur DIESE Wegwerf-VM und die Jobs desselben Commits, nicht andere Mandanten
Schnelles Herunterfahren nach AbschlussNach ihrem letzten Job wartet die VM bis zu 60 Sekunden auf einen weiteren Job desselben Commits, schaltet sich dann ab und wird gelöscht. Ein separater Reaper außerhalb des normalen Ablaufs erfasst verwaiste VMs (Runner nie registriert, Löschen verpasst) innerhalb einer absoluten Obergrenze von 6 h 10 min
ENI und SG pro VMNetzwerkisolation unabhängig von der Kernel-Grenze. Die VM von Mandant A kann die VM von Mandant B über das Netzwerk nicht erreichen: getrennte ENIs, getrennte Security Groups
Lebenszyklus für einen CommitJeder Job läuft in einem neuen Job-Container. Eine VM wird nie für einen anderen Commit, ein anderes Repository oder einen anderen Mandanten wiederverwendet, sodass sie nie die Secrets eines früheren Mandanten enthält
OIDC-TokensJede VM erhält ein neues OIDC-Token, signiert vom Runner-OIDC-Aussteller, mit aud=fremforge und sub=repo:<owner>/<repo>:ref:<refname>. Die Vertrauensrichtlinien in der Cloud der Kunden richten sich für assume_role_with_web_identity nach dieser Audience und diesem Sub

Jobs, die sich eine VM teilen

Eine VM wird nur für Jobs desselben Commits im selben Repository (und damit derselben Organisation) wiederverwendet: andere Workflows, Läufe oder erneute Läufe dieses Commits oder ein Deploy nach seinem Build. Zwischen diesen Jobs setzt fremforge alles zurück, wovon es weiß, dass es Zugangsdaten enthalten kann: den Job-Container, /workspace und /tmp, den Docker-Login und die npm-Konfiguration sowie die üblichen Dateien mit Zugangsdaten. Lässt sich dieses Zurücksetzen nicht bestätigen, nimmt die VM keinen weiteren Job an, und der nächste Job bekommt eine neue VM.

Das Zurücksetzen ist keine neue VM. Jobs können den Docker-Daemon der VM nutzen, der auf der VM root ist, sodass ein Job etwas für einen späteren Job desselben Commits zurücklassen kann. Mit Zugangsdaten geladene Images, der Tool-Cache und der Go-Build-Cache bleiben ebenfalls auf der VM. Behandle alle Jobs eines Commits als eine Vertrauensdomäne:

  • Führe keinen nicht vertrauenswürdigen Code (von Beitragenden gelieferte Fixtures, nicht geprüfte Abhängigkeits-Updates) in der Pipeline desselben Commits aus wie einen Job, der Produktions-Secrets hält.
  • Sichere Deploys mit einer Freigabe für die Umgebung ab (siehe Jobs validate und apply trennen) und bevorzuge kurzlebige OIDC-Zugangsdaten gegenüber gespeicherten Schlüsseln.
  • Darf ein Deploy nie eine Maschine mit einem Build teilen, führe ihn auf einem eigenen Runner aus.

Limits pro Mandant

LimitStandardÜbersteuerung
Gleichzeitige Jobs pro Mandant2 pro Nutzer garantiert, mindestens 10 und höchstens 60 (Testphase: 2). Darüber hinaus darf ein zahlender Mandant freie Kapazität bis 60 nutzen, aber nur solange 20 Plattform-Slots frei bleiben, sodass die Lastspitze eines Mandanten nie die garantierten Jobs eines anderen verzögert. Zum Vergleich, von GitHub gehostet: Free 20, Pro 40, Team 60, Enterprise 500Enterprise-on-Demand: Eine Übersteuerung pro Mandant ersetzt den garantierten Anteil
Gleichzeitige Jobs über alle MandantenBegrenzt durch die Rechenkapazität der Plattform in eu-de—
Obergrenze für die Job-Rate7 Job-Starts pro rollierendem 5-Minuten-Fenster pro Slot der Lastspitzen-Obergrenze des Mandanten: 420 für einen zahlenden Mandanten, 14 in der Testphase. Sie wächst mit einer angehobenen Obergrenze für Gleichzeitigkeit mit, ist also eine Rückfallebene gegen Missbrauch und nie das Limit, auf das eine normale Pipeline zuerst stößt. GitHub veröffentlicht kein Limit für Job-StartsÜbersteuerung pro Mandant
Laufzeit pro Job3600 s (60 min)Pro Workflow-Schritt konfigurierbar, aber auf 6 h begrenzt
Runner-Minuten-Kontingentseat_cap × 1000 minutes/month (oder ein ausdrückliches Kontingent pro Mandant)Betreiberkonfiguration; entspricht der öffentlichen Preisliste
VM-FlavorStandard c9.large.2 (2 vCPU / 4 GiB RAM); c9.xlarge.4 (4 vCPU / 16 GiB) für runs-on: [fremforge, large]Das Label runs-on: eines Workflow-Schritts leitet auf andere Flavors

Überschreitet ein Mandant das Runner-Minuten-Kontingent und ist keine Mehrnutzung aktiviert (oder ist sie eingefroren), verweigert die Plattform die Zuteilung: Der wartende Job des Workflows wechselt in Forgejo auf Cancelled. Mandanten mit aktivierter Mehrnutzung laufen weiter und bekommen den Überschuss in Rechnung gestellt.

Erreicht ein Mandant die Obergrenze für Gleichzeitigkeit, warten weitere Jobs in der Warteschlange und werden zugeteilt, sobald ein Slot frei wird.

Was Kundencode NICHT tun kann

  • Die fremforge-API, den internen Endpunkt von Forgejo oder einen anderen Plattformdienst erreichen (die API ist nur über die öffentliche Bunny-Domain mit ordnungsgemäßer Authentifizierung erreichbar, wie für jeden externen Aufrufer)
  • Die Runner-VM eines anderen Mandanten lesen (getrenntes ENI; Verkehr zwischen VMs wird von der Security Group ausdrücklich verweigert)
  • Die Secrets eines anderen Mandanten lesen (Workflow-Secrets werden nur an den Runner übergeben, der den Workflow ausführt, dem sie gehören; das Zerstören der VM löscht die Zugangsdaten im Speicher)
  • Zustand über den eigenen Commit hinaus erhalten (die VM wird zerstört, sobald die Jobs dieses Commits fertig sind, und keine Platte wird zwischen VMs geteilt)
  • Die OTC-API direkt mit privilegiertem Scope erreichen (keine IAM-Agency zugeordnet; die aus den Metadaten abgeleitete Identität hat keine Rollen)
  • Cloud-Metadaten-Endpunkte erreichen (169.254.169.254, 100.100.100.200, beide ausdrücklich im SSRF-Schutz verweigert)
  • Den Runner-Pool erschöpfen (gleichzeitige Obergrenze pro Mandant + globale Rechenobergrenze der Plattform)
  • Andere Mandanten in der Warteschlange aushungern (gleichzeitige Obergrenze pro Mandant)
  • Aus dem Hypervisor ausbrechen (die VM ist die Grenze; der Host darunter gehört T Cloud Public und ist durch denselben VMM isoliert, der jeden kommerziellen ECS-Mandanten in der Region trennt)

Empfohlene Workflow-Formen

Jobs validate und apply trennen

Führe nicht vertrauenswürdigen Code (PR-Builds, Abhängigkeits-Scans, von Beitragenden gelieferte Test-Fixtures) in einem Job validate ohne Produktionszugangsdaten aus, und sichere den Job apply mit einer Freigabe für die Umgebung ab. Der Job validate sieht die Secrets des Jobs apply nie. Beide Jobs gehören allerdings zum selben Commit und können daher nacheinander auf derselben VM laufen: siehe Jobs, die sich eine VM teilen.

uses:-Referenzen per SHA festlegen, wenn die Lieferkette zählt

uses: actions/checkout@v4 wird zu frem.sh/actions/checkout aufgelöst (der native Forgejo-Pull-Mirror von fremforge für github.com/actions/checkout, Synchronisation alle 8 Stunden). Der Mirror folgt den Upstream-Tags einschließlich Force-Pushes, daher ist das Festlegen per SHA der einzige Weg, bytegenaue Stabilität zu garantieren:

# Bytewise-stable across maintainer force-pushes
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5  # v4.2.0

# Picks up upstream's current HEAD at last mirror sync — including
# any maintainer-credential-compromise force-push
- uses: actions/checkout@v4

OIDC für die Cloud-Authentifizierung statt langlebiger Secrets

Jede Runner-VM erhält ein neues OIDC-Token mit aud=fremforge. Konfiguriere die Vertrauensrichtlinie deines Cloud-Anbieters so, dass sie dieses Token akzeptiert und gegen kurzlebige Zugangsdaten tauscht. Speichere keine langlebigen AWS-Access-Keys oder GCP-Service-Account-JSONs in Workflow-Secrets, wo sie in der Prozessumgebung landen.

Fristen für Workflow-Schritte begrenzen

Setze timeout-minutes: für einzelne Schritte, um zu begrenzen, wie lange ein hängender Schritt laufen kann. Die Laufzeitgrenze auf VM-Ebene (activeDeadlineSeconds=3600) ist die Untergrenze der Plattform; Timeouts pro Schritt geben schnellere Rückmeldung.

Bedrohungsmodell im Überblick

BedrohungGegenmaßnahme
Kunden-Workflow enthält ZugangsdatenPush-Schutz (Gitleaks) blockiert den Commit, bevor er in der Historie landet
Kunden-Workflow versucht, die fremforge-Plattform zu lesenENI + SG pro VM verweigern; der VM ist keine IAM-Agency zugeordnet; die API ist nur über den öffentlich authentifizierten Weg erreichbar
Der Job eines Mandanten versucht, die VM eines anderen zu lesenENI pro VM auf getrennten IPs; SG verweigert standardmäßig im ganzen Runner-Subnetz; und sie liegen auf verschiedenen VMs mit verschiedenen Kerneln
Ausbruch auf Kernel-Ebene (root in der VM → Host-Kernel über eine CVE)Kompromittiert nur die Wegwerf-VM, die die Jobs dieses Commits ausführt. Andere Mandanten NICHT, denn sie haben ihre eigene VM. Die VM wird in jedem Fall etwa eine Minute nach dem letzten Job dieses Commits zerstört
Kunden-Workflow versucht, Daten über DNS abfließen zu lassenDNS ist erlaubt (Workflows brauchen es legitim), aber der Egress-Proxy protokolliert jedes CONNECT mit vollem Hostnamen für das Audit
Kompromittierter Upstream-act_runnerVom Upstream getestetes Binary (wir forken nicht). Über den EU-Cache gespiegelt, mit Trivy-Sperren auf dem Runner-Image. CVE-Korrekturen kommen über den wöchentlichen Neubau
Kunden-Workflow versucht, Metadaten-IPs zu erreichenAusdrückliche Sperre im SSRF-Schutz: 169.254.169.254 (AWS-Stil) und 100.100.100.200 (T Cloud Public)
Kunde monopolisiert die KapazitätGarantierter Anteil pro Mandant (2 pro Nutzer, 10 bis 60) mit Lastspitzen nur in freie Kapazität, die 20 Slots frei lässt, Obergrenze für die Job-Rate (7 Starts pro Lastspitzen-Slot pro 5 min), Obergrenze für Kontingent-Minuten
Veraltete Runner-VM überlebt den TaskDie Laufzeitgrenze pro Job beendet hart bei Fristablauf; die Plattform löscht die VM, wenn der Runner endet; ein separater Reaper außerhalb des normalen Ablaufs erfasst verwaiste VMs mit einer absoluten Obergrenze von 6 h 10 min

Nachvollziehbarkeit

Jede Zuteilung wird an drei Stellen protokolliert:

  1. Tabelle runner_jobs: tenant_id, repo, forgejo_task_id, started_at, finished_at, duration_seconds, vm_id. Quelle für die Abrechnungsaggregation und den Tab Infrastructure in der Betreiberkonsole
  2. Tabelle metering_events: Zeilen mit code=runner_minute, abgeleitet aus runner_jobs.duration_seconds. Grundlage für die Rechnungspositionen und das Panel „Runner minutes used" des Mandanten
  3. Protokollstrom für Betreiber: strukturierte Start-Protokolle für den Betreiber, mit laufender Alarmierung bei verweigerten Zuteilungen, hängenden VMs, überschrittenen Fristen und erschöpfter Kapazität

Mandanten sehen ihre eigene Nutzung unter Organisationsverwaltung → Build und Deployment → CI-Nutzung, einschließlich der Minuten pro Monat und einer Tabelle der Laufzeiten pro Job.