Skip to main content

Azure Foundry Connector: Environment & API Reference

What exactly this connector queries, what permissions it needs, and what test data must exist for it to produce output.

Read architecture/11-platform-mental-model.md first for the conceptual model.


Credentials Required

# Azure Entra (app registration with client_credentials grant)
AZURE_TENANT_ID=<directory-tenant-id>
AZURE_CLIENT_ID=<app-registration-client-id>
AZURE_CLIENT_SECRET=<app-registration-secret>

# Optional: limit to specific subscriptions (auto-discovers all if empty)
AZURE_SUBSCRIPTION_IDS=<comma-separated-sub-ids>

Required Roles (three separate scopes)

1. ARM scope — subscription level

RoleWhere to assignPurpose
ReaderAzure Portal → Subscription → Access control (IAM)List AIServices accounts, projects, Function Apps, role assignments

2. Foundry data plane — AIServices account level

RoleWhere to assignPurpose
Azure AI UserAzure Portal → AIServices account → Access control (IAM)List agents, connections, threads

This is the most commonly missed permission. Without it, the connector discovers accounts and projects via ARM but gets 401 on every data-plane call (agents, connections, threads).

The role is assigned on the AIServices account resource, not per-project. All sub-projects inherit from the parent account.

Role GUID: 53ca6127-db4c-4b6e-9c83-d83438ad60d0

PermissionTypePurpose
Application.Read.AllApplicationRead SP details (credential types, status)
Directory.Read.AllApplicationRead SP owners
User.Read.AllApplicationDetect disabled owner accounts
AuditLog.Read.AllApplicationSign-in logs (needs P1/P2 licence)

Without Graph permissions: Connector still works. Evidence completeness shows unavailable_no_access for entra_sp_details and sign_in_logs. You won't see owner names or sign-in timestamps.


API Calls (exact endpoints)

ARM — Resource discovery

GET https://management.azure.com/subscriptions?api-version=2022-12-01

Auto-discover all subscriptions. Cached per session.

GET https://management.azure.com/subscriptions/{sub}/providers/Microsoft.MachineLearningServices/workspaces?api-version=2024-10-01

Legacy Hub/Project model. Filters kind ∈ ["Hub", "Project"].

GET https://management.azure.com/subscriptions/{sub}/providers/Microsoft.CognitiveServices/accounts?api-version=2023-05-01

Current AIServices model (2025+). Filters kind == "AIServices".

GET https://management.azure.com{account_resource_id}/projects?api-version=2025-04-01-preview

Enumerate projects under an AIServices account.

GET https://management.azure.com/subscriptions/{sub}/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&$filter=principalId eq '{id}'

RBAC role assignments for a managed identity.

Foundry data plane — Agent and connection discovery

Token scope depends on endpoint domain:

EndpointScope
*.services.ai.azure.comhttps://ai.azure.com/.default
*.api.azureml.mshttps://ml.azure.com/.default
*.cognitiveservices.azure.comhttps://cognitiveservices.azure.com/.default
# List agents (new API)
GET {project_endpoint}/assistants?api-version=v1

# List agents (legacy API)
GET {project_endpoint}/agents/v1.0/assistants?api-version=2024-12-01-preview

Paginates via OpenAI-compatible has_more + after={last_id}.

# List connections
GET {project_endpoint}/connections?api-version=v1
# List threads (execution evidence)
GET {project_endpoint}/threads?api-version=v1&limit=100

Client-side filters to last 30 days. Thread count = proxy for agent execution frequency.

Graph API — Identity enrichment

GET /v1.0/servicePrincipals/{object_id}
GET /v1.0/servicePrincipals/{object_id}/owners
GET /v1.0/auditLogs/signIns?$filter=servicePrincipalId eq '{id}'&$top=1&$orderby=createdDateTime desc

Scan Phases (execution order)

