Scenario: Foundry Agent → Azure Logic App → ServiceNow
Architecture Overview
User Request (natural language)
│
▼
┌────────────────────────────┐
│ Foundry ProvisionUser │ GPT-4o extracts UPN
│ Agent (AI Agent) │ from natural language
└──────────┬─────────────────┘
│ OpenAPI action (SAS-signed URL)
▼
┌────────────────────────────┐
│ Azure Logic App │ Receives JSON payload
│ prod-28.eastus.logic.azure│ with UPN + metadata
└──────────┬─────────────────┘
│ HTTP connector
▼
┌────────────────────────────┐
│ ServiceNow Incident API │ Creates incident
│ (incident table) │ for user provisioning
└────────────────────────────┘
Auth Model
This scenario does not use OAuth or managed identity for the Foundry → Logic App call. Instead:
- Foundry → Logic App: SAS-signed URL (Shared Access Signature). The Logic App HTTP trigger URL embeds a
sigquery parameter that authenticates the caller. No Entra identity is involved in this hop. - Logic App → ServiceNow: HTTP connector with Basic Auth or OAuth (configured inside Logic App).
The Foundry agent runs as a project managed identity (shared Entra SP id-svc-foundry, same as Agent701). The SAS token is a credential attached to a connection node, modeled as connection --USES--> credential.
Components
1. Foundry Agent
- Name: ProvisionUser Agent
- Model: GPT-4o
- Tools: OpenAPI action pointing to Logic App trigger URL
- Project: Same project as Agent701 (shared managed identity)
- Ownership: IT Platform Team (team only — triggers
ownership_ambiguous)
2. Azure Logic App
- Name: prod-28 (East US)
- Trigger: HTTP request (SAS-signed)
- Action: Create ServiceNow incident
- Resource type:
Microsoft.Logic/workflows(Azure PaaS)
3. ServiceNow Incident
- Table:
incident - Fields populated: short_description (from agent), caller_id (UPN extracted by GPT-4o)
SecurityV0 Entity Mapping
| Real Component | Entity Type | Node ID | Source System |
|---|---|---|---|
| ProvisionUser Agent | workload | wl-foundry-provisioner | microsoft_foundry |
| Project Managed Identity | identity | id-svc-foundry (reused) | entra_id |
| IT Platform Team | human_identity | owner-it-platform-team (reused) | entra_id |
| Agent Executor Role | role | foundry-role-provisioner-exec | microsoft_foundry |
| SN Incident Creator Role | role | sn-role-incident-creator | servicenow |
| Logic App Invoke Permission | permission | perm-logic-app-invoke | microsoft_foundry |
| SN Incident Write Permission | permission | perm-sn-incident-write | servicenow |
| Azure Logic App | resource | res-logic-app-provisioner | microsoft_foundry |
| SN Incident Table | resource | res-sn-incident-table | servicenow |
| Logic App Connection | connection | conn-logic-app-provisioner | microsoft_foundry |
| SAS Token | credential | cred-sas-logic-app | microsoft_foundry |
Expected Findings
| Finding | Severity | Why |
|---|---|---|
llm_egress | high | Agent uses GPT-4o (egress_category: "llm") |
ownership_ambiguous | medium | Only team owner (IT Platform Team), no individual |
reachable_sensitive_domain | high | Paths reach confidential resources (Logic App, SN incident table) |
Verification
After seeding with seed-demo-w1.ts:
# Check the workload exists
curl -s "http://localhost:3000/api/v1/authority-paths" \
-H "X-Tenant-Id: demo-w1" | \
jq '[.data[] | select(.workload.display_name == "Foundry ProvisionUser Agent")]'
# Check findings
curl -s "http://localhost:3000/api/v1/findings" \
-H "X-Tenant-Id: demo-w1" | \
jq '[.data[] | select(.entity_display_name == "Foundry ProvisionUser Agent") | .finding_type]'