Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problème
Fournir un certificat à Repod demandait de connaître trois procédures distinctes, dont deux n'étaient écrites nulle part.
scripts/gen-selfsigned-certs.sh, seul chemin documenté.nginx/tls-proxy.confpour le faire pointer vers/certs/letsencrypt/live/$DOMAIN/. C'est un fichier suivi par git : la modification entre en conflit au prochaingit pullet n'est rejouée sur aucune nouvelle instance. La première émission butait en plus sur une dépendance circulaire non documentée : nginx refuse de démarrer sans certificat, et sans nginx le challenge ACME n'est pas servi sur:80. Le renouvellement n'était câblé nulle part.Et le certificat obtenu ne couvrait que l'UI et l'API : les dépôts de paquets restaient en HTTP clair alors que le proxy TLS était déjà devant eux. La signature GPG protège l'intégrité, mais l'inventaire des paquets et des versions installées circulait en clair. En mode TLS, la page « Configuration client » générait par-dessus le marché des commandes bâties sur
https://<host>:80, une URL qui ne répond pas.Ce que fait cette PR
Un point d'entrée unique,
scripts/setup-tls.sh, qui alimente toujours le même couple canoniquerepos/certs/tls/{cert.pem,key.pem}(celui que nginx et Traefik lisent déjà). Plus aucun fichier suivi par git à éditer après une émission, et le script recharge lui-même le proxy actif.Le mode
csrproduit une requête multi-SAN à faire signer par l'autorité de l'organisation : un dépôt interne est joint sous plusieurs noms, et souvent aussi par IP depuis les machines sans résolution DNS. La clé est écrite danspending/, jamais au chemin canonique (il peut s'écouler des jours avant la signature), pendant lesquels le certificat en service ne doit pas bouger. Au retour,import --cert repod.crt --chain ca.pemsans--keyreprend cette clé, vérifie qu'elle correspond, installe et videpending/.Tous les contrôles tournent avant la moindre écriture, et l'installation est atomique. Sont refusés : un certificat qui ne correspond pas à la clé, une clé protégée par une phrase de passe (nginx démarre sans terminal, elle ne pourrait
jamais être saisie), un certificat expiré. Sont signalés : une chaîne intermédiaire absente ou dans le mauvais ordre (l'échec habituel d'une PKI AD CS à deux niveaux), qu'il vaut mieux voir avant la mise en service que dans les journaux des clients (et une expiration à moins de trente jours).
Côté Let's Encrypt, un
--deploy-hookrecopie le certificat vers le chemin canonique. Le hook étant enregistré dans le fichier de renouvellement à l'émission,certbot renewle rejoue seul. Un mode résident sans cron est fourni en bloc commenté, sans jamais monter le socket Docker.Enfin, les dépôts sont servis par le proxy sur
:443sous le même certificat que l'UI :/repos/et/apk/vers apt-repo,/rpm/vers rpm-repo, avec parité Traefik.Découpage
feat(tls): point d'entrée unique de fourniture du certificatscripts/setup-tls.shfeat(tls): installer le certificat Let's Encrypt sans éditer la conf nginxfix(stats): préserver l'IP client des téléchargements derrière un proxyreal_ipdans les deux dépôtsfeat(tls): servir les dépôts APT/RPM/APK derrière le certificat du proxyfix(ui): URLs de dépôt cassées en mode TLS sur la page Configuration clientapi.js+ 8 testsdocs(tls): réécrire la section de déploiement TLS.env.exampleLe commit
real_ipprécède volontairement l'exposition des dépôts :download_stats.pycompte les clients uniques sur$remote_addr, et sans lui tous les téléchargements passant par le proxy se confondraient en un seul client. Isolé, il est sans effet.Compatibilité
Rien ne casse, et rien n'est à migrer côté clients.
sources.listet.repodéjà déployés continuent de fonctionner à l'identique. Le HTTPS est un accès supplémentaire, pas un remplacement.scripts/gen-selfsigned-certs.shn'est pas modifié, etsetup-tls.sh self-signed <HÔTE>lui délègue : résultat identique àl'existant dans le cas mono-hôte.
repos/certs/letsencryptdansnginx-proxyest conservé : les déploiements qui ont déjà fait pointertls-proxy.confverslive/$DOMAIN/continuent de fonctionner.Vérifications
/repos/dists/…,/repos/pool/*.deb,/apk/…/APKINDEX.tar.gz,/rpm/…/repodata/repomd.xmlet/rpm/…/*.rpmrépondent 200 en HTTPS avec le bon contenu,/atteint toujours le frontend, et les en-têtes de sécurité du blocserversont bien hérités par leslocationde dépôt./rpm=>/rpm/,/rpm/almalinux9=>/rpm/almalinux9/,/repos/pool→/repos/pool/, toutes enhttps://et préfixe conservé.downloads.logjournalise l'IP du conteneur client et non celle du proxy, pour un.debcomme pour un.rpm.StripPrefixcorrect, HSTS présent, IP client préservée.csrmulti-SAN, signature par une PKI de test à deux niveaux,importsans--key. Refus vérifiés sur clé non correspondante, clé chiffrée, mauvais mot de passe PKCS#12, requête déjà en attente,csrsans--san.openssl pkcs12 -export: feuille et intermédiaire installés.nginx -tvert sur les trois configurations,docker compose configvert sur les trois combinaisons d'overlays,shellcheckpropre,vitest runà 58 tests verts dont 8 nouveaux.Pour rejouer localement