Aller au contenu

Modèle d'accès — identités, rôles, délégation

Comment GS-Apps décide qui a le droit de faire quoi. Lecture 15 min. Audience : devs, auditeurs sécurité, et administrateurs de la Console UG (volet utilisateur en fin de page). Date : 2026-06-23 | Version : 1.1

QuestionRéponseSource de vérité
Qui es-tu ?Un compte du tenant Workforce, ou un invité/membre d’un tenant autoriséAzure AD (allowlist tid)
Que peux-tu faire dans l’app ?Tes rôles (compagnie × module)BD ug.UserCompanyBcRoles
Qui administre les rôles ?Le corporate (control plane UG) délègue à un admin par compagnieConsole UG
Qui peut tout voir (superuser) ?Les corporate-admins, par grant data (pas un groupe Entra)ug (flag isCorporateAdmin)
Qui touche l’infra Azure ?Une poignée d’humains, durcis par PIM/MFA/CARôles d’annuaire Entra (plan séparé)
Identité vs Autorisation
flowchart TB
subgraph ID["PLAN IDENTITÉ — qui es-tu (Azure AD)"]
  direction LR
  T1[Tenant Workforce 27fd7029<br/>Members corporate]
  T2[Tenants autorisés<br/>Guests / B2B]
  T1 --> GATE
  T2 --> GATE
  GATE{{allowlist tid<br/>ug.Companies.azure_tid}}
end
subgraph AZ["PLAN AUTORISATION — ce que tu peux faire (BD ug)"]
  direction LR
  R[ug.UserCompanyBcRoles<br/>user × compagnie × module × rôle]
  S[ug.UserCompanyAccess<br/>scope cross-compagnie — Cas 6]
  C[isCorporateAdmin<br/>grant data]
end
GATE -->|JWT validé| AZ
classDef id fill:#eef2ff,stroke:#4338ca,color:#312e81
classDef az fill:#fef2f2,stroke:#D92231,color:#7f1d1d
class T1,T2,GATE id
class R,S,C az

Le JWT prouve l’identité (signature + issuer exact-match v1/v2 + tid dans l’allowlist — ADR-063 D-N1). Tout le reste — ce que tu peux faire — se résout côté serveur depuis la BD ug. Conséquence directe : un superuser peut venir d’un autre tenant (membre ou invité d’un tenant autorisé), parce que son pouvoir est un grant ug, découplé du tenant.

Tenant unifié Workforce 27fd7029 (ADR-055), trois populations :

PopulationuserType EntraAuthStatut
CorporateMemberMSAL Azure ADActif
TerrainGuestEmail OTPEn pause (Phase 2+)
Externes / B2BGuestOTP / OIDC fédéréPhase 2+

Toutes les App Registrations sont en signInAudience: AzureADMultipleOrgs + JWKS /common. Le backend valide JWT.tid contre l’allowlist ug.Companies.azure_tid (contrôle critique), puis résout l’utilisateur par (azure_tid, azure_oid). Une nouvelle compagnie s’onboarde par INSERT data (pas de re-déploiement de code).

La source unique des rôles est la table ug.UserCompanyBcRoles (Système C). Les groupes Azure AD comme source d’authZ sont rejetés (ADR-063 §2 / SPEC-1 D-C1) : la BD est la seule vérité.

  • Grain : (user, compagnie, bc_key, rôle). Le bc_key est un module (15 modules au catalogue, ADR-066) — vocabulaire MAJUSCULES post-nettoyage (ADM, pas ADMIN ; une contrainte CK le force).
  • Modèle : RBAC tenant-scoped + RLS (Row-Level Security). Pas de ReBAC (sur-ingénierie écartée).
  • Scope cross-compagnie : le Cas 6 du prédicat RLS (ug.UserCompanyAccess, ADR-064) autorise un user à voir plusieurs compagnies via un mapping aplati. Inerte tant qu’aucun seed.

isCorporateAdmin est une propriété de l’utilisateur résolu, dérivée de la donnée ug (appartenance/grant au niveau de la company-parent UG, écrite par la Console UG) — jamais d’un compte de service, jamais en dur (ADR-063 D-N2). Elle mappe au bypass Cas 2 du prédicat RLS. Le hardcode adminReadClaims:true historique a été retiré (CH3) : injectCompanyId() dérive désormais companyId / isCorporateAdmin du user résolu, fail-closed si absent.

