SCOP d'ingénieurs experts du logiciel libre depuis 2004
+33 1 70 61 60 16

Délégation de droits avec Gitlab

Gitlab aime la normalisation, la composition de services. JWT est un des pivots pour déléguer des droits.

Notre prochain webinar

Gitlab se positionne comme le centre névralgique de votre atelier logiciel. Il centralise la gestion du code et des utilisateurs, mais surtout, il permet de brancher un ensemble cohérent de services qui forme le dit atelier logiciel.

Il y a une RFC pour ça

RFC7519 en l'occurrence.

Gitlab n'est pas super motivé pour réinventer la roue, et encore moins pour tout ce qui touche à la sécurité. Ils se sont pris suffisamment de CVE pour apprendre l'humilité. Gitlab s'appuie sur un ensemble de bibliothèques (rails, doorkeeper, jwt, rack-oauth2…) et de services tiers, comme la Registry de Docker .

Les jetons JWT

JWT, comme Json Web Token, est un ensemble de normes définissant des jetons (du bête clef/valeur avec un ensemble de clefs normalisées aux noms trop courts). Le tout en JSON, emballé en base64.

Ça ressemble à ça :

    [prism]
    {
        "access": [
            {
                "type": "repository",
                "name": "demo/beuha",
                "actions": [
                    "pull"
                ]
            }
        ],
        "jti": "8ad97967-165d-4c44-a0a5-b8a47f7",
        "aud": "container_registry",
        "sub": "bob",
        "iss": "gitlab-issuer",
        "iat": 1550530417,
        "nbf": 1550530412,
        "exp": 1550530717
    }
    [/prism]
    

bob a maintenant l' access à container_registry depuis l'autorité gitlab-issuer , le jeton à l'identité jti , n'est pas utilisable avant nbf , ni après exp et à été émis à iat .

Le tout est emballé dans un autre JSON, accompagné d'une signature asymétrique.

La clef (du très classique RSA) privée est coté Gitlab, et la partie publique est coté Registry.

L'utilisateur demande un jeton à Gitlab, ce jeton est confié à la Registry pour faire une action. La registry ne cause jamais au Gitlab, elle fait confiance au jeton, et surtout à sa signature.

La registry Docker

Lorsque l'on tripote la Registry sans être authentifié, on se prend un prévisible 401, et surtout un header HTTP nous donnant les informations pour s'authentifier :

Www-AuthenticateBearer realm="https://gitlab.bearstech.com/jwt/auth",service="container_registry"

On a l'URL pour soumettre notre demande, demande qui sera authentifiée avec un jeton Gitlab. Oui, il faut un jeton pour obtenir un jeton. Sauf qu'entre ces deux jetons, il y a la notion de délégation. La registry ne voit que les informations qui la concernent, et ne pourra faire aucune action coté Gitlab. Chose possible avec le jeton Gitlab.

La demande de jeton, en python , va ressembler à ça :

class Gitlab: "Gitlab server" def __init__(self, domain): self.domain = domain def token(self, project, action='pull', client_id='gitlab_ci', service='container_registry', offline_token=True): p = urllib.parse.quote_plus(project) r = requests.get(('https://{domain}/jwt/auth?' 'client_id={cid}' '&service={service}' '&offline_token={ot}' '&scope={scope}').format( domain=self.domain, cid=client_id, service=service, ot='true' if offline_token else 'false', scope='repository:%s:%s' % (p, action)), auth=(os.getenv('USER'), os.getenv('TOKEN'))) return r.json().get('token') 

Il y a quelques pinaillages comme l'escape du nom du projet exigé par Gitlab, ou le scope avec des : de partout pour décrire l' access . Pour réclamer un jeton Registry , il faut aller chercher sur son Gitlab un Jeton d'accès à l'adresse /profile/personal_access_tokens .

Gitlab nous renvoie un jeton, que l'on peut tester avec l'interface web de JWT.io .

En fournissant la clef publique à JWT.io (publique, j'insiste, celle qui est référencée dans la configuration de la Registry), il est même possible de valider la signature du jeton.

Authlib permet de faire cette vérification, avec l'aide de x5092json , par ce que la bibliothèque [cryptography] https://cryptography.io/en/latest/ a tendance à détester tous les certificats. Même quand ils passent la validation d'OpenSSL.

 openssl x509 -text -noout -in public.pem 

La recommandation trouvée sur Stack overflow est de demander à OpenSSL d'extraire juste la clef publique du certificat pour que cryptography arrête de bouder. Voilà, plus de rien, c'est plus de pureté.

Ils ont un ticket ouvert sur le thème "doit-on détester tout ce qui n'est pas cliniquement pur?".

Je garde CFSSL comme PKI, incomparable face à la bouse Easy-RSA .

Ensuite, avec le token et sa signature, il faut une couche de paranoïa, on vérifie que la signature est bien du type attendu (RSASHA256), de taille suffisante, 256, avec le bon émetteur, et qu'elle est dans sa fenêtre de validité. La bibliothèque est censée le faire, mais bon, même les paranoïaques ont des ennemis. Hum, le certificat est-il en lecture seule, pas périmé, et bien signé par votre Autorité de Certification (CA)?

La démo complète est disponible sur Github .

What else?

Voilà, vous êtes capable d'authentifier un service avec la délégation de droit de Gitlab, avec des informations sur un projet et la notion de lecture/écriture. Tout ça sans avoir à créer un nouveau service pour Gitlab.

C'est pas beau les RFCs?


Mathieu Lecarme

Inscrivez-vous à notre newsletter

Mieux comprendre le monde du DevOps et de l'administration système.

Abonnez-vous à notre newsletter

Hébergement & Infogérance

  • ✓ Service Astreinte 24h/7j/365
  • ✓ Supervision, monitoring & Alertes
  • ✓ Mises à jour en continu
  • ✓ Certificat SSL letsencrypt
  • ✓ Hébergement dédié sécurisé en France
  • ✓ Backup vers datacenter distant
Découvrir notre offre

Expertise Technologique

Notre équipe possède une vaste expertise technologique.