AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Foundry Cross Resource

skill-aiappsgbb-awesome-gbb-foundry-cross-resource · by aiappsgbb

>

No reviews yet
0 installs
13 views
0.0% view→install

Install

$ agentstack add skill-aiappsgbb-awesome-gbb-foundry-cross-resource

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-aiappsgbb-awesome-gbb-foundry-cross-resource)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Foundry Cross Resource? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Cross-Resource Model Invocation via Foundry AI Gateway

> Status — verified live on 2026-04-23 with Foundry account > xtest-foundry-mr5kfi / project xtest-proj-mr5kfi (Sweden Central) calling > deployment gpt-4o-mini v2024-07-18 hosted on a different Azure OpenAI > account (acme-aoai-shared) through APIM acme-ai-apim. Both ApiKey > and ProjectManagedIdentity auth paths returned PONG on all three > invocation patterns. See "Verified working configuration" at the end. > > Default in worked examples below: gpt-5.4-mini (current > Foundry-routable chat-mini family, May 2026). The original verification > was on gpt-4o-mini; the gateway routes by deployment-name-in-path > regardless of model family, so the recipe is mechanically identical for > any deployment your APIM backend actually carries. The exact API > version string in the connection metadata below is illustrative — > use whatever your backend deployment is registered with (check > az cognitiveservices account deployment show).


1. What this skill solves

You have a Foundry project ("consumer") that needs to invoke models deployed on a different Azure OpenAI / AI Services account ("backend"), fronted by an Azure API Management instance acting as the AI Gateway. You want to address those models via the Foundry-native string connectionName/deploymentName so the application code is identical to a local-deployment call.

┌────────────────────────┐                ┌──────────────────────────┐                ┌─────────────────────────────┐
│  Consumer Foundry      │                │  APIM AI Gateway         │                │  Backend AI/OpenAI account  │
│  project               │  Foundry MI    │  acme-ai-apim        │   APIM MI →    │  acme-aoai-shared       │
│  xtest-proj-mr5kfi     ├───or────────► │   /xtest-aoai            ├──Bearer───────►│  gpt-5.4-mini deployment    │
│  (Sweden Central)      │  ApiKey        │   /xtest-aoai-pmi        │  (msi token)   │  (East US 2)                │
│                        │                │                          │                │                             │
│  ApiManagement         │                │  validate token /        │                │  Cognitive Services User RBAC│
│  connection            │                │  enforce subscription    │                │  granted to APIM MI         │
│  category=ApiManagement│                │  set-backend-service     │                │                             │
│  target=APIM API URL   │                │  authentication-managed- │                │                             │
│  authType=ApiKey | PMI │                │   identity → backend     │                │                             │
└────────────────────────┘                └──────────────────────────┘                └─────────────────────────────┘

The consumer project never holds the backend's API key or RBAC. APIM is the trust boundary.


2. The 100% reliable checklist

Before any agent call, ALL of these must be true. Cross them off in order; the official validator script test_apim_connection.py plus the field-tested probes in §8 below verify each step end-to-end.

| # | Item | How to verify | |---|------|---------------| | 1 | Backend AI Services / Azure OpenAI account exists with the model deployed | az cognitiveservices account deployment list -g -n | | 2 | APIM exists (any SKU; Developer is fine for testing, Standard v2/Premium for prod) and has system-assigned managed identity enabled | az apim show -g -n --query identity | | 3 | APIM MI has Cognitive Services User (or Cognitive Services OpenAI User) on the backend account | az role assignment list --assignee --scope | | 4 | APIM has an API whose path you'll target (e.g., /xtest-aoai) with inbound policy that calls set-backend-service + authentication-managed-identity + Bearer header injection (see §6) | Invoke-RestMethod -Uri https://.azure-api.net//deployments//chat/completions?api-version=2024-10-21 -Headers @{api-key='';...} returns 200 | | 5 | (ApiKey only) An APIM subscription scoped to that API (or to a product the API is in) exists; you have the primary key | az apim subscription show ... | | 6 | (PMI only) APIM API has subscriptionRequired: false AND inbound policy includes ` with containing the **consumer project MI's client/app ID** | API GET shows subscriptionRequired:false; policy GET shows the GUID | | 7 | Consumer Foundry project exists, has Azure AI User RBAC for the caller, and (PMI) has system-assigned managed identity enabled | az cognitiveservices account project show ... --query identity | | 8 | An ApiManagement connection exists on the consumer project (NOT AzureOpenAI, NOT AIServices) | See §5 for the verified PUT body | | 9 | The connection's metadata.models is a **JSON-stringified** array (NOT a real array) and metadata.deploymentInPath matches the backend style | See §5 — this is the most common silent error | | 10 | Caller code uses model="/" and calls responses.create(...) (NOT chat.completions.create`) | See §7 |

