CI/CD avec GitHub et signatures avec cosign
Objectifs
- Construire une image de conteneur automatiquement avec les GitHub Workflows / Actions
- Signer une image de conteneur avec cosign
- Configurer podman pour n’accepter que des images de conteneur signées
CI/CD avec les GitHub Workflows / Actions
- Créer un compte GitHub si vous n’en avez pas déjà un
- Ajouter un clé SSH à votre compte
- Créer un nouveau dépot public sur GitHub
- Cloner le dépôt en local sur votre machine
Ajouter un
Containerfile
pour créer une image de conteneur :conteneur/Containerfile
:FROM registry.fedoraproject.org/fedora:39 RUN touch /insa-cvl
Ajouter le workflow GitHub suivant :
.github/workflows/conteneur.yml
:name: "Build container image" env: NAME: "conteneur" # Si votre identifiant de compte GitHub comporte des majuscules, remplacez # '${{ github.repository_owner }}' par votre identifiant en miniscule uniquement REGISTRY: ghcr.io/${{ github.repository_owner }} # Ce workflow ne sera exécuté que lors d'un 'push' sur la branche 'main' on: push: branches: - main # Authorise : # - Accès en lecture seule au contenu du dépôt Git # - Accès en lecture/écriture au "packages" pour avoir l'accès au registre de # conteneurs de GitHub permissions: contents: read packages: write jobs: build-push-image: runs-on: ubuntu-latest steps: # Récupération du dépôt Git - name: Checkout repo uses: actions/checkout@v4 # Construction de l'image de conteneur avec buildah - name: Build container image uses: redhat-actions/buildah-build@v2 with: context: ${{ env.NAME }} image: ${{ env.NAME }} tags: latest containerfiles: ${{ env.NAME }}/Containerfile layers: false oci: true # Publication de l'image de conteneur dans le regsitre de GitHub avec podman - name: Push to Container Registry uses: redhat-actions/push-to-registry@v2 id: push with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} image: ${{ env.NAME }} tags: latest
Vous devez obtenir une organisation comme suit :
$ tree -a . ├── conteneur │ └── Containerfile ├── .git │ └── ... └── .github └── workflows └── conteneur.yml
Commiter et poussez vos changements dans votre dépôt distant.
Observer la construction de votre image dans l’onglet Actions.
Vérifier que votre image est bien construite et disponible dans le registre de conteneur de GitHub à l’aide de l’interface Web.
Tester votre image :
$ podman run --rm -ti ghcr.io/<utilisateur GitHub>/conteneur # ls / ... insa-cvl ...
Sigstore et Cosign
Installer cosign. Suivre la documentation en ligne: https://docs.sigstore.dev/system_config/installation/
Générer une clé pivée et publique pour signer les conteneurs avec cosign
$ cosign generate-key-pair
Connectez vous au registre de conteneurs GitHub de votre dépôt :
$ podman login ghcr.io/<utilisateur GitHub>
Si vous utilisez l’authentification multi-facteurs, suivez la documentation GitHub pour créer un access token à utiliser comme mot de passe dans la commande précédente.
Si nécessaire, copiez les token d’authentification de podman à l’emplacement de ceux de Docker :
$ cp ${XDG_RUNTIME_DIR}/containers/auth.json ~/.docker/config.json
Signer votre image avec cosign :
$ cosign sign --key cosign.key ghcr.io/<utilisateur GitHub>/conteneur
Vérifier la signature ajoutée à l’image avec cosign :
$ cosign verify --key cosign.pub ghcr.io/<utilisateur GitHub>/conteneur
Signatures avec cosign dans le workflow GitHub
Nous allons ensuite automatiser cette procédure à l’aide du workflow GitHub :
- Ajouter la clé privée
cosign.key
comme secret dans GitHub :- Aller dans les préférences du dépôt, puis “Secrets et variables”, puis “Actions”
- Ajouter la clé privée dans les secrets associés au dépôt
- Nommer le secret
COSIGN_PRIVATE_KEY
Ajouter la signature du conteneur à l’aide de cosign dans le workflow GitHub, à la suite du contenu existant :
... # Authentification au registre de conteneur de GitHub - name: Login to Container Registry uses: redhat-actions/podman-login@v1 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # Installation de cosign - uses: sigstore/cosign-installer@v3.3.0 # Signature de l'image de conteneur - name: Sign container image run: | cosign sign -y --key env://COSIGN_PRIVATE_KEY ${{ env.REGISTRY }}/${{ env.NAME }}@${{ steps.push.outputs.digest }} env: COSIGN_EXPERIMENTAL: false COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
Attendre qu’une nouvelle version de l’image soit publiée dans le registre de conteneur
Vérifier la signature de la nouvelle image à l’aide de cosign :
$ cosign verify --key cosign.pub ghcr.io/<utilisateur GitHub>/conteneur
Configurer Podman pour vérifier les signatures
Nous allons configurer podman sur notre système pour qu’il vérifie la signature des images de conteneurs et qu’il refuse les images non signées.
Installer la clé publique :
$ sudo mkdir -p /etc/pki/containers $ sudo cp cosign.pub /etc/pki/containers/ $ sudo restorecon -RFv /etc/pki/containers
Ajouter la configuration du registre pour récupérer les signatures :
$ cat /etc/containers/registries.d/ghcr.io-<utilisateur GitHub>.yaml docker: ghcr.io/<utilisateur GitHub>: use-sigstore-attachments: true $ sudo restorecon -RFv /etc/containers/registries.d/ghcr.io-<utilisateur GitHub>.yaml
Configurer ensuite la politique utilisée par podman. Modifier le fichier
/etc/containers/policy.json
pour obtenir la configuration suivante. Les...
signifient de laisser les valeurs qui se trouvent déjà dans le fichier à ces emplacements :{ "default": [ { "type": "reject" } ], "transports": { "docker": { "ghcr.io/<utilisateur GitHub>": [ { "type": "sigstoreSigned", "keyPath": "/etc/pki/containers/ghcr.io-<utilisateur GitHub>.pub", "signedIdentity": { "type": "matchRepository" } } ], ... "": [ { "type": "insecureAcceptAnything" } ] }, ... } }
La page de man qui explique les options de configuration utilisées : containers-policy.json(5)
Vérifier que seul les conteneurs signés sont acceptés :
$ podman rmi --force ghcr.io/<utilisateur GitHub>/conteneur $ podman pull ghcr.io/<utilisateur GitHub>/conteneur $ podman run --rm -ti ghcr.io/<utilisateur GitHub>/conteneur
Ajouter une copie du workflow initial pour créer un autre conteneur non signé dans le même repo mais avec un autre tag et vérifier qu’il n’est pas accepté par podman
Références
- Exemple complet avec support multi-architectures: