A working prototype for governing agent-to-agent traffic with Microsoft Entra Agent Identity, SPIFFE/SPIRE workload identity, and sidecar-enforced policy. The sample runs on Azure Container Apps and includes optional GCP and GitHub Actions federation paths with no shared secrets.
This repository is the public baseline for Identity Research for Agent Management Using SPIFFE. The README is the landing page; the full architecture, setup guide, and API reference are published through GitHub Pages:
Docs and API reference: https://microsoft.github.io/identity-spiffe/
- A sidecar that enforces mTLS, route-level RBAC, JWT validation, Conditional Access-style risk signals, and live admin governance before traffic reaches the app.
- Entra Agent Identity provisioning for Azure-native agents and federated external callers.
- SPIFFE/SPIRE SVIDs for workload-to-workload mTLS, including optional cross-cloud bundle federation.
- A portal and admin control plane for policy, health, audit, token, and mTLS allow-list management.
- Deployable examples for Azure agents, a GCP-hosted agent, and a GitHub Actions federated caller.
Every governed call passes through independent checks. Any failed layer denies the request.
The live Enforcement Layers view in the portal — every governed request walks all four layers before the backend ever sees it.
| Layer | Enforcement point | Denies when |
|---|---|---|
| 1 | SPIFFE/SPIRE mTLS in spiffe-proxy |
Caller SPIFFE ID is not allowed by the target |
| 2 | Sidecar RBAC policy | Method/path is not permitted for that caller |
| 3 | Entra OAuth2/JWT validation | Token is missing, expired, wrong audience, or lacks role |
| 4a | Conditional Access-style risk evaluation | Caller risk or governance state is unacceptable |
| 4b | Admin tag governance | Required live Graph-backed tags are absent |
flowchart LR
subgraph Browser
U[Admin / Viewer]
end
subgraph ACA["Azure Container Apps Environment"]
Portal[isp-portal]
SP[securityportal-mock]
ACP[admin-control-plane]
subgraph BB["budget-backend pod"]
BBAPP[app]
BBSC[spiffe-proxy sidecar]
BBAG[SPIRE agent]
end
subgraph CALLER["caller pod, e.g. budget-report"]
CAPP[app]
CSC[spiffe-proxy egress]
CAG[SPIRE agent]
end
end
subgraph VM["Azure VM"]
SPIRE[(SPIRE Server)]
end
subgraph GCP["GCP, optional --google"]
GCE[GCE VM: google-budget-reader]
end
subgraph GH["GitHub, optional --github"]
RUNNER[Self-hosted Runner VM]
GHA[GitHub Actions OIDC]
end
U --> Portal
Portal --> ACP
ACP -->|X-Spiffe-Admin-Key| BBSC
CAPP --> CSC
CSC -.->|mTLS + JWT| BBSC
BBSC --> BBAPP
BBAG -.->|SVID| SPIRE
CAG -.->|SVID| SPIRE
GCE -.->|SPIFFE federation via VPN| SPIRE
GCE -->|mTLS + JWT| BBSC
GHA -->|OIDC| RUNNER
RUNNER -->|mTLS + JWT| BBSC
SP --> Portal
sequenceDiagram
autonumber
participant Caller as Caller Agent
participant Egress as Egress Sidecar
participant Ingress as Ingress Sidecar
participant App as Target App
participant Graph as Entra / Graph
Caller->>Egress: HTTP request
Egress->>Egress: Fetch SVID from SPIRE
Egress->>Ingress: mTLS handshake with SPIFFE cert
Note over Ingress: Layer 1: verify caller SPIFFE ID
Egress->>Ingress: Forward request + Entra JWT
Note over Ingress: Layer 2: RBAC method/path check
Note over Ingress: Layer 3: JWT signature, audience, roles
Ingress->>Graph: Resolve caller governance attributes
Note over Ingress: Layer 4a: CA/risk evaluation
Note over Ingress: Layer 4b: required tag match
Ingress->>App: Forward authorized request
App->>Ingress: Response
Ingress->>Egress: Response
Egress->>Caller: Response
flowchart LR
subgraph GCP["GCP trust_domain: gcp.aim.microsoft.com"]
GA[GCP agent app]
GSC[spiffe-proxy egress]
GSP[GCP SPIRE agent]
GSRV[(GCP SPIRE server)]
end
subgraph AZ["Azure trust_domain: aim.microsoft.com"]
ASRV[(Azure SPIRE server)]
ABB[budget-backend]
AENTRA[Entra Agent Identity + FIC]
end
GSRV <-.->|SPIFFE bundle federation| ASRV
GA -->|1. Get SPIFFE SVID| GSP
GSP -->|2. Exchange external OIDC via FIC| AENTRA
GSC -->|3. mTLS + JWT| ABB
Read the GitHub Pages quickstart for prerequisites and the full deployment path.
The common commands are:
az login
azd auth login
azd env new isp-example
# Azure-only environment (seed the portal admin with the identity you'll sign in as)
./deploy.sh --new --with-admin=you@your-tenant.com
# Existing environment, code changes only
./deploy.sh --skip-provision
# Optional federated callers
./deploy.sh --new --google
./deploy.sh --new --githubPortal sign-in tip.
deploy.shonly adds the signed-inaz loginuser to theAgent Management Administratorsgroup by default. If you'll sign into the portal with a different identity, pass--with-admin=<upn>(repeatable) or setISP_INITIAL_ADMINS=alice@contoso.com,bob@contoso.com. Use./scripts/portal-members.sh add-admin <upn>to add more admins (oradd-viewer,remove-admin,list) after deploy.
Important deployment rules:
- Do not use
azd deploy <service>for agent services. Use./deploy.sh --skip-provisionor./scripts/reattest.sh. - Do not use
az containerapp update --set-env-varson multi-container apps. Export full YAML, edit it, then reimport. - Do not use
az vm run-command invoke. Use the helper path that callsaz vm run-command create --timeout-in-seconds.
The portal (isp-portal) is the operator surface for everything the sidecars
enforce — a live read of policy, identity, transport, and audit, plus the
controls to change them. Sign-in is gated by Entra; group membership in
Agent Management Administrators unlocks the policy editor and network
controls, Agent Management Viewers gets read-only access.
The overview dashboard at a glance — live health, one-click security scan, and the agent connection flow color-coded by enforcement decision.
Behind those screens are dedicated Network Access, Policy Editor, System Health, Test Calls, and Logs pages. See the architecture overview for how each page maps to a sidecar or control-plane API.
| Path | Purpose |
|---|---|
src/spiffe-proxy/ |
Go sidecar implementing mTLS, RBAC, JWT validation, audit streaming, and /mgmt/* |
src/shared/ |
Shared Python credential providers, token exchange, CA evaluation, and JWT validation |
src/budget-*, src/employee-menus/, src/demo-agent/ |
Sample agents and target services |
src/admin-control-plane/ |
Management front door for protected sidecar APIs |
portal/ |
Entra-signed-in management portal and API backend |
securityportal-mock/ |
Mock SOC/risk signal source used by the demo |
infra/ |
Bicep modules for Azure infrastructure |
scripts/ |
Deployment, Entra bootstrap, federation setup, re-attestation, and validation scripts |
docs/ |
GitHub Pages documentation and API reference |
- Quickstart
- System overview
- Management APIs
- Authentication flows
- Google federation how-to
- GitHub Actions federation how-to
Local docs preview:
python3 -m pip install -r requirements-docs.txt
mkdocs serveRun the enforcement matrix after deployment:
python3 scripts/test_agents.pyUseful operational checks:
./scripts/current-deployment.sh
./scripts/reattest.sh
mkdocs build --strictThis is a prototype. It is designed to show the pattern and make the implementation copyable, not to be run unchanged as a production platform.