Aller au contenu

Autorisation — qui peut faire quoi, et comment vous le prouvez

Control Center répond à deux questions d’autorisation, et elles sont réellement différentes. « Cette personne peut-elle appeler cette opération ? » porte sur les humains, les rôles et les dépôts. « Cet agent peut-il provoquer cet effet ? » porte sur les actions, les arguments et le rayon d’impact — cette question-là relève des Garde-fous.

Cette page traite la première question, ainsi que la trace que l’une et l’autre laissent derrière elles.

Toute décision d’autorisation côté humain se résout à travers une seule fonction :

can(principal, permission, resource) → allow | deny + why

Une permission s’écrit <domain>:<tier> — tickets:write, members:administer, repos:read. Le catalogue est dérivé, et non écrit à la main : il est calculé à partir de la surface d’opérations elle-même (le préfixe du nom de l’opération donne le domaine, le rôle minimal que celle-ci applique déjà donne le niveau), si bien que les ~550 opérations portent une permission sans que personne n’ait à en saisir une.

Cette dérivation est la propriété qui vaut la peine d’être protégée. Elle signifie qu’une opération NOUVELLE est contrôlée par défaut — le mode de défaillance d’un modèle annoté à la main, c’est que quelqu’un oublie, et ce qu’il oublie est précisément le contrôle. Un test à cliquet fige l’ensemble des domaines obtenu, de sorte qu’ajouter une opération sous un nouveau préfixe relève d’une décision de nommage prise par un humain plutôt que d’un accident.

Les quatre niveaux correspondent exactement aux rôles intégrés :

Niveau Rôle minimal Exemple
read Invité tickets:read
write Membre tickets:write
administer Admin members:administer
own Propriétaire workspace:own

Cinq rôles intégrés — propriétaire, admin, membre, lecteur, invité — sont des préréglages posés au-dessus de ce catalogue. La propriété est un siège unique par espace de travail, transmis explicitement via Transférer la propriété (un propriétaire qui s’en va est sinon impossible à retirer : le déprovisionnement SCIM refuse tout propriétaire d’espace de travail — transférez d’abord).

Les rôles personnalisés sont soustractifs. Un rôle personnalisé nomme un préréglage de base (admin, member, viewer ou guest — jamais owner) et un ensemble de permissions RETIRÉES de celui-ci — « admin, mais sans la gestion des membres ». Il ne peut jamais accorder davantage que sa base, ce qui est précisément ce qui les rend sûrs à introduire dans une installation existante : chaque contrôle existant reste une borne supérieure valide. Les membres les détiennent sous la forme custom:<id>, et un client trop ancien pour comprendre cette valeur retombe sur invité plutôt que de deviner.

Sous les rôles se trouvent les attributions par dépôt (none / read / review / write) : l’appartenance à un espace de travail ne confère jamais silencieusement plus de droits que la forge. Toutes les surfaces qui exposent du code les vérifient — y compris celles qui atteignent le code par la bande, comme un terminal ou une session d’éditeur ouverte sur l’arbre de travail d’un espace.

Certaines opérations ne concernent pas du tout un espace de travail : les réglages à l’échelle de l’installation, la configuration SSO, les identifiants des fournisseurs, la gestion des modèles, les sauvegardes complètes de l’installation. Celles-là déclarent une autorité serveur et sont refusées à tout le monde sauf à l’opérateur de l’installation (le propriétaire de serveur enregistré). Il existe délibérément une seule identité d’opérateur, et une seule définition de celle-ci.

Chaque décision d’autorisation — accordée comme refusée — est ajoutée à un journal d’audit chaîné par hachage, propre à chaque espace de travail.

Un journal qui ne consigne que les refus répond à la question « qu’avons-nous bloqué ? » mais pas à « qu’a réellement fait cet agent, et qui l’a autorisé ? », qui est la question par laquelle commence un retour d’incident. Chaque entrée enregistre donc toute la chaîne d’attribution : le principal agissant, l’humain au nom duquel il a agi, la délégation par laquelle il est arrivé, l’action et ses arguments (sous forme d’empreinte), la décision, et la règle qui a décidé.

Les entrées sont chaînées : le hachage de chacune couvre celui de la précédente, si bien que modifier, supprimer ou réordonner une ligne rompt tous les hachages qui suivent. Vérifier la chaîne recalcule la chaîne entière et nomme le premier maillon qui ne tient pas. Un journal d’audit que vous ne pouvez pas contrôler reste un journal ; un journal que vous pouvez recalculer est une preuve.

Deux conséquences qu’il vaut la peine de connaître :

  • La table d’audit est exemptée de la purge fondée sur l’âge. Une chaîne de hachages ne peut pas être tronquée par le milieu. La rétention procède par export puis troncature, et la troncature laisse un point de contrôle portant le hachage terminal du segment supprimé : ce qui subsiste se vérifie donc toujours depuis le début.
  • Elle se trouve à côté de la chronologie d’activité, et non au-dessus. La chronologie montre ce que les gens ont fait ; le journal, ce qui a été autorisé et refusé. Un identifiant de corrélation partagé relie un même appel dans les deux.

Il s’exporte en JSON délimité par des sauts de ligne et peut être diffusé en flux vers un SIEM (Splunk, Elastic, Sentinel — un point de terminaison HTTP avec un jeton bearer). La diffusion en flux est au mieux par conception : un SIEM indisponible ne doit jamais bloquer l’appel d’outil d’un agent, et la copie durable et vérifiable se trouve sur le disque dans tous les cas.

Une installation peut définir un âge maximal de session et un délai d’inactivité. Les deux sont appliqués lors du contrôle des identifiants d’appareil par lequel passe chaque voie authentifiée — une limite de session qu’un client peut ignorer s’adresse à un questionnaire, pas à un attaquant. Une installation peut aussi exiger SSO, ce qui désactive l’association manuelle de nouveaux appareils (avec une garde anti-enfermement : l’exigence est refusée tant qu’aucune connexion SSO fonctionnelle n’existe).

  • Pas des ACL par objet. Il n’existe délibérément aucune permission par ticket ni par message. La séparation au niveau des dépôts est ce que les équipes demandent réellement, et elle existe ; le partage par objet est une surface combinatoire dont la demande n’est pas démontrée ici.
  • Pas un moteur de politique que l’on configure dans un DSL. Le vocabulaire est fermé à dessein, de sorte que toute la politique peut être rendue, expliquée et énumérée.
  • Pas appliqué ailleurs qu’au serveur. Les vérifications côté client n’existent que pour éviter de proposer un contrôle qui sera refusé. La décision faisant autorité est toujours celle du serveur.