ADR-070 fige un seul jeu de termes — à utiliser dans l’UI, la doc et le code neuf. Les valeurs d’enum internes restent inchangées :

Terme (humain)SensInterne consoleAccessVia
Administrateur d’organisationgod-view, toutes compagniescorporate (home UG_CORPORATE) · uca (double-clé Cas 6)
Administrateur de compagnieadmin scopé à sa compagniedelegated
Membrerôles par module, pas d’administration

Module ≠ niveau. ADM est un module (clé bc_key, ADR-066) ; ADMIN est un niveau de rôle (UTILISATEUR < GESTIONNAIRE < ADMIN). On écrit « rôle Administrateur sur le module Admin », jamais « ADM/ADMIN ». Désigner un admin est non délégable (anti-escalade : un administrateur de compagnie ne crée jamais d’admin).

ADR-067 tranche la frontière d’administration : le corporate ne micro-gère pas les rôles de chaque compagnie ; il délègue.

Deux étages de délégation
flowchart TB
subgraph D1["ÉTAGE 1 — Control plane corporate (Console UG)"]
  A1[Créer compagnies / tenants]
  A2[REACH — ug.UserCompanyAccess Cas 6]
  A3[Désigner l'admin de chaque compagnie<br/>1 ligne UCBR · ADM/ADMIN/compagnie]
  A4[Entitlement modules par compagnie<br/>ug.CompanyModules — NON délégable]
end
subgraph D2["ÉTAGE 2 — Admin délégué (par compagnie)"]
  B1[Finegrant : rôles des users<br/>de SA compagnie · scopé]
end
A3 --> B1
classDef corp fill:#eef2ff,stroke:#4338ca,color:#312e81
classDef del fill:#ecfdf5,stroke:#059669,color:#064e3b
class A1,A2,A3,A4 corp
class B1 del
  • Étage 1 (corporate) : compagnies, REACH, désigne l’admin de chaque compagnie, et fixe l’entitlement modules (quels modules une compagnie a le droit d’activer — non délégable).
  • Étage 2 (admin délégué) : fait le finegrant — les rôles des users de sa compagnie, scopé à sa compagnie.
  • Invariants : zéro double administration (D3) ; garde-fous de scope + non-escalade — un ADMIN n’accorde jamais plus qu’ADMIN, ni hors de sa compagnie / ses modules (D4) ; le corporate garde la vue god de supervision / bris de glace (D5).

Concrètement, la surface du finegrant délégué est une vue scopée de la Console UG (DelegatedConsoleView), pas N écrans séparés. Le résolveur resolveConsoleAccess (@gs/auth-multi-tenant/console-access) rend un verdict 'corporate' | 'uca' | 'delegated' | null (fail-closed : corporate court-circuite d’abord ; delegated exige ≥1 compagnie administrée).

Le « superuser » de l’app = un corporate-admin. C’est un grant data ug (isCorporateAdmin), curé — on ne l’accorde qu’aux compétents. Deux portes le gardent : (1) identité dans un tenant autorisé (allowlist tid) + (2) le grant ug. Pas de groupe Entra parallèle comme source d’authZ (ce serait une 2e liste = double administration + contredit la source unique).

6. Volet utilisateur — gérer les accès dans la Console UG

Section intitulée « 6. Volet utilisateur — gérer les accès dans la Console UG »

La Console UG (ug.groupesignalisation.ca) est le poste de pilotage des accès. Ce que tu y vois dépend de ton verdict :

Tu es corporate-admin

Tu vois la matrice complète (toutes compagnies) : créer des compagnies, donner du REACH, désigner l’admin de chaque compagnie, fixer les modules d’une compagnie. C’est aussi ta vue de supervision / bris de glace.

Tu es admin délégué d'une compagnie

Tu vois la matrice scopée à ta/tes compagnie(s) : tu gères les rôles de tes utilisateurs, dans la limite de tes modules, sans pouvoir t’auto-escalader ni toucher une autre compagnie.

Pour donner un accès : ouvre la compagnie, choisis l’utilisateur, coche le rôle pour le(s) module(s) voulu(s). L’écriture va dans ug.UserCompanyBcRoles, sous RLS — l’utilisateur la voit à sa prochaine connexion (résolution JIT).