If step 4 doesn't return 200 outside Foundry, no Foundry call will work. Always smoke-test the gateway directly first.


3. Decision tree

                          ┌──────────────────────────────────────┐
                          │ What backend does APIM forward to?   │
                          └─────────────┬────────────────────────┘
                                        │
              ┌─────────────────────────┴────────────────────────┐
              │                                                  │
   AOAI / AI Services on /openai                       OpenAI v1 (/v1/...)  
   (most common — Azure OpenAI)                        or Anthropic etc.    
              │                                                  │
              ▼                                                  ▼
   metadata.deploymentInPath = "true"           metadata.deploymentInPath = "false"
   metadata.inferenceAPIVersion = "2024-10-21"  metadata.inferenceAPIVersion = ""  (or omit)
   models[].properties.model.format = "OpenAI"  models[].properties.model.format = "OpenAI"|"Anthropic"|"NonOpenAI"
                                                modelDiscovery.listModelsEndpoint = "/models"
                                                modelDiscovery.deploymentProvider = "AzureOpenAI"|"OpenAI"|"Anthropic"|"NonOpenAI"

                          ┌──────────────────────────────────────┐
                          │ How do callers prove identity to APIM?│
                          └─────────────┬────────────────────────┘
                                        │
              ┌─────────────────────────┼────────────────────────┐
              │                         │                        │
        APIM subscription key   Project Managed Identity    Both (dual-auth)
              │                  (no static secrets)               │
              ▼                         ▼                        ▼
   authType: "ApiKey"           authType: "ProjectManagedIdentity"  Two connections OR
   credentials.key:        credentials: {}                     APIM 
   APIM api: subscription req   audience:                           policy that branches
   APIM policy: pass-through      "https://cognitiveservices.azure.com"
                                APIM policy: validate-azure-ad-token
                                  with 
                                  containing project MI clientId
                                APIM api: subscriptionRequired=false

4. APIM-side configuration

4.1 Service URL on the API

The Foundry connection target is https://.azure-api.net/. Inside the API's inbound policy you set-backend-service to the backend account. Foundry then appends /deployments/{dep}/chat/completions?api-version=... (or /v1/responses etc.) to the gateway URL.

Operations on the API (i.e., the routes Foundry will call) must therefore match the AOAI / OpenAI surface. The simplest setup is catch-all with one operation per HTTP verb on the wildcard path /{*path}. For Azure OpenAI backends, all of the following must reach the inbound policy and 200:

POST /deployments/{deployment-id}/chat/completions?api-version=2024-10-21
POST /deployments/{deployment-id}/embeddings?api-version=2024-10-21
POST /v1/responses?api-version=preview          (Responses API)
GET  /models?api-version=2024-10-21             (model catalogue, used for dynamic discovery)

4.2 ApiKey-only inbound policy (verified working — xtest-aoai)


    
        
        
        
        
            @("Bearer " + (string)context.Variables["msi-access-token"])
        
    
    
    
    

Subscription enforcement is at the API/product level (set subscriptionRequired: true and configure subscriptionKeyParameterNames.header to api-key so the caller sends api-key: , not Ocp-Apim-Subscription-Key). Foundry sends the api-key header.

4.3 PMI-only inbound policy (verified working — xtest-aoai-pmi)


    
        
        "
            header-name="Authorization"
            failed-validation-httpcode="401"
            failed-validation-error-message="Unauthorized: token did not match expected audience or application">
            
                
            
            
                https://cognitiveservices.azure.com
                https://cognitiveservices.azure.com/
            
        
        
        
        
            @("Bearer " + (string)context.Variables["msi-access-token"])
        
    
    
    
    

PMI API also needs subscriptionRequired: false on the API resource (otherwise APIM rejects with 401 before the policy runs).

> **Why ` and not with xmsmirid?** > Both mechanisms work in principle, but the xmsmirid value Foundry's > project MI puts in its token is **not** the project ARM ID — it varies by > resource provider and current APIs. The MI's appid claim is universally > present and stable, so is the documented and > most reliable check. (Verified 2026-04-23: a policy requiring > xms_mirid = returned 401; switching to ` returned 200.)

4.4 Dual-auth inbound policy (ApiKey OR PMI)


    
        
        
            
                "
                    header-name="Authorization"
                    failed-validation-httpcode="401">
                    
                        
                    
                    
                        https://cognitiveservices.azure.com
                        https://cognitiveservices.azure.com/
                    
                
            
        
        .openai.azure.com/openai" />
        
        
            @("Bearer " + (string)context.Variables["msi-access-token"])
        
    

