Lab Identity Governance Fabric · Reference

MCP Gateway Authorization — As-Built Topology

how one AD-rooted group model, rendered from policy-as-code, governs three gateways with one job each — agentgateway (MCP tools · live), Envoy AI Gateway (LLM providers), Cisco Secure Access (private apps) — over the same identity truth
flowchart TB
  HRIS["HRIS → IGA → ITSM gate
onboarding drives AD"] subgraph SOT["AD on-prem — source of truth"] ADG["Users + 17 SG-* groups
in an AD OU · tiered T0–T4"] end subgraph PROXY["The auth-proxy host — two sync engines, side by side"] ECN["Entra Connect
AD users+groups → Entra"] DDS["AD Duo Auth Proxy
Duo Directory Sync · [ADDS]"] end ENT["Entra tenant"] DUO["Duo directory
AD-synced groups (incl. 17 SG-*)"] subgraph PAC["Policy-as-code · SSOT"] INT["mcp-authz-intent.yaml"]-->RND["the policy renderer"] end subgraph PDP["Decision · Duo cloud Authorization API (true PDP)"] DAC["ext_authz connectors
agentgw + envoy · LIVE"] CSA["Cisco Secure Access
managed SSE · PLANNED"] end subgraph PEP["Enforcement · gateways (PEP) — one job each"] AGW["agentgateway · LIVE
MCP tools"] ENV["Envoy AI Gateway · LIVE
LLM providers"] SAG["Cisco Secure Access
private apps (ZTNA) · PLANNED"] end subgraph RES["Resources"] MCP["MCP servers
github · ms-learn · splunk"] LLM["LLM providers
Anthropic · OpenAI · Ollama"] APPS["Private apps
-lite consoles + fabric API"] end HRIS-->ADG ADG-->|Entra path|ECN-->ENT ADG-->|AD→Duo path · SG-* groups|DDS-->DUO ENT-.->|Entra→Duo sync|DUO DUO-->DAC ENT-.->CSA RND-->DAC RND-->CSA DAC-->AGW DAC-->ENV CSA-->SAG AGW-->MCP ENV-->LLM SAG-->APPS LEAVER["HRIS leaver → IGA → SSF/CAEP session revoke"]-.->|pulls token|AGW LEAVER-.->ENV LEAVER-.->SAG
The load-bearing idea

Groups are an identity-plane object, not a gateway object. 17 AD security groups in an AD OU — tiered T0–T4 — reach Duo via the AD Duo Directory Sync (the Auth-Proxy path) — a distinct sync from Entra Connect's AD → Entra — and serve every gateway. What is per-gateway is the policy binding, authored once in mcp-authz-intent.yaml and rendered to each PDP. The same 17 groups govern all three planes — MCP tools, LLM providers, and private apps; a new gateway or plane renders the same intent to its PDP, it never mints a new group set.

The plane, end to end

Source of truth → sync → decision (PDP) → enforcement (PEP) → resources. Policy-as-code drives the PDPs; the leaver signal pulls tokens back out.

Two directory-sync paths (validated via Duo Admin API)

HRIS onboarding drives AD on-prem. The auth-proxy host runs two sync engines side by side: Entra Connect pushes AD users + groups into the Entra tenant, and the AD Duo Auth Proxy (the [ADDS] Duo Directory Sync) pushes them into Duo. The 17 SG-* groups reach Duo on the AD path — not through Entra. Duo's directory holds the AD-synced groups (incl. all 17 SG-*), plus groups from a Microsoft Entra sync and a Google sync — three inbound directory syncs converging on one Duo, which the gateways' authorization then reads.

Per-tool-call decision

Two checks on every call: authenticate the Duo JWT, then authorize the tool against the sponsor's groups. Default-deny.

sequenceDiagram
  participant C as Agent / MCP client
  participant G as Gateway (PEP)
  participant D as Duo Authorization Connector (PDP)
  C->>G: tools/call (Bearer Duo JWT)
  G->>G: mcpAuthentication — validate iss/aud/JWKS
  G->>D: ext_authz Check (token + target_tool)
  D->>D: sponsor groups ∩ allowedTools(group, server)
  alt authorized
    D-->>G: ALLOW (allowedTools)
    G-->>C: tool result
  else not in any group's bundle
    D-->>G: DENY
    G-->>C: 403 (tool hidden / refused)
  end
  

The 17 groups (net-new, deployed to ADUC)

■ T0 reference■ T1 read ■ T2 write■ T3 privileged (.adm/JIT) ■ T4 sensitive (.adm/JIT+alert)
AD groupPlaneTierProvisioningScope
SG-MCP-MSLearnMCPT0birthrightms-learn ×3
SG-MCP-GitHub-ReadMCPT1birthrightgithub read ×26
SG-MCP-GitHub-WriteMCPT2requestablegithub write ×14
SG-MCP-GitHub-MergeMCPT3JIT · .admmerge_pull_request · SoD ≠ Write
SG-MCP-GitHub-AdminMCPT3JIT · .admcreate_repository, delete_file
SG-MCP-AppSecMCPT4JIT+alert · .admrun_secret_scanning
SG-MCP-Splunk-ReadMCPT1birthrightsplunk metadata ×6
SG-MCP-Splunk-QueryMCPT3JIT · .admrun_query, run_saved_search
SG-MCP-Splunk-IAMDataMCPT4JIT+alert · .admget_user_info, get_user_list
SG-MCP-Duo-ReadMCPT1birthrightduo read ×47 · detail
SG-MCP-Duo-LogSyncMCPT1birthrightlogsync metrics/rollups ×5
SG-MCP-Duo-WriteMCPT2requestableduo write ×19 · SoD ≠ Admin
SG-MCP-Duo-AuthMCPT2requestableauth challenge/verify/token ×4
SG-MCP-Duo-AdminMCPT3JIT · .admdestructive ×13 · SoD ≠ Write
SG-MCP-Duo-DNGMCPT3JIT · .admDNG relay config ×6
SG-MCP-Duo-IntelMCPT3JIT · .admposture/diagnostics ×7
SG-MCP-Duo-IAMDataMCPT4JIT+alert · .admlog PII mine + export ×6
SG-MCP-Duo-SecretsMCPT4JIT+alert · .admintegration secrets + bypass codes ×4
SG-LLM-LocalLLMT0birthrightOllama (no egress)
SG-LLM-ExternalLLMT2requestableAnthropic/OpenAI · DLP-gated
SG-LLM-FrontierLLMT3JITfrontier models · budget-bound
SG-AGW-Fabric-ReadAPIT1requestableGET · hris/iga/itsm/cmdb
SG-AGW-Fabric-OperatorAPIT3JIT · .admcontrol endpoints
SG-MCP-AgentGW-AdminadminT3JIT · .admagentgateway console/config
SG-MCP-EnvoyGW-AdminadminT3JIT · .admEnvoy admin (planned)
SG-MCP-SecureAccess-AdminadminT3JIT · .admSecure Access admin (planned)
Why this scales

Groups = f(roles × tiers) — independent of gateway count and tool count. A new tool is auto-tiered by the onboarding rubric into an existing group; a new gateway renders the same intent to its PDP. T3/T4 bind to an elevated .adm identity, so neither a human on their daily account nor an agent acting on-behalf-of them can reach destructive or data-exfil tools. Compliance maps clean: NIST 800-53 AC-2/3/5/6, 800-171/CMMC 3.1.x, ISO 27001 A.5/A.8, SOC 2 CC6, HIPAA §164.312.

← conceptual: Agentic AI Gateways & Access (page 5)

Lane: personal lab · synthetic data — reference architecture over synthetic identities only, no customer data.