Phase 1 — Workspace discovery (ARM):

  1. Enumerate subscriptions
  2. List ML workspaces (legacy Hub/Project)
  3. List CognitiveServices accounts (AIServices)
  4. For each AIServices account: list projects

Phase 2 — Agent and connection discovery (data plane): 5. For each project: list agents (assistants) 6. For each project: list connections 7. For each project: count recent threads (execution evidence)

Phase 3 — ARM RBAC (per managed identity): 8. For each managed identity principal ID: query role assignments 9. Resolve role definition names (cached lookup)

Phase 4 — Entra enrichment (Graph, optional): 10. For each managed identity: fetch SP details 11. For each SP: fetch owners 12. For each SP: fetch last sign-in timestamp

Phase 5 — Transform and submit: 13. Build NormalizedGraph (nodes, edges, evidence completeness) 14. POST to platform ingestion endpoint


Test Data Requirements

Minimum viable (to see non-zero output)

  1. AIServices account in at least one subscription
  2. App registration with Reader on that subscription
  3. App registration with Azure AI User on that AIServices account
  4. At least one Foundry project under the account
  5. At least one AI agent created in that project

For richer output

  1. Agent with connections (Azure OpenAI, Azure AI Search, etc.)
  2. Agent with recent usage (threads created in last 30 days)
  3. Managed identity with ARM role assignments (Cognitive Services Contributor, etc.)
  4. Graph API permissions on the app registration (for owner/sign-in data)

What the current dev environment has

Our dev tenant (bcf375ed-..., subscription 2a25bc41-...) contains:

  • 3 AIServices accounts:
    • gpt-nano-for-summary → 1 project, 1 agent
    • s-appt-scheduler → 1 project, 2 agents
    • sv0-foundry-agent-project → 1 project, 2 agents
  • 5 agents total across 3 projects
  • 6 managed identities with ARM role assignments
  • 2 connections discovered
  • 4 execution evidence records (thread counts)

What was missing (and fixed 2026-03-10)

s-appt-scheduler and sv0-foundry-agent-project were returning 401 on agents and connections endpoints. Fix: Added Azure AI User role on both AIServices accounts for the connector app registration.

Before fix: 1 agent, 0 connections, 0 execution evidence After fix: 5 agents, 2 connections, 4 execution evidence


Evidence Completeness

Evidence SourceStatus when workingCommon failure
workspacesavailableWrong credentials or no AIServices accounts exist
agentsavailableMissing Azure AI User role on AIServices account → 401
connectionsavailable or partialMissing Azure AI User role → 401, or some projects denied
execution_evidenceavailable or partialNo threads in last 30 days, or endpoint doesn't support threads API
arm_rbacavailable or unavailable_no_accessMissing Reader role on subscription
entra_sp_detailsavailable or unavailable_no_accessMissing Application.Read.All Graph permission
sign_in_logsavailable or unavailable_not_enabledNo P1/P2 licence, or missing AuditLog.Read.All
data_plane_authorityavailableSynthetic (always available if agents found)

Troubleshooting

"No permission to list agents in project X (401)" — Missing Azure AI User role on the AIServices account. Go to Azure Portal → AIServices account → Access control (IAM) → Add role assignment → Azure AI User → assign to the connector app registration.

"Discovered 0 Foundry workspaces" — Either no AIServices accounts exist in the subscription, or the app registration lacks Reader role on the subscription.

"0 agents" but workspaces found — Agents exist in the Foundry portal but the connector can't list them. Check the Azure AI User role assignment.

"arm_rbac: unavailable_no_access" — The Reader role is present (can list resources) but role assignment queries return 403. This can happen if the role is inherited from a management group with restricted permissions.

"sign_in_logs: unavailable_not_enabled" — The Azure AD tenant doesn't have P1/P2 licence. Sign-in logs require a premium licence. Non-blocking.

Thread counts seem low — Threads API returns project-level threads, not agent-filtered. If multiple agents share a project, counts are approximate. Also, only threads from the last 30 days are counted.