Zum Hauptinhalt springen

fremforge-Registrys aus GitHub Actions und OpenShift nutzen

Dein Quellcode und deine CI können bei GitHub bleiben und deine Cluster bei OpenShift, während die Pakete in deiner fremforge-Organisation liegen. Beide erreichen die Registry über einen Registry-Robot: ein Login, das der Organisation gehört, nicht einer Person.

Ein Registry-Robot:

  • liest die Pakete einer Organisation, oder liest und veröffentlicht sie, und zwar für jeden Pakettyp;
  • kann veröffentlichen, aber nicht löschen: Das Löschen einer Paketversion, einer Datei, eines Container-Tags oder eines Images wird mit 403 abgewiesen und im Audit-Log als registry_robot.delete_refused erfasst. Löschen bleibt Sache eines Admins der Organisation, in der Weboberfläche oder mit dem eigenen Login;
  • kann keinen Code lesen, die Weboberfläche nicht öffnen und keine andere Organisation erreichen;
  • belegt keinen Nutzer;
  • läuft nach höchstens 365 Tagen ab; danach funktionieren weder er noch eines seiner Tokens;
  • ist mit der Person, die ihn angelegt hat, unter Org-Admin → Sicherheit → Zugriff → Registry-Robots aufgeführt, und jedes Anlegen, jede Rotation, jede Löschung und jedes abgewiesene Löschen eines Pakets steht im Audit-Log der Organisation.

In der CI von fremforge selbst brauchst du keinen: Ein Job in Forgejo Actions hat bereits ein Token für die Pakete seiner eigenen Organisation. Siehe Aus Forgejo Actions veröffentlichen.

Einen Robot anlegen

In der Konsole: Org-Admin → Sicherheit → Zugriff → Registry-Robots → Robot anlegen. Wähle Pakete lesen für ein Pull Secret und Pakete lesen und veröffentlichen (kein Löschen) für einen CI-Job, der veröffentlicht.

Die Seite zeigt dann einmalig den Benutzernamen und das Token des Robots. Kopiere beides; das Token wird nicht noch einmal angezeigt. Geht es verloren, stellt Token rotieren ein neues aus und widerruft das alte sofort.

Oder über die API, mit einem API-Token mit dem Scope policy:write:

curl -sS -X POST "https://frem.sh/_app/api/v1/orgs/<org>/registry-robots" \
  -H "Authorization: Bearer $FREMFORGE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "github-publish", "access": "write", "expires_in_days": 90}'

Die Antwort enthält username und token. access ist read oder write, und expires_in_days liegt zwischen 1 und 365 (Standard 90). Rotiere mit POST /orgs/<org>/registry-robots/<id>/rotate, optional mit {"expires_in_days": n} für ein neues Ablaufdatum, und lösche mit DELETE /orgs/<org>/registry-robots/<id>.

Der Benutzername hat die Form <org prefix>-fremforge-bot-reg-<8 hex characters>. Das Präfix ist der Name deiner Organisation, bei Bedarf gekürzt, damit der Benutzername in 40 Zeichen passt: Ein Robot von acme-infrastructure-team heißt etwa acme-infrastr-fremforge-bot-reg-1a2b3c4d. Kopiere den Benutzernamen, den die Seite oder die API anzeigt, statt ihn aus dem Namen der Organisation zusammenzusetzen. Jeder der folgenden Clients nimmt ihn als Benutzernamen und das Token als Passwort.

GitHub Actions

Hinterlege den Robot im GitHub-Repository oder in der GitHub-Organisation: den Benutzernamen als Variable FREMFORGE_REGISTRY_USER und das Token als Secret FREMFORGE_REGISTRY_TOKEN. Setze ORG auf deine fremforge-Organisation.

Container-Images

- name: Push to fremforge
  env:
    FREMFORGE_USER: ${{ vars.FREMFORGE_REGISTRY_USER }}
    FREMFORGE_TOKEN: ${{ secrets.FREMFORGE_REGISTRY_TOKEN }}
    ORG: <org>
  run: |
    echo "$FREMFORGE_TOKEN" | docker login frem.sh -u "$FREMFORGE_USER" --password-stdin
    docker build -t "frem.sh/$ORG/app:$GITHUB_SHA" .
    docker push "frem.sh/$ORG/app:$GITHUB_SHA"

Gepullt wird genauso, mit docker pull frem.sh/<org>/app:<tag>. Ein gepushter Tag lässt sich nicht überschreiben, wenn unveränderliche Releases für die Organisation eingeschaltet sind.

npm

npm sendet ein Token nur an eine Registry-URL, die exakt übereinstimmt. Gib npm deshalb die Registry des Scopes und das Token für genau diese URL:

- name: Publish to fremforge
  env:
    FREMFORGE_TOKEN: ${{ secrets.FREMFORGE_REGISTRY_TOKEN }}
    ORG: <org>
  run: |
    printf '@<scope>:registry=https://frem.sh/api/packages/%s/npm/\n//frem.sh/api/packages/%s/npm/:_authToken=%s\n' \
      "$ORG" "$ORG" "$FREMFORGE_TOKEN" > .npmrc
    npm publish

