feat: add costing-entra-appid sample with Azure Workbook dashboard#145
feat: add costing-entra-appid sample with Azure Workbook dashboard#145ncheruvu-MSFT wants to merge 46 commits intomainfrom
Conversation
- Add costing sample with cost allocation workbook, cost exports, and budget alerts - Add screenshots for cost reports and dashboard views - Remove manual fallback steps (managed identity handles export auth) - Update README with screenshot gallery - Update shared azure_resources and template notebook
- APIM cost attribution by Entra ID caller (app registration) - Custom metric emission via caller-id-policy.xml - Azure Workbook with foldable sections, name resolution, accessibility - Notebook: full end-to-end deploy, Entra test apps, traffic, verification - KQL queries for usage, cost allocation, and request trends
🐍 Python 3.14 Results
|
🐍 Python 3.12 Results
|
🐍 Python 3.13 Results
|
…atterns - Replace ARM template with Bicep using shared modules (diagnostics, api, appinsights, workspaces) - Externalize KQL queries to .kql files (verify-metric-ingestion, budget-alert-threshold) - Replace caller-id-policy.xml with emit_metric_caller_id.xml (emit-metric policy) - Add Azure Monitor Workbook (workbook.json) with cost attribution dashboards - Rewrite create.ipynb following _TEMPLATE pattern with NotebookHelper/deploy_sample() - Rewrite README.md matching costing sample section order and formatting - Remove old screenshots (will be re-added once sample is deployed)
- Fix emit_metric_caller_id.xml: add curly braces for APIM Razor parser - Fix main.bicep: reference infrastructure's existing App Insights/Log Analytics instead of deploying separate instances (emit-metric sends to service-level AI) - Fix create.ipynb: correct App Insights query endpoint and workbook portal link - Fix budget-alert-threshold.kql: use 'timestamp' instead of 'TimeGenerated' for customMetrics table
|
@ncheruvu-MSFT, please also address the three |
|
@ncheruvu-MSFT & @san360, I addressed the |
- README.md: Fix heading 'Two' -> 'Three Tracking Approaches' - main.bicep: Remove primaryKey from apiSubscriptionKeys output (security) - create.ipynb: Replace api_subscription_keys Bicep output lookups with get_apim_subscription_key() (RBAC-controlled ARM listSecrets) - verify-token-metric-ingestion.kql: Add tokenType filter, default to '*' (all)
|
Hi @ncheruvu-MSFT, I should be able to review Tuesday or Wednesday. Apologies for taking so long! |
| var payload = System.Text.Encoding.UTF8.GetString( | ||
| Convert.FromBase64String(parts[1].PadRight(parts[1].Length + (4 - parts[1].Length % 4) % 4, '='))); |
samples/costing/main.bicep
Outdated
| // KQL queries (Entra ID tab). Replace them with the actual App Insights name | ||
| // so the app() function resolves correctly at runtime. | ||
| var rawWorkbookJson = string(loadJsonContent('workbook.json')) | ||
| var workbookJsonWithAppInsights = replace(rawWorkbookJson, '__APP_INSIGHTS_NAME__', applicationInsightsName) |
| "import json\n", | ||
| "import requests\n", | ||
| "\n", | ||
| "from apimrequests import ApimRequests\n", | ||
| "from azure_resources import get_apim_subscription_key\n", | ||
| "\n", | ||
| "if not use_real_jwt:\n", | ||
| " print_info('Real JWT testing is disabled (use_real_jwt = False)')\n", | ||
| " print_info('To enable, set use_real_jwt = True and provide client credentials in the init cell')\n", | ||
| "elif not all([real_jwt_tenant_id, real_jwt_client_id, real_jwt_client_secret]):\n", | ||
| " print_error('Missing credentials: set real_jwt_tenant_id, real_jwt_client_id, and real_jwt_client_secret in the init cell')\n", | ||
| "elif 'apim_gateway_url' not in locals():\n", | ||
| " print_error('Please run the deployment cell first')\n", | ||
| " raise SystemExit(1)\n", | ||
| "else:\n", | ||
| " # Acquire a token using the client credentials flow\n", | ||
| " token_url = f'https://login.microsoftonline.com/{real_jwt_tenant_id}/oauth2/v2.0/token'\n", | ||
| " token_payload = {\n", | ||
| " 'grant_type': 'client_credentials',\n", | ||
| " 'client_id': real_jwt_client_id,\n", | ||
| " 'client_secret': real_jwt_client_secret,\n", | ||
| " 'scope': f'{real_jwt_client_id}/.default'\n", | ||
| " }\n", | ||
| "\n", | ||
| " print_info('Acquiring token from Microsoft Identity Platform...')\n", | ||
| " token_response = requests.post(token_url, data=token_payload, timeout=30)\n", | ||
| "\n", | ||
| " if token_response.status_code != 200:\n", | ||
| " print_error(f'Token acquisition failed ({token_response.status_code}): {token_response.text[:300]}')\n", | ||
| " else:\n", | ||
| " access_token = token_response.json().get('access_token', '')\n", | ||
| " payload_part = access_token.split('.')[1]\n", | ||
| " payload_part += '=' * (4 - len(payload_part) % 4) # pad base64\n", | ||
| " claims = json.loads(base64.urlsafe_b64decode(payload_part))\n", | ||
| " real_appid = claims.get('appid', claims.get('azp', 'unknown'))\n", |
simonkurtz-MSFT
left a comment
There was a problem hiding this comment.
Hi Naga,
Please take a look at my comments as well as Copilot's. Once that's done, please take a good, manual look over everything once more, please. I'll review any changes that you make Tuesday or Wednesday.
Thank you!
…output cleanup - Extract caller-id JWT parsing into reusable policy fragment (pf-extract-caller-id.xml) - Fix orphaned raise SystemExit, duplicate alert_email, duplicate print_ok in init cell - Fix undefined sample_requests_per_caller -> sample_requests_per_subscription - Remove duplicate print block in Real JWT cell - Clear all notebook cell outputs - Remove temp REVIEW-FIXES.md - Discard unrelated authX-pro whitespace change
|
Hi @ncheruvu-MSFT, please add a graceful fallback in the event that AI tokens were not captured:
|
When caller-tokens custom metrics have not been ingested yet, the
evaluate pivot() operator does not create prompt/completion/total
columns. Replace coalesce(prompt, 0.0) with column_ifexists('prompt', 0.0)
in all four affected queries so the AI Gateway Token/PTU tab renders
gracefully instead of showing KQL resolution errors.
…o feature/costing-entra-appid


Summary
Adds a new sample costing-entra-appid that demonstrates APIM cost attribution by Entra ID caller (app registration).
What's included
Azure Workbook features
Testing