{
  "schema": "aaes/capability-pack/1",
  "provider": "azure",
  "version": "1.1.0",
  "description": "Azure Resource Manager pack: read subscriptions, resource groups, resources and subscription cost data, and administer one Azure OpenAI or Foundry account (model deployments, content filters, access-key rotation). Cost Management uses POST with a query body but changes no provider state.",
  "notes": "Every endpoint here is on the shared Azure management host management.azure.com, which stays real — it is the documented authority for ARM, not a tenant placeholder. SUBSCRIPTION_ID is a path placeholder the deployment binds to a concrete subscription before enabling; the paths are otherwise the documented ARM shapes with pinned api-version query values, and the review binds those versions — Microsoft documents api-version as required on every one of these operations.\n\nThe credential targets login.microsoftonline.com for token minting, which is also a real shared host, but token minting is the external process's call, not a capability: the executor injects the minted value and never calls the token endpoint itself, so no capability allowlists it.\n\nApproval classification: all four capabilities sit at R0, the read floor. The Cost Management query is a POST by HTTP shape but a read by effect — the request body is a query definition (type, timeframe, dataset with aggregation, grouping and filter) and the response is rows of cost data; nothing is created or changed at the provider. It is registered as read with the POST shape stated plainly in the description, the same honesty the GCP pack applies to getIamPolicy.\n\nCost data is financial at the read floor — a lower bound: an R0 financial read can still be a serious confidentiality risk. The read moves no money, so no cost ceiling is declared on the AAES action; per-request API behaviour at the provider is the deployment's review.\n\nDocumented exclusions for the Resource Manager reads: this pack does not register resource group or resource create/update/delete, deployments (Microsoft.Resources/deployments), role assignments or any Microsoft.Authorization write, Microsoft.Billing operations, Cost Management exports (which write query results to storage), or tenant- and management-group-scope variants of the registered lists — subscription scope only, except azure.subscriptions.list, which is the tenant-level subscriptions collection (GET /subscriptions) by design. Every list read here describes the collection read only — single-resource reads and resource-group-scoped resource listing are not registered by this pack.\n\nAzure OpenAI and Foundry administration (added in 1.1.0): seven capabilities on the same ARM host manage one Microsoft.CognitiveServices account through the Azure AI Services account-management API, api-version 2024-10-01: deployments (list, create or update, delete), content filters, which ARM calls raiPolicies (list, create or update, delete), and access-key rotation (regenerateKey). SUBSCRIPTION_ID, RESOURCE_GROUP, ACCOUNT_NAME, DEPLOYMENT_NAME and RAI_POLICY_NAME are path placeholders to bind before enabling. The two list reads use this pack's read-only token. The writes name a separate reference, secret-ref-azure-cognitiveservices-admin-token, minted by the same client-credentials process for a second app registration that holds write rights on that one account only; the Reader registration above never gets them.\n\nTiers sit at the floor of the declared actions. Creating or updating a deployment declares pay because provisioned SKUs bill hourly per deployed PTU until the deployment is deleted. Key rotation declares delete and share: the old key is destroyed and the response carries both current keys. Changing a content filter is R2 by the action floor, and policy should raise it for production. Every other operation in the account-management API is excluded: the rest of the Accounts group (including listKeys, create, update and delete), Deleted Accounts, Commitment Plans and Tiers, Defender for AI Settings, Encryption Scopes, Models, Model Capacities and their calculation, Network Security Perimeter Configurations, Private Endpoint Connections and Private Link Resources, Rai Blocklists and their items, Rai Content Filters, Resource Skus, Usages, and the availability checks. Single-deployment and single-filter reads are not registered. Azure Reservations purchases and the Foundry data-plane and inference endpoints are outside this API and are not registered.",
  "credential": {
    "secret_ref_id": "secret-ref-azure-client-credentials-token",
    "custody": "customer_vault",
    "inject": "header",
    "inject_name": "Authorization",
    "note": "A Microsoft Entra access token for a dedicated least-privilege app registration, held in the client's own secret manager. The stored material must be the complete Authorization header value: the scheme 'Bearer', one separating space, then the token — 'Bearer <token>'. customer_vault is the only generally-supported production custody model here — identity_federation and customer_broker are refused at startup and inline is lab-only. The reviewed token process is the OAuth 2.0 client credentials grant against the v2.0 endpoint: an external deployment process holds the app registration's client id and client secret, POSTs grant_type=client_credentials with scope=https://management.azure.com/.default to https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token, receives an access token (Microsoft documents expires_in, approximately one hour), and writes the complete header value under this reference; there are no refresh tokens in this flow, so renewal is the external process repeating the grant — the executor injects the stored value verbatim and performs no token lifecycle itself.\n\nRevocation is removing the client secret from the app registration or disabling the app: that stops future token issuance (a repeated grant fails closed), but the client credentials flow has no refresh tokens and no documented per-token revocation — an already-minted token remains valid until its expiry (approximately one hour), so treat the token lifetime as the exposure window. A certificate client assertion is the documented stronger alternative to a shared secret and is the deployment's review.\n\nLeast privilege: RBAC Reader on the subscription covers the three ARM inventory reads; for the Cost Management query, Microsoft's cost-scope documentation shows subscription Reader already grants read-only access to Cost Analysis, Forecast and the Query API, so plain Reader can suffice — the purpose-built Cost Management Reader role is the tighter alternative, and Enterprise Agreement subscriptions additionally require the 'AO view charges' billing setting to be enabled.\n\nGrant nothing broader.\n\nExecutor hygiene: the value must live only in executor memory for the lifetime of a call, must never be written to logs, traces or diagnostics, and must not appear in crash dumps; a deployment that cannot meet that bar must not enable the pack."
  },
  "capabilities": [
    {
      "capability_id": "azure.subscriptions.list",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "management.azure.com"
      ],
      "endpoint": "https://management.azure.com/subscriptions?api-version=2022-12-01",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-azure-client-credentials-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "azure-subscriptions-collection",
      "description": "List all subscriptions the credential's tenant exposes to it: display names, subscription ids, states and managing tenants — the account-structure inventory.\n\nThe registered path covers the collection read only — single-subscription reads (GET /subscriptions/{subscriptionId}) are not registered by this pack.",
      "requires_review": true
    },
    {
      "capability_id": "azure.resourcegroups.list",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "management.azure.com"
      ],
      "endpoint": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/resourcegroups?api-version=2021-04-01",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-azure-client-credentials-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "azure-subscription",
      "description": "List all resource groups in one subscription: names, locations, provisioning states and tags — the organisational layout of the estate. SUBSCRIPTION_ID is a placeholder the deployment binds to a concrete subscription before enabling.\n\nThe registered path covers the collection read only — single-resource-group reads are not registered by this pack.",
      "requires_review": true
    },
    {
      "capability_id": "azure.resources.list",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "management.azure.com"
      ],
      "endpoint": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/resources?api-version=2021-04-01",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-azure-client-credentials-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "azure-subscription",
      "description": "List all resources in one subscription: resource ids, names, types, locations, SKUs and tags — the full deployed-estate inventory an audit path starts from. The documented $filter and $expand query options narrow or enrich the same read. SUBSCRIPTION_ID is a placeholder the deployment binds to a concrete subscription before enabling.\n\nThe registered path covers the collection read only — single-resource reads are not registered by this pack.",
      "requires_review": true
    },
    {
      "capability_id": "azure.costmanagement.query",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "financial",
      "egress_allowlist": [
        "management.azure.com"
      ],
      "endpoint": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/providers/Microsoft.CostManagement/query?api-version=2025-03-01",
      "method": "POST",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-azure-client-credentials-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "azure-costmanagement-scope",
      "description": "Query usage and cost data at subscription scope. This POST retrieves data: the request body is a query definition (type such as Usage or ActualCost, timeframe, and a dataset carrying aggregation, granularity, grouping and filter) and the response is columns and rows of cost data — nothing is created or changed at the provider, so the declared action is read at the minimum R0 tier.\n\nThis is subscription financial data at the read floor — a lower bound: an R0 financial read can still be a serious confidentiality risk. The read moves no money, so no cost ceiling is declared on the AAES action. The documented scope path segment supports billing-account, resource-group and management-group scopes too; this registration binds subscription scope only. SUBSCRIPTION_ID is a placeholder the deployment binds to a concrete subscription before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "azure.cognitiveservices.deployments.list",
      "version": "1.1.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "management.azure.com"
      ],
      "endpoint": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/ACCOUNT_NAME/deployments?api-version=2024-10-01",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-azure-client-credentials-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "azure-cognitiveservices-deployments",
      "description": "List the model deployments of one Azure OpenAI or Foundry account (Deployments - List): model name, format and version, SKU and capacity, rate limits, the content filter (raiPolicyName) each deployment uses and its provisioning state.",
      "requires_review": true
    },
    {
      "capability_id": "azure.cognitiveservices.deployment.put",
      "version": "1.1.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "financial",
      "egress_allowlist": [
        "management.azure.com"
      ],
      "endpoint": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/ACCOUNT_NAME/deployments/DEPLOYMENT_NAME?api-version=2024-10-01",
      "method": "PUT",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-azure-cognitiveservices-admin-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "create",
        "update",
        "pay"
      ],
      "resource_id": "azure-cognitiveservices-deployments",
      "description": "Create or update one model deployment (Deployments - Create Or Update): model, SKU and capacity, rate limits and the content filter it uses. Provisioned SKUs are billed hourly for the deployed PTUs whether or not the deployment serves requests, and billing stops only when the deployment is deleted, so the capability declares pay at R3. The SKU and capacity come from the request body. DEPLOYMENT_NAME is a placeholder.",
      "requires_review": true
    },
    {
      "capability_id": "azure.cognitiveservices.deployment.delete",
      "version": "1.1.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "management.azure.com"
      ],
      "endpoint": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/ACCOUNT_NAME/deployments/DEPLOYMENT_NAME?api-version=2024-10-01",
      "method": "DELETE",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-azure-cognitiveservices-admin-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "delete"
      ],
      "resource_id": "azure-cognitiveservices-deployments",
      "description": "Delete one model deployment (Deployments - Delete). Traffic to the deployment name fails afterwards, and provisioned capacity released this way may not be available again. DEPLOYMENT_NAME is a placeholder.",
      "requires_review": true
    },
    {
      "capability_id": "azure.cognitiveservices.raipolicies.list",
      "version": "1.1.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "management.azure.com"
      ],
      "endpoint": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/ACCOUNT_NAME/raiPolicies?api-version=2024-10-01",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-azure-client-credentials-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "azure-cognitiveservices-account",
      "description": "List the account's content filters (Rai Policies - List): base policy, mode, and each filter's category, source (prompt or completion), severity threshold and blocking flag, plus custom blocklists.",
      "requires_review": true
    },
    {
      "capability_id": "azure.cognitiveservices.raipolicy.put",
      "version": "1.1.0",
      "kind": "tool",
      "risk_tier": "R2",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "management.azure.com"
      ],
      "endpoint": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/ACCOUNT_NAME/raiPolicies/RAI_POLICY_NAME?api-version=2024-10-01",
      "method": "PUT",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-azure-cognitiveservices-admin-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "create",
        "update"
      ],
      "resource_id": "azure-cognitiveservices-account",
      "description": "Create or update one content filter (Rai Policies - Create Or Update). A change can lower thresholds or switch blocking off for every deployment that uses the filter, so policy should raise this tier for filters on production deployments. RAI_POLICY_NAME is a placeholder.",
      "requires_review": true
    },
    {
      "capability_id": "azure.cognitiveservices.raipolicy.delete",
      "version": "1.1.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "management.azure.com"
      ],
      "endpoint": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/ACCOUNT_NAME/raiPolicies/RAI_POLICY_NAME?api-version=2024-10-01",
      "method": "DELETE",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-azure-cognitiveservices-admin-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "delete"
      ],
      "resource_id": "azure-cognitiveservices-account",
      "description": "Delete one content filter (Rai Policies - Delete). RAI_POLICY_NAME is a placeholder.",
      "requires_review": true
    },
    {
      "capability_id": "azure.cognitiveservices.key.regenerate",
      "version": "1.1.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "management.azure.com"
      ],
      "endpoint": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/ACCOUNT_NAME/regenerateKey?api-version=2024-10-01",
      "method": "POST",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-azure-cognitiveservices-admin-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "update",
        "delete",
        "share"
      ],
      "resource_id": "azure-cognitiveservices-account",
      "description": "Rotate one of the account's two access keys (Accounts - Regenerate Key, body keyName Key1 or Key2). The old value of that key stops working, which cannot be undone, and the response returns the current values of both key1 and key2 to the caller. The capability declares delete for the destroyed key and share for the returned key material, at R3. Route the response straight to the secret manager; never let an agent keep it.",
      "requires_review": true
    }
  ],
  "resources": [
    {
      "resource_id": "azure-subscriptions-collection",
      "kind": "api",
      "locator": "https://management.azure.com/subscriptions",
      "data_class": "internal",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    },
    {
      "resource_id": "azure-subscription",
      "kind": "api",
      "locator": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID",
      "data_class": "internal",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    },
    {
      "resource_id": "azure-costmanagement-scope",
      "kind": "api",
      "locator": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/providers/Microsoft.CostManagement",
      "data_class": "financial",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    },
    {
      "resource_id": "azure-cognitiveservices-account",
      "kind": "api",
      "locator": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/ACCOUNT_NAME",
      "data_class": "internal",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    },
    {
      "resource_id": "azure-cognitiveservices-deployments",
      "kind": "api",
      "locator": "https://management.azure.com/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.CognitiveServices/accounts/ACCOUNT_NAME/deployments",
      "data_class": "financial",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    }
  ],
  "review": {
    "state": "library",
    "date": "2026-10-22",
    "sources": [
      "https://learn.microsoft.com/en-us/rest/api/resources/subscriptions/list?view=rest-resources-2022-12-01 (retrieved 2026-09-21)",
      "https://learn.microsoft.com/en-us/rest/api/resources/resource-groups/list?view=rest-resources-2021-04-01 (retrieved 2026-09-21)",
      "https://learn.microsoft.com/en-us/rest/api/resources/resources/list?view=rest-resources-2021-04-01 (retrieved 2026-09-21)",
      "https://learn.microsoft.com/en-us/rest/api/cost-management/query/usage?view=rest-cost-management-2025-03-01 (retrieved 2026-09-21)",
      "https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow (retrieved 2026-09-21)",
      "https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/understand-work-scopes (retrieved 2026-09-21)",
      "https://learn.microsoft.com/en-us/rest/api/aiservices/accountmanagement/deployments/list?view=rest-aiservices-accountmanagement-2024-10-01 (retrieved 2026-10-22)",
      "https://learn.microsoft.com/en-us/rest/api/aiservices/accountmanagement/deployments/create-or-update?view=rest-aiservices-accountmanagement-2024-10-01 (retrieved 2026-10-22)",
      "https://learn.microsoft.com/en-us/rest/api/aiservices/accountmanagement/deployments/delete?view=rest-aiservices-accountmanagement-2024-10-01 (retrieved 2026-10-22)",
      "https://learn.microsoft.com/en-us/rest/api/aiservices/accountmanagement/rai-policies/list?view=rest-aiservices-accountmanagement-2024-10-01 (retrieved 2026-10-22)",
      "https://learn.microsoft.com/en-us/rest/api/aiservices/accountmanagement/rai-policies/create-or-update?view=rest-aiservices-accountmanagement-2024-10-01 (retrieved 2026-10-22)",
      "https://learn.microsoft.com/en-us/rest/api/aiservices/accountmanagement/rai-policies/delete?view=rest-aiservices-accountmanagement-2024-10-01 (retrieved 2026-10-22)",
      "https://learn.microsoft.com/en-us/rest/api/aiservices/accountmanagement/accounts/regenerate-key?view=rest-aiservices-accountmanagement-2024-10-01 (retrieved 2026-10-22)",
      "https://learn.microsoft.com/en-us/azure/foundry/openai/concepts/provisioned-throughput-billing (retrieved 2026-10-22)",
      "https://learn.microsoft.com/en-us/rest/api/aiservices/accountmanagement/operation-groups?view=rest-aiservices-accountmanagement-2024-10-01 (retrieved 2026-10-22)"
    ],
    "reviewer_id": "owner-delegated"
  }
}