Mit derselben .npmrc installiert npm install Pakete aus @<scope>/….

PyPI

- name: Publish to fremforge
  env:
    FREMFORGE_USER: ${{ vars.FREMFORGE_REGISTRY_USER }}
    FREMFORGE_TOKEN: ${{ secrets.FREMFORGE_REGISTRY_TOKEN }}
    ORG: <org>
  run: |
    python -m pip install twine
    twine upload --repository-url "https://frem.sh/api/packages/$ORG/pypi" \
      -u "$FREMFORGE_USER" -p "$FREMFORGE_TOKEN" dist/*

Installiere mit den Zugangsdaten des Robots in der Index-URL:

pip install --index-url "https://$FREMFORGE_USER:$FREMFORGE_TOKEN@frem.sh/api/packages/$ORG/pypi/simple/" <package>

Maven

Füge einen Server mit der ID hinzu, die deine pom.xml für das fremforge-Repository verwendet, und lies den Robot aus der Umgebung:

<settings>
  <servers>
    <server>
      <id>fremforge</id>
      <username>${env.FREMFORGE_USER}</username>
      <password>${env.FREMFORGE_TOKEN}</password>
    </server>
  </servers>
</settings>
- name: Publish to fremforge
  env:
    FREMFORGE_USER: ${{ vars.FREMFORGE_REGISTRY_USER }}
    FREMFORGE_TOKEN: ${{ secrets.FREMFORGE_REGISTRY_TOKEN }}
  run: mvn --batch-mode -s .ci/settings.xml deploy

mit dem Repository in der pom.xml wie unter Maven: https://frem.sh/api/packages/<org>/maven.

Ohne gespeichertes Secret: das OIDC-Token von GitHub

Ein Robot kann statt eines gespeicherten Registry-Tokens auch das eigene OIDC-Token von GitHub Actions akzeptieren. Gib dem Robot die numerische ID deiner GitHub-Organisation (oder deines GitHub-Benutzers) und optional ein Repository, unter GitHub Actions beim Robot oder mit github_repository_owner_id und github_repository in der API. Ein Job dieses Owners fordert dann sein OIDC-Token mit der Audience https://frem.sh/<org> an (permissions: id-token: write) und tauscht es bei POST https://frem.sh/_app/api/v1/registry/oidc-token (org, robot, id_token) gegen den Benutzernamen des Robots und ein Token mit einer Stunde Laufzeit. Der Austausch ist in der API-Referenz unter Registry robots beschrieben; jedes ausgestellte Token steht mit Repository, Ref und Lauf-ID im Audit-Log.

SBOMs

SBOMs gehen an die fremforge-API, nicht an die Registry, mit einem API-Token mit dem Scope sboms:write. Siehe SBOMs aus GitHub Actions hochladen.

OpenShift und Kubernetes

Ziehe Images aus fremforge mit einem Robot mit Lesezugriff als Image Pull Secret:

kubectl create secret docker-registry frem-sh \
  --docker-server=frem.sh \
  --docker-username=<robot username> \
  --docker-password=<robot token> \
  --namespace=<namespace>

und verweise im Workload darauf:

spec:
  imagePullSecrets:
    - name: frem-sh
  containers:
    - name: app
      image: frem.sh/<org>/app:1.4.2

OpenShift liest dasselbe Secret vom Typ kubernetes.io/dockerconfigjson. Rotiere den Robot, bevor er abläuft, und ersetze das Secret durch eines, das aus dem neuen Token erstellt wurde.

Hosts, die du in einer Egress-Firewall freigeben musst

HostPortVerwendet für
frem.sh443Jede Registry-Anfrage: Logins, Indizes, Uploads sowie Manifeste und Layer von Container-Images
obs.eu-de.otc.t-systems.com443Downloads von Paketdateien außer Container-Images: npm-Tarballs, Wheels, JARs usw.

Der Download einer Paketdatei, die kein Container-Image ist, wird mit 303 und einem kurzlebigen signierten Link zur Datei im Objektspeicher unter obs.eu-de.otc.t-systems.com beantwortet, dem der Client folgt. Dieser Name ist ein CNAME von obs.lz01.eu-de.otc.t-systems.com; eine Firewall, die jeden Namen in der Kette prüft, braucht also beide. Layer von Container-Images liefert frem.sh selbst aus.

frem.sh wird über ein CDN ausgeliefert, daher ändern sich seine Adressen: Gib den Host über den Namen frei, nicht über die IP-Adresse.

Dependency Proxy

Ein Robot mit Lesezugriff zieht mit demselben Token auch über den Dependency Proxy deiner Organisation (Docker Hub, npm, PyPI und die anderen öffentlichen Registrys). Siehe Authentifizierung.