API must have subscriptionRequired: false (so PMI calls aren't rejected up front); the `` branch enforces token validation only when no subscription was used.


5. Connection schema (verified live)

ARM type: Microsoft.CognitiveServices/accounts/projects/connections@2025-04-01-preview. Reachable also via the Foundry data-plane endpoint https://.services.ai.azure.com/api/projects//connections/?api-version=v1.

> ⚠ The metadata.models and metadata.modelDiscovery fields are > JSON-encoded strings, not real JSON objects. This is because Azure > connection metadata is a flat string→string dictionary. Pass the JSON as a > string value or your PUT will be silently ignored / rejected.

5.1 ApiKey connection — verified working PUT body

{
  "properties": {
    "category": "ApiManagement",
    "target": "https://acme-ai-apim.azure-api.net/xtest-aoai",
    "authType": "ApiKey",
    "credentials": { "key": "" },
    "isSharedToAll": true,
    "metadata": {
      "deploymentInPath": "true",
      "inferenceAPIVersion": "2024-10-21",
      "models": "[{\"name\":\"gpt-5.4-mini\",\"properties\":{\"model\":{\"name\":\"gpt-5.4-mini\",\"format\":\"OpenAI\",\"version\":\"2026-04-30\",\"publisher\":\"Microsoft\"}}}]"
    }
  }
}

PUT URL:

https://management.azure.com/subscriptions//resourceGroups//providers/
Microsoft.CognitiveServices/accounts//projects//
connections/?api-version=2025-04-01-preview

Or via the data plane:

PUT https://.services.ai.azure.com/api/projects//connections/?api-version=v1

5.2 PMI connection — verified working PUT body

{
  "properties": {
    "category": "ApiManagement",
    "target": "https://acme-ai-apim.azure-api.net/xtest-aoai-pmi",
    "authType": "ProjectManagedIdentity",
    "credentials": {},
    "audience": "https://cognitiveservices.azure.com",
    "isSharedToAll": true,
    "metadata": {
      "deploymentInPath": "true",
      "inferenceAPIVersion": "2024-10-21",
      "models": "[{\"name\":\"gpt-5.4-mini\",\"properties\":{\"model\":{\"name\":\"gpt-5.4-mini\",\"format\":\"OpenAI\",\"version\":\"2026-04-30\",\"publisher\":\"Microsoft\"}}}]"
    }
  }
}

audience lives at properties.audience, NOT in metadata. The data-plane GET strips it from the response, but it is required on PUT and is what Foundry uses when requesting the MI token.

5.3 Metadata reference (full)

| Field | Type | Required | Default | Purpose | |-------|------|----------|---------|---------| | deploymentInPath | string "true"/"false" | Yes (in practice — without it: Upstream gateway returned NotFound) | none | "true" → AOAI shape /deployments/{dep}/chat/completions. "false" → OpenAI v1 shape with model in body. | | inferenceAPIVersion | string | Recommended for AOAI | none | Appended as ?api-version=.... Use 2024-10-21 (or newer GA) for AOAI; leave empty for /v1/responses style backends. | | deploymentAPIVersion | string | Optional | inferenceAPIVersion | Used for modelDiscovery list calls. | | models | string (JSON array, escaped) | Required if no modelDiscovery | none | Static catalogue. Must be JSON-stringified. | | modelDiscovery | string (JSON object, escaped) | Required if no models | none | Dynamic discovery. Must be JSON-stringified. Defaults: listModelsEndpoint=/deployments, getModelEndpoint=/deployments/{deploymentName}, deploymentProvider=AzureOpenAI. Override to /models and OpenAI for OpenAI-v1 style backends. | | customHeaders | string (JSON object) | Optional | none | Adds extra HTTP headers on every Foundry-to-APIM call. | | authConfig | string (JSON object) | Optional | none | For non-Authorization-header auth (e.g., gateway expects x-api-key: Bearer ). |

models[].properties.model.format accepts OpenAI, Anthropic, NonOpenAI. For Azure OpenAI deployments use OpenAI.

5.4 What does NOT work (verified failures)

| Connection variant | Result | |--------------------|--------| | Connection with no metadata at all | 400 Model gateway error: Upstream gateway returned NotFound | | Connection with metadata.modelDiscovery (stringified) but no models | 400 Model gateway error: Upstream gateway returned NotFound (against AOAI backends — AOAI's /deployments data-plane endpoint isn't a list) | | models passed as a real JSON array (not stringified) | Foundry stores it but inference returns Upstream gateway returned NotFound; this is a silent footgun | | authType: "AAD" (legacy alias) on Responses API | Inconsistent — sometimes accepted, sometimes rejected. Use ProjectManagedIdentity for Responses API / hosted agents. | | authType: "ProjectManagedIdentity" on Assistants v1 API | Rejected"AuthType ProjectManagedIdentity for connection is not supported". The standard-agent Assistants API (/assistants, /threads//runs) only accepts authType: "AAD". | | authType: "AAD" on **private VNet standard ag

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.