Aller au contenu principal

Utiliser les registres fremforge depuis GitHub Actions et OpenShift

Votre code source et votre CI peuvent rester sur GitHub, et vos clusters sur OpenShift, tandis que les paquets résident dans votre organisation fremforge. Les deux accèdent au registre via un robot de registre : un identifiant qui appartient à l’organisation, et non à une personne.

Un robot de registre :

  • lit, ou lit et publie, les paquets d’une seule organisation, pour tous les types de paquets ;
  • peut publier mais pas supprimer : la suppression d’une version de paquet, d’un fichier, d’un tag de conteneur ou d’une image est refusée avec 403 et consignée dans le journal d’audit sous registry_robot.delete_refused. La suppression reste l’affaire d’un administrateur de l’organisation, dans l’interface web ou avec ses propres identifiants ;
  • ne peut pas lire le code, ouvrir l’interface web ni accéder à une autre organisation ;
  • n’occupe aucun utilisateur payant ;
  • a une durée de validité de 365 jours au maximum, après quoi il cesse de fonctionner, ainsi que tous ses jetons ;
  • est listé, avec la personne qui l’a créé, sous Administration de l’organisation → Sécurité → Accès → Robots de registre, et chaque création, renouvellement, suppression et suppression de paquet refusée figure dans le journal d’audit de l’organisation.

Dans la CI propre à fremforge, vous n’en avez pas besoin : une tâche Forgejo Actions dispose déjà d’un jeton pour les paquets de sa propre organisation. Voir Publier depuis Forgejo Actions.

Créer un robot

Dans la console : Administration de l’organisation → Sécurité → Accès → Robots de registre → Créer un robot. Choisissez Lire les paquets pour un secret de pull et Lire et publier les paquets (sans suppression) pour une tâche CI qui publie.

La page affiche alors une seule fois le nom d’utilisateur et le jeton du robot. Copiez les deux ; le jeton ne sera plus affiché. S’il est perdu, Renouveler le jeton en émet un nouveau et révoque immédiatement l’ancien.

Ou avec l’API, en utilisant un jeton d’API doté du 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}'

La réponse contient username et token. access vaut read ou write, et expires_in_days est compris entre 1 et 365 (90 par défaut). Renouvelez avec POST /orgs/<org>/registry-robots/<id>/rotate, éventuellement avec {"expires_in_days": n} pour fixer une nouvelle date d’expiration, et supprimez avec DELETE /orgs/<org>/registry-robots/<id>.

Le nom d’utilisateur a la forme <org prefix>-fremforge-bot-reg-<8 hex characters>. Le préfixe est le nom de votre organisation, raccourci si nécessaire pour que le nom d’utilisateur tienne en 40 caractères : un robot d’acme-infrastructure-team porte un nom du type acme-infrastr-fremforge-bot-reg-1a2b3c4d. Copiez le nom d’utilisateur affiché par la page ou par l’API plutôt que de le reconstruire à partir du nom de l’organisation. Chaque client ci-dessous l’utilise comme nom d’utilisateur, et le jeton comme mot de passe.

GitHub Actions

Enregistrez le robot dans le dépôt ou l’organisation GitHub : le nom d’utilisateur comme variable FREMFORGE_REGISTRY_USER et le jeton comme secret FREMFORGE_REGISTRY_TOKEN. Définissez ORG sur votre organisation fremforge.

Images de conteneurs

- 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"

Récupérez de la même manière, avec docker pull frem.sh/<org>/app:<tag>. Un tag poussé ne peut pas être écrasé lorsque les versions immuables sont activées pour l’organisation.

npm

npm n’envoie un jeton qu’à une URL de registre qui correspond exactement ; indiquez-lui donc le registre du scope et le jeton pour cette 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

Le même .npmrc permet d’installer les paquets @<scope>/… avec npm install.

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/*

Installez avec les identifiants du robot dans l’URL de l’index :

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

Maven

Ajoutez un serveur portant l’id que votre pom.xml utilise pour le dépôt fremforge, en lisant le robot depuis l’environnement :

<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

avec le dépôt déclaré dans pom.xml comme dans Maven : https://frem.sh/api/packages/<org>/maven.

Sans secret stocké : le jeton OIDC de GitHub

Un robot peut aussi accepter le jeton OIDC de GitHub Actions à la place d’un jeton de registre stocké. Indiquez au robot l’id numérique de votre organisation GitHub (ou de votre utilisateur) et, éventuellement, un dépôt, sous GitHub Actions sur le robot, ou avec github_repository_owner_id et github_repository dans l’API. Une tâche de ce propriétaire demande alors son jeton OIDC avec l’audience https://frem.sh/<org> (permissions: id-token: write) et l’échange sur POST https://frem.sh/_app/api/v1/registry/oidc-token (org, robot, id_token) contre le nom d’utilisateur du robot et un jeton valable 1 heure. L’échange est décrit dans la référence de l’API sous Registry robots ; chaque jeton qu’il émet figure dans le journal d’audit avec le dépôt, la ref et l’id d’exécution.

SBOM

Les SBOM sont envoyés à l’API fremforge, et non au registre, avec un jeton d’API doté du scope sboms:write. Voir Téléverser des SBOM depuis GitHub Actions.

OpenShift et Kubernetes

Récupérez les images depuis fremforge avec un robot en lecture seule utilisé comme secret de pull d’images :

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

et référencez-le depuis la charge de travail :

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

OpenShift lit le même secret kubernetes.io/dockerconfigjson. Renouvelez le robot avant son expiration et remplacez le secret par un nouveau créé à partir du nouveau jeton.

Hôtes à autoriser dans un pare-feu sortant

HôtePortUtilisation
frem.sh443Toutes les requêtes au registre : connexions, index, téléversements, ainsi que manifestes et couches des images de conteneurs
obs.eu-de.otc.t-systems.com443Téléchargements des fichiers de paquets autres que les images de conteneurs : tarballs npm, wheels, JAR, etc.

Le téléchargement d’un fichier de paquet autre qu’une image de conteneur répond 303 avec un lien signé de courte durée vers le fichier dans le stockage objet sur obs.eu-de.otc.t-systems.com, que le client suit. Ce nom est un CNAME de obs.lz01.eu-de.otc.t-systems.com ; un pare-feu qui vérifie chaque nom de la chaîne a donc besoin des deux. Les couches des images de conteneurs sont servies par frem.sh lui-même.

frem.sh est servi via un CDN, ses adresses changent donc : autorisez-le par nom, et non par adresse IP.

Proxy de dépendances

Un robot disposant d’un accès en lecture récupère aussi les paquets via le proxy de dépendances de votre organisation (Docker Hub, npm, PyPI et les autres registres publics), avec le même jeton. Voir Authentification.