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.
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
| Question | Réponse | Source 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 compagnie | Console 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/CA | Rôles d’annuaire Entra (plan séparé) |
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 :
| Population | userType Entra | Auth | Statut |
|---|---|---|---|
| Corporate | Member | MSAL Azure AD | Actif |
| Terrain | Guest | Email OTP | En pause (Phase 2+) |
| Externes / B2B | Guest | OTP / 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é.
(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).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) | Sens | Interne consoleAccessVia |
|---|---|---|
| Administrateur d’organisation | god-view, toutes compagnies | corporate (home UG_CORPORATE) · uca (double-clé Cas 6) |
| Administrateur de compagnie | admin scopé à sa compagnie | delegated |
| Membre | rô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.
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
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).
Distinct : les humains qui tiennent les clés Azure (App Regs, Conditional Access, SQL db_owner, provision-app.ps1). C’est un plan séparé, durci selon la règle de l’art 2026 (ADR-069) : MFA partout, PIM (rôles eligible/JIT), Conditional Access, < 5 Global Admins, compte break-glass. Avoir une adresse UG ne donne aucun de ces droits.
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).
bc_key