Rôles, groupes et permissions¶
Ce qu'un compte utilisateur peut faire dans
l'interface web et l'API REST vient uniquement de rôles, un rôle étant un ensemble de
permissions, donnés à ses groupes, chacun sur tous les projets ou sur une liste de
projets. Un compte n'a jamais de rôle ni de projet propre : pour donner un accès à une personne,
ajoutez-la à un groupe. Les administrateurs les gèrent dans les écrans Groupes,
Rôles et Utilisateurs (permission users.manage), ou par l'API /api/v1/groups,
/api/v1/roles et /api/v1/users.
Les jetons Bearer sont destinés aux machines et gardent leur rôle fixe (mcp, admin, ci,
metrics, voir Rôles), sauf les jetons api de l'API REST et
de son Swagger, qui suivent ce modèle (voir jetons API) :
un jeton personnel porte les droits actuels de son utilisateur, un jeton de rôle les permissions
d'un rôle sur ses projets. Une personne obtient la lecture ou le triage par les groupes de son
compte.
Permissions¶
| Permission | Autorise | Par projet |
|---|---|---|
reports.read |
Projets, rapports, findings, posture, tendance, SARIF | ✅ |
findings.triage |
Changer le statut d'un finding, rejeter la proposition d'un agent | ✅ |
rules.manage |
Règles de scan et checklists | |
standards.manage |
Normes de développement | |
tokens.manage |
Jetons de projet | |
settings.manage |
Langue des rapports, proxy sortant, base d'avis | |
users.manage |
Utilisateurs, groupes, rôles et configuration OIDC (elle décide qui rejoint quel groupe) | |
audit.read |
Journal d'audit | |
projects.create |
Créer un nouveau projet, que son créateur lit ensuite (voir Création d'un projet), et valider ou refuser les projets demandés par un enrôlement | |
projects.delete |
Supprimer un projet avec ses rapports, ses findings et ses références (voir Suppression d'un projet) | |
mcp_tokens.create |
Créer un jeton MCP personnel dans Mon compte |
users.manage permet à son détenteur de se donner toutes les autres permissions : ne la donnez
qu'aux administrateurs. Accepter un risque ou marquer un faux positif demande en plus une session
de l'interface web, jamais un jeton (voir triage des findings).
Rôles¶
Un rôle est un nom, une description et au moins une permission. Deux rôles intégrés existent dès le départ et ne peuvent être ni modifiés ni supprimés, car le contrôleur s'appuie sur eux :
| Rôle intégré | Permissions | Utilisé par |
|---|---|---|
reader |
reports.read |
les groupes de projet des projets validés ou créés |
admin |
toutes les permissions (y compris celles qu'ajoute une version ultérieure) | le groupe administrators du premier administrateur, SECREVIEW_OIDC_ADMIN_GROUPS |
Deux rôles ordinaires sont aussi créés avec la base : les administrateurs les modifient ou les suppriment comme n'importe quel autre.
| Rôle ordinaire | Permissions | Donne |
|---|---|---|
triager |
reports.read, findings.triage |
le triage des findings |
mcp-user |
mcp_tokens.create |
la création d'un jeton MCP personnel ; donnez-le avec un rôle de lecture, car le jeton atteint les projets que son utilisateur peut lire |
Les administrateurs créent d'autres rôles (100 au plus), par exemple un rôle Auditeur avec
audit.read et reports.read. La modification d'un rôle s'applique aussitôt aux sessions
ouvertes des membres de ses groupes ; supprimer un rôle le retire de ses groupes.
Groupes¶
Un groupe a un nom (200 caractères au plus), une description, des rôles et des membres. Chaque
rôle d'un groupe s'applique à tous les projets, ou seulement à une liste de projets
(50 au plus) quand le rôle n'est fait que de permissions par projet (reports.read,
findings.triage). Un rôle qui contient une permission sur tout le contrôleur s'applique
toujours à tous les projets.
Les membres ont deux origines :
- locale : ajoutés par un administrateur (écran Groupes ou Utilisateurs, CLI) ;
- OIDC : quand le groupe est ouvert au OIDC, les utilisateurs OIDC dont le claim des groupes contient exactement le nom du groupe le rejoignent à chaque connexion (voir OIDC). Les valeurs du claim qui ne nomment aucun groupe sont ignorées.
Un nouveau groupe n'est ouvert au OIDC que sur demande ("sso": true par l'API).
Renommer un groupe, ou le fermer au OIDC, retire aussitôt ses membres OIDC.
Groupes de projet¶
Le groupe de projet d'un projet est un groupe non ouvert au OIDC dont le seul rôle est
reader sur ce seul projet. La validation d'un enrôlement le
crée sans aucun membre (pour que le projet existe, sans donner d'accès), et la
création d'un projet le crée avec son créateur. Un groupe existant de ce
type est réutilisé (même créé par un administrateur, quel que soit son nom) ; sinon le groupe
project:<projet> est créé (avec un numéro, par exemple project:shop (2), quand un autre groupe
porte déjà ce nom). Un administrateur donne à un développeur la lecture du projet en ajoutant son
compte à ce groupe (voir lecture du projet) : tous les développeurs
d'un projet partagent ainsi un groupe, géré comme les autres.
Création d'un projet¶
Un utilisateur dont les groupes portent projects.create crée un projet avec le bouton
Nouveau projet (à gauche d'Actualiser) de l'écran Projets, dans une fenêtre modale (POST /api/v1/projects, depuis une session de l'interface web
uniquement : un jeton ne crée jamais de projet). Le contrôleur crée le
groupe de projet du projet et y ajoute le compte comme membre local : le
compte lit aussitôt le projet, de même que son
jeton MCP personnel, qui peut alors y
enregistrer les rapports de son agent. Le projet apparaît sur l'écran Projets,
Aucun rapport, jusqu'à son premier rapport.
Le nom est normalisé (Mobile App crée
mobile-app). Seul un nouveau projet peut être créé : un nom qui a déjà un rapport, qu'un rôle d'un groupe
cite (projet validé compris), ou qu'un jeton atteint est refusé (409) ; un projet encore en
attente n'est pas encore connu : le créer solde sa demande, pour que cette
permission n'ouvre jamais les rapports d'un projet existant. Le créateur n'obtient que reader ;
un administrateur donne le triage ou d'autres membres par les groupes, comme d'habitude. Chaque
création est inscrite au journal d'audit (project.created).
curl -X POST -H "Authorization: Bearer $SESSION" -H "Content-Type: application/json" \
https://secreview.example.com/api/v1/projects -d '{"project": "mobile-app"}'
# {"project": "mobile-app", "reports_total": 0, "last_report_at": null, …}
Suppression d'un projet¶
Un utilisateur dont les groupes portent projects.delete (seul admin par défaut) supprime un
projet avec le bouton corbeille de sa ligne sur l'écran Projets, après confirmation
(DELETE /api/v1/projects/{project}, depuis une session de l'interface web uniquement : un
jeton ne supprime jamais de projet). La suppression est irréversible et retire, en une seule
transaction, tout ce qui se rapporte au projet :
- ses rapports, avec leurs findings et les commentaires de ces findings ;
- le projet dans les rôles des groupes : un rôle qui n'a plus de projet est retiré (jamais laissé sur tous les projets), et un groupe de projet qui n'a plus de rôle est supprimé avec ses membres ; tout autre groupe est conservé ;
- le projet dans les jetons : un jeton qui n'atteint aucun autre projet est révoqué (jamais laissé sur tous les projets), les autres gardent leurs autres projets.
Le journal d'audit conserve les événements du projet et inscrit project.deleted, avec les
comptes dans son détail ; chaque groupe et jeton modifié ou supprimé a son propre événement
(group.deleted, group.roles_changed, token.revoked, token.projects_changed). Un projet
inconnu donne 404.
curl -X DELETE -H "Authorization: Bearer $SESSION" \
https://secreview.example.com/api/v1/projects/mobile-app
# {"project": "mobile-app", "reports": 3, "findings": 12, "groups_deleted": ["project:mobile-app"], …}
Ce qu'un utilisateur peut faire¶
Les permissions d'un utilisateur sont l'union des permissions des rôles de tous ses groupes.
Chaque permission garde ses propres projets : elle couvre tous les projets si l'un de ses rôles
les couvre, sinon l'union de leurs projets (200 au plus par permission : au-delà, le compte n'a
aucun accès). Un utilisateur reader sur tous les projets par un groupe et triager sur crm
par un autre lit tous les projets et ne trie que crm.
Un changement de groupe (rôles, membres) ou de rôle s'applique aussitôt aux sessions ouvertes. Un compte sans aucune permission ne peut pas se connecter, et ses sessions ouvertes s'arrêtent.
Un utilisateur n'a pas de rôle à lui : GET /api/v1/me renvoie ses permissions, chacune avec
ses projets (null : tous les projets), et role vaut toujours user pour une session web (le
rôle du jeton sinon). L'écran Utilisateurs et Mon compte affichent ces permissions telles
quelles : un utilisateur qui ne gère que les jetons et les normes ne lit aucun projet. Une session
web ne passe jamais pour un jeton admin, même avec toutes les permissions : les routes réservées
aux jetons (/metrics, les scans de pipeline) la refusent.
{"client": "alice", "role": "user", "projects": null,
"permissions": {"reports.read": null, "findings.triage": ["crm"]}, …}
Le dernier administrateur¶
Au moins un compte garde users.manage : supprimer ce compte, son groupe, le rôle de son groupe
ou la permission de son rôle est refusé (409 ou 422). Une connexion OIDC qui retire le dernier
détenteur de son groupe OIDC n'est pas bloquée : le fournisseur d'identité reste l'autorité.
Gardez de préférence un administrateur local.
Jetons créés depuis l'interface¶
Un jeton ne donne jamais plus que ce que détient son créateur : créer un jeton, changer ses
projets, renouveler son secret ou le révoquer demande reports.read sur tous les projets du jeton, avant et après un changement de ses
projets, et, pour un jeton api de rôle, chaque permission de son rôle sur ces projets ; l'écran Jetons ne liste que les jetons des projets que l'utilisateur
lit.
API¶
# Un rôle et un groupe qui le donne sur le projet « billing », ouvert au OIDC
curl -X POST https://secreview.example.com/api/v1/roles \
-H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "Auditor", "description": "Reads the log", "permissions": ["audit.read", "reports.read"]}'
curl -X POST https://secreview.example.com/api/v1/groups \
-H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "payments-team", "description": "", "sso": true}'
curl -X PUT https://secreview.example.com/api/v1/groups/4/roles \
-H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \
-d '{"roles": [{"role_id": 2, "projects": ["billing"]}]}'
curl -X PUT https://secreview.example.com/api/v1/groups/4/members \
-H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \
-d '{"user_ids": [7, 9]}'
# Les groupes locaux du compte 7 (ses groupes OIDC sont gardés)
curl -X PUT https://secreview.example.com/api/v1/users/7 \
-H "Authorization: Bearer $ADMIN_TOKEN" -H "Content-Type: application/json" \
-d '{"group_ids": [4]}'
| Route | Effet |
|---|---|
GET /api/v1/permissions |
Permissions qu'un rôle peut contenir, et si elles peuvent être limitées à des projets |
GET, POST /api/v1/roles ; PUT, DELETE /api/v1/roles/{id} |
Rôles |
GET, POST /api/v1/groups ; PUT, DELETE /api/v1/groups/{id} |
Groupes (GET renvoie aussi la configuration OIDC qui les utilise) |
PUT /api/v1/groups/{id}/roles |
Remplace les rôles d'un groupe |
PUT /api/v1/groups/{id}/members |
Remplace les membres locaux d'un groupe (les membres OIDC sont gardés) |
POST /api/v1/users |
Crée un utilisateur, membre des groupes group_ids |
PUT /api/v1/users/{id} |
Remplace les groupes locaux (group_ids) d'un utilisateur ; un champ absent reste inchangé |
Un champ roles dans le corps de ces deux routes est refusé (422) : un compte n'a pas de rôle
propre.
Chaque modification est écrite au journal d'audit (role.*,
group.*, user.groups_changed). En CLI, security-review-controller user set-groups change les
groupes d'un compte, et security-review-controller group list / group roles liste les groupes et les rôles (voir
CLI).
Mise à jour depuis les rôles fixes¶
La migration de schéma 0013 déplace les anciens accès dans des groupes :
- chaque association de rôle OIDC devient un groupe ouvert au OIDC du nom de son groupe, avec le rôle de l'association sur les mêmes projets ;
- chaque compte qui avait un rôle propre rejoint
administrators,triagersoureaders(groupes non ouverts au OIDC) s'il voyait tous les projets, sinon un groupe personneluser:<nom>.
La migration de schéma 0014 transforme ensuite chaque groupe personnel user:<nom> dont le seul
membre est ce compte (ajouté par un administrateur) en rôles directs du compte, sur les mêmes
projets, et supprime le groupe. Un groupe personnel qui a d'autres membres, ou ouvert au OIDC, est
gardé.
La migration de schéma 0018 supprime ces rôles directs : chacun devient l'appartenance locale à
un groupe non ouvert au OIDC qui a le même rôle sur les mêmes projets, de sorte que personne ne
perd ni ne gagne d'accès (dernier administrateur compris). Un rôle sur une liste de projets donne
un groupe par projet, project:<projet> pour reader (le groupe de projet),
sinon project:<projet>:<rôle> ; un rôle sur tous les projets donne le groupe role:<rôle>. Un
groupe existant non ouvert au OIDC dont le seul rôle est le même (comme administrators pour
admin) est réutilisé.
Le rôle donné à un compte OIDC par ses groupes à sa dernière connexion est recalculé à sa
prochaine connexion. Les variables SECREVIEW_OIDC_TRIAGER_GROUPS, SECREVIEW_OIDC_READER_GROUPS
et SECREVIEW_OIDC_DEFAULT_ROLE disparaissent : créez les groupes de mêmes noms avec le rôle
triager ou reader, et utilisez SECREVIEW_OIDC_DEFAULT_GROUP à la place du rôle par défaut.
Mise à jour depuis les jetons reader et triager¶
La migration de schéma 0021 réserve les jetons aux machines :
- les jetons
readerettriagersont révoqués ; chaque révocation est écrite dans le journal d'audit (token.revoked, acteurmigration). Donnez aux personnes qui les utilisaient un compte utilisateur dans un groupe qui a le rôlereaderoutriagersur les mêmes projets ; un script d'administration utilise un jetonadmin; - le rôle
triagern'est plus intégré : il garde ses permissions et ses groupes, et peut désormais être modifié ou supprimé.