From 6a01421d33ec9f0402eee4e7405ad1310373a76e Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 07:47:47 -0700 Subject: [PATCH 01/10] feat(sre-agent): add deployable Azure template --- .../.openpublishing.redirection.finops.json | 5 + docs-mslearn/TOC.yml | 24 +- docs-mslearn/toolkit/changelog.md | 56 +- docs-mslearn/toolkit/hubs/configure-sre.md | 249 ++++ docs-mslearn/toolkit/sre-agent/agents.md | 363 ++++++ docs-mslearn/toolkit/sre-agent/deploy.md | 219 ++++ docs-mslearn/toolkit/sre-agent/get-started.md | 135 ++ docs-mslearn/toolkit/sre-agent/knowledge.md | 172 +++ docs-mslearn/toolkit/sre-agent/kusto-tools.md | 497 ++++++++ docs-mslearn/toolkit/sre-agent/overview.md | 151 +++ .../toolkit/sre-agent/python-tools.md | 514 ++++++++ .../toolkit/sre-agent/scheduled-tasks.md | 277 ++++ docs-mslearn/toolkit/sre-agent/security.md | 200 +++ docs-mslearn/toolkit/sre-agent/template.md | 209 +++ docs-mslearn/toolkit/sre-agent/tools.md | 186 +++ .../toolkit/sre-agent/troubleshooting.md | 252 ++++ docs/deploy/sre-agent/14.0/azuredeploy.json | 1119 +++++++++++++++++ .../sre-agent/14.0/createUiDefinition.json | 169 +++ .../sre-agent/14.0/sre-agent-recipe.zip | Bin 0 -> 346636 bytes docs/deploy/sre-agent/latest/azuredeploy.json | 1119 +++++++++++++++++ .../sre-agent/latest/createUiDefinition.json | 169 +++ .../sre-agent/latest/sre-agent-recipe.zip | Bin 0 -> 346636 bytes src/scripts/Build-SreAgentTemplate.ps1 | 47 + src/scripts/Build-Toolkit.ps1 | 6 +- src/templates/sre-agent/.build.config | 9 + src/templates/sre-agent/bin/apply-extras.sh | 581 +++++++++ .../sre-agent/bin/check-prerequisites.sh | 67 + src/templates/sre-agent/bin/deploy.sh | 558 ++++++++ src/templates/sre-agent/bin/post-provision.sh | 9 + src/templates/sre-agent/bin/telemetry.sh | 53 + .../sre-agent/createUiDefinition.json | 169 +++ .../examples/ci-cd/github-actions-deploy.yml | 32 + src/templates/sre-agent/infra/main.bicep | 132 ++ .../infra/modules/apply-extras.bicep | 103 ++ .../kusto-all-databases-viewer-rbac.bicep | 26 + .../sre-agent/infra/modules/monitoring.bicep | 39 + .../infra/modules/resource-group-rbac.bicep | 33 + .../sre-agent/infra/modules/sre-agent.bicep | 103 ++ src/templates/sre-agent/infra/resources.bicep | 78 ++ .../infra/scripts/Apply-SreAgentExtras.ps1 | 306 +++++ src/templates/sre-agent/main.bicep | 164 +++ src/templates/sre-agent/package-manifest.json | 21 + 42 files changed, 8584 insertions(+), 37 deletions(-) create mode 100644 docs-mslearn/toolkit/hubs/configure-sre.md create mode 100644 docs-mslearn/toolkit/sre-agent/agents.md create mode 100644 docs-mslearn/toolkit/sre-agent/deploy.md create mode 100644 docs-mslearn/toolkit/sre-agent/get-started.md create mode 100644 docs-mslearn/toolkit/sre-agent/knowledge.md create mode 100644 docs-mslearn/toolkit/sre-agent/kusto-tools.md create mode 100644 docs-mslearn/toolkit/sre-agent/overview.md create mode 100644 docs-mslearn/toolkit/sre-agent/python-tools.md create mode 100644 docs-mslearn/toolkit/sre-agent/scheduled-tasks.md create mode 100644 docs-mslearn/toolkit/sre-agent/security.md create mode 100644 docs-mslearn/toolkit/sre-agent/template.md create mode 100644 docs-mslearn/toolkit/sre-agent/tools.md create mode 100644 docs-mslearn/toolkit/sre-agent/troubleshooting.md create mode 100644 docs/deploy/sre-agent/14.0/azuredeploy.json create mode 100644 docs/deploy/sre-agent/14.0/createUiDefinition.json create mode 100644 docs/deploy/sre-agent/14.0/sre-agent-recipe.zip create mode 100644 docs/deploy/sre-agent/latest/azuredeploy.json create mode 100644 docs/deploy/sre-agent/latest/createUiDefinition.json create mode 100644 docs/deploy/sre-agent/latest/sre-agent-recipe.zip create mode 100644 src/scripts/Build-SreAgentTemplate.ps1 create mode 100644 src/templates/sre-agent/.build.config create mode 100755 src/templates/sre-agent/bin/apply-extras.sh create mode 100755 src/templates/sre-agent/bin/check-prerequisites.sh create mode 100755 src/templates/sre-agent/bin/deploy.sh create mode 100755 src/templates/sre-agent/bin/post-provision.sh create mode 100755 src/templates/sre-agent/bin/telemetry.sh create mode 100644 src/templates/sre-agent/createUiDefinition.json create mode 100644 src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml create mode 100644 src/templates/sre-agent/infra/main.bicep create mode 100644 src/templates/sre-agent/infra/modules/apply-extras.bicep create mode 100644 src/templates/sre-agent/infra/modules/kusto-all-databases-viewer-rbac.bicep create mode 100644 src/templates/sre-agent/infra/modules/monitoring.bicep create mode 100644 src/templates/sre-agent/infra/modules/resource-group-rbac.bicep create mode 100644 src/templates/sre-agent/infra/modules/sre-agent.bicep create mode 100644 src/templates/sre-agent/infra/resources.bicep create mode 100644 src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 create mode 100644 src/templates/sre-agent/main.bicep create mode 100644 src/templates/sre-agent/package-manifest.json diff --git a/docs-mslearn/.openpublishing.redirection.finops.json b/docs-mslearn/.openpublishing.redirection.finops.json index ab20d5dbd..b2caf8eba 100644 --- a/docs-mslearn/.openpublishing.redirection.finops.json +++ b/docs-mslearn/.openpublishing.redirection.finops.json @@ -130,6 +130,11 @@ "redirect_url": "/cloud-computing/finops/toolkit/workbooks/customize-workbooks", "redirect_document_id": false }, + { + "source_path_from_root": "/finops/finops/toolkit/hubs/configure-sre.md", + "redirect_url": "/cloud-computing/finops/toolkit/sre-agent/overview", + "redirect_document_id": false + }, { "source_path_from_root": "/finops/finops/framework/manage/culture.md", "redirect_url": "/cloud-computing/finops/framework/manage/education", diff --git a/docs-mslearn/TOC.yml b/docs-mslearn/TOC.yml index 4d48e0aff..4edc706b0 100644 --- a/docs-mslearn/TOC.yml +++ b/docs-mslearn/TOC.yml @@ -54,7 +54,7 @@ href: framework/optimize/optimize-cloud-usage-cost.md - name: Architecting for cloud href: framework/optimize/architecting.md - - name: Workload optimization + - name: Usage optimization href: framework/optimize/workloads.md - name: Rate optimization href: framework/optimize/rates.md @@ -154,6 +154,26 @@ href: toolkit/hubs/upgrade.md - name: Compatibility guide href: toolkit/hubs/compatibility.md + - name: FinOps toolkit SRE Agent + items: + - name: Overview + href: toolkit/sre-agent/overview.md + - name: Deploy + href: toolkit/sre-agent/deploy.md + - name: Agents and skills + href: toolkit/sre-agent/agents.md + - name: Tools + href: toolkit/sre-agent/tools.md + - name: Scheduled tasks + href: toolkit/sre-agent/scheduled-tasks.md + - name: Knowledge and memory + href: toolkit/sre-agent/knowledge.md + - name: Security and permissions + href: toolkit/sre-agent/security.md + - name: Troubleshooting + href: toolkit/sre-agent/troubleshooting.md + - name: Template reference + href: toolkit/sre-agent/template.md - name: Power BI items: - name: Overview @@ -170,7 +190,7 @@ href: toolkit/power-bi/invoicing.md - name: Rate optimization report href: toolkit/power-bi/rate-optimization.md - - name: Workload optimization report + - name: Usage optimization report href: toolkit/power-bi/workload-optimization.md - name: Data ingestion report href: toolkit/power-bi/data-ingestion.md diff --git a/docs-mslearn/toolkit/changelog.md b/docs-mslearn/toolkit/changelog.md index 04f1298d2..6c538b1f8 100644 --- a/docs-mslearn/toolkit/changelog.md +++ b/docs-mslearn/toolkit/changelog.md @@ -3,7 +3,7 @@ title: FinOps toolkit changelog description: Review the latest features and enhancements in the FinOps toolkit, including updates to FinOps hubs, Power BI reports, and more. author: MSBrett ms.author: brettwil -ms.date: 05/19/2026 +ms.date: 06/01/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit @@ -25,55 +25,49 @@ This article summarizes the features and enhancements in each release of the Fin The following section lists features and enhancements that are currently in development. ---> - -
- -## v15 - -_Released June 2026_ - -### [Implementing FinOps guide](../implementing-finops-guide.md) v15 - -- **Fixed** - - Corrected stale and incorrect descriptions for `BilledCost`, `EffectiveCost`, `BillingCurrency`, `BillingProfileId`, `BillingProfileName`, `CommitmentDiscountQuantity`, `ListUnitPrice`, `PricingQuantity`, `PricingUnitDescription`, and `TotalSavingsRunningTotal` in the [data dictionary](help/data-dictionary.md) to align with FOCUS 1.2 ([#2112](https://github.com/microsoft/finops-toolkit/pull/2112)). - -### Claude Code plugin v15 +### Claude Code plugin v15.0.0 - **Added** - Added Claude Code plugin with skills for FinOps hubs and Azure Cost Management ([#2043](https://github.com/microsoft/finops-toolkit/pull/2043)). - Added 4 agents (CFO, FinOps practitioner, database query, hubs agent), 5 commands (`/ftk-hubs-connect`, `/ftk-hubs-healthCheck`, `/ftk-mom-report`, `/ftk-ytd-report`, `/ftk-cost-optimization`), and an output style. - Linked to the existing KQL query catalog in `src/queries/` from the plugin. -### [FinOps hubs](hubs/finops-hubs-overview.md) v15 +### Bicep Registry module pending updates -- **Changed** - - Added a callout to the `config_RunBackfillJob` backfill option clarifying that it isn't supported on Microsoft Customer Agreement (MCA) billing accounts or billing profiles ([#2113](https://github.com/microsoft/finops-toolkit/issues/2113)). +- Cost Management export modules for subscriptions and resource groups. ### [Data dictionary](help/data-dictionary.md) updates - **Fixed** - Corrected stale and incorrect descriptions for `BilledCost`, `EffectiveCost`, `BillingCurrency`, `BillingProfileId`, `BillingProfileName`, `CommitmentDiscountQuantity`, `ListUnitPrice`, `PricingQuantity`, `PricingUnitDescription`, and `TotalSavingsRunningTotal` to align with FOCUS 1.2 ([#2112](https://github.com/microsoft/finops-toolkit/pull/2112)). - -### [Optimization engine](optimization-engine/overview.md) updates - -- **Fixed** - - Removed call to Azure Classic administrators endpoint (deprecated on May 1, 2026) from Azure RBAC assignments exports ([#2142](https://github.com/microsoft/finops-toolkit/issues/2142)). - --> - -> [!div class="nextstepaction"] -> [Download](https://github.com/microsoft/finops-toolkit/releases/tag/v15) -> [!div class="nextstepaction"] -> [Full changelog](https://github.com/microsoft/finops-toolkit/compare/v14...v15) - -
+
## v14 _Released April 2026_ +### Claude Code plugin v13.0.0 + +- **Added** + - Added Claude Code plugin with skills for FinOps hubs and Azure Cost Management. + - Added 4 agents (CFO, FinOps practitioner, database query, hubs agent), 5 commands (`/ftk-hubs-connect`, `/ftk-hubs-healthCheck`, `/ftk-mom-report`, `/ftk-ytd-report`, `/ftk-cost-optimization`), and an output style. + - Linked to the existing KQL query catalog in `src/queries/` from the plugin. + +### [SRE agent](sre-agent/overview.md) + +- **Added** + - Added Azure SRE Agent template with a packaged Deploy to Azure path, `deploy.sh` local CLI automation, and Bicep infrastructure. + - Added 5 subagents (`finops-practitioner`, `azure-capacity-manager`, `chief-financial-officer`, `ftk-database-query`, `ftk-hubs-agent`), 3 skills, 50 tools, and 1 Kusto MCP connector. + - Added 19 scheduled tasks (daily, weekly, monthly, semiannual, and quarterly cadences) with Teams channel delivery. + - Added 6 knowledge documents for agent onboarding, artifact verification, Teams notification patterns, known issues, document index guidance, and FinOps Toolkit output style. + - Added FinOps toolkit SRE Agent documentation pages for Microsoft Learn. +- **Changed** + - Set agent action mode to Autonomous so scheduled tasks can deliver reports without human approval. + - Switched scheduled task persistence from legacy CLI creation to manifest apply for idempotent re-runs. + - Replaced "save to knowledge base" instructions with `#remember` for operational notes across all scheduled tasks. + ### [Implementing FinOps guide](../implementing-finops-guide.md) v14 - **Added** diff --git a/docs-mslearn/toolkit/hubs/configure-sre.md b/docs-mslearn/toolkit/hubs/configure-sre.md new file mode 100644 index 000000000..cf9800933 --- /dev/null +++ b/docs-mslearn/toolkit/hubs/configure-sre.md @@ -0,0 +1,249 @@ +--- +title: Configure an SRE agent for FinOps hubs +description: Learn how to configure an Azure SRE agent to connect to your FinOps hub for scheduled cost analysis, capacity monitoring, and reporting. +author: msbrett +ms.author: brettwil +ms.date: 06/02/2026 +ms.topic: how-to +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: micflan +# customer intent: As a FinOps hub admin, I want to connect an Azure SRE agent to my hub so that I can receive scheduled cost reports, anomaly detection, and capacity monitoring in Teams. +--- + +# Configure an SRE agent for FinOps hubs + +[Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) supports agent-based operational workflows. This article shows how to connect Azure SRE Agent to a [FinOps hub](finops-hubs-overview.md), configure scheduled cost analysis and capacity checks from the [SRE agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent), and send results to Teams with the [Teams notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). + +
+ +## Prerequisites + +- [Deployed a FinOps hub instance](finops-hubs-overview.md#create-a-new-hub) with Data Explorer. +- [Configured scopes](configure-scopes.md) and ingested data successfully. +- Permissions to create deployed resources, such as **Contributor** on the subscription when the template creates the agent resource group. You also need permissions to assign roles at subscription, target resource group, and agent scopes, such as **Role Based Access Control Administrator**, **User Access Administrator**, or **Owner** on those scopes. [Learn more](/azure/role-based-access-control/built-in-roles). +- The `Microsoft.App` resource provider [registered](https://learn.microsoft.com/azure/azure-resource-manager/management/resource-providers-and-types#register-resource-provider) on the subscription. +- For local CLI deployments only: [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) 2.60 or later, `curl`, `jq`, `python3`, and `bash` available locally for the [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent). + +
+ +## Review deployed resources + +The [SRE agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent) deploys a single Azure SRE agent with these resources and configuration objects: + +| Component | Count | Description | +|-----------|-------|-------------| +| SRE agent | 1 | Stable [`Microsoft.App/agents`](https://learn.microsoft.com/azure/sre-agent/overview) resource in [autonomous mode](https://learn.microsoft.com/azure/sre-agent/run-modes) | +| Managed identities | 1-2 | System-assigned managed identity for the agent; portal deployments also create a user-assigned identity for the deployment script | +| Log Analytics | 1 | Workspace for agent telemetry | +| Application Insights | 1 | Linked to Log Analytics for monitoring | +| Target resource group RBAC | 3-4 per target group | Reader, Monitoring Reader, Log Analytics Reader, and Contributor when `accessLevel` is `High` | +| Azure Data Explorer role (optional) | 1 | `AllDatabasesViewer` when Azure Data Explorer parameters are provided | +| Subagents | 5 | `finops-practitioner`, `azure-capacity-manager`, `chief-financial-officer`, `ftk-database-query`, `ftk-hubs-agent` | +| Skills | 3 | `azure-capacity-management`, `azure-cost-management`, `finops-toolkit` | +| Tools | 50 | Kusto and Python tools for cost, capacity, governance, and reporting workflows | +| Connector | 1 | Kusto MCP connector to the FinOps hub Azure Data Explorer cluster | +| Scheduled tasks | 19 | Reports at daily, weekly, monthly, semiannual, and quarterly cadences | +| Knowledge docs | 6 | Onboarding, artifact verification, Teams notification patterns, known issues, document index guidance, and the FinOps Toolkit output style | + +
+ +## Deploy the SRE agent + +Use the Azure portal deployment for the same one-click experience as other FinOps toolkit templates. The template creates the Azure resources and runs an embedded deployment script to apply the FinOps hub recipe assets. + + +> [!div class="nextstepaction"] +> [Deploy to Azure](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fmicrosoft.github.io%2Ffinops-toolkit%2Fdeploy%2Fsre-agent%2Flatest%2Fazuredeploy.json/createUIDefinitionUri/https%3A%2F%2Fmicrosoft.github.io%2Ffinops-toolkit%2Fdeploy%2Fsre-agent%2Flatest%2FcreateUiDefinition.json) + + +You can also use the [local deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent). It is copied from the Microsoft SRE Agent starter lab and updated for the FinOps toolkit. It uses Azure CLI + Bicep directly and doesn't use `azd`: + +```bash +cd src/templates/sre-agent + +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + --resource-group \ + --name \ + --location \ + --cluster-uri https://..kusto.windows.net/Hub \ + [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] +``` + +The portal deployment is the customer-facing template entry point. `bin/deploy.sh` remains available for local CLI automation. + +The local [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent): + +1. Sets the `az` CLI context to the target subscription. This step is required for [B2B tenant environments](#troubleshoot-b2b-tenant-environments). +2. Runs a subscription-scoped Azure CLI + Bicep deployment from `infra/main.bicep`. +3. Runs `bin/apply-extras.sh`, which applies the recipe assets that are not deployed by Bicep. + +The extras step follows the Microsoft SRE Agent template pattern: connectors and KnowledgeFile sources are applied as SRE Agent child resources, while built-in tool configuration, 3 skills, 5 subagents, 50 tools, and 19 scheduled tasks are applied through the SRE Agent data plane. + +### Grant the optional Azure Data Explorer viewer role + +To grant the agent's managed identity the `AllDatabasesViewer` role on your Azure Data Explorer cluster, pass `--cluster-uri`. The deployment resolves the cluster ARM resource ID from the URI when the cluster is in the target subscription. If the cluster is in another subscription or can't be resolved, pass `--cluster-resource-id` explicitly. The deployment uses the [Azure Data Explorer role module](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/infra/modules/kusto-all-databases-viewer-rbac.bicep): + +```bash +--cluster-uri https://..kusto.windows.net/Hub \ +--cluster-resource-id /subscriptions/.../resourceGroups//providers/Microsoft.Kusto/clusters/ +``` + +If your Azure Data Explorer cluster has `publicNetworkAccess` set to `Disabled`, the deployment still creates all SRE Agent resources, assigns `AllDatabasesViewer`, and creates the `finops-hub-kusto` connector. The script also prints a warning because hosted Azure SRE Agent can't run direct KQL queries against private endpoint ADX clusters. Review the [Azure SRE Agent VNET known limitations](https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations), then decide whether to enable public query access for the cluster. Until public query access is enabled or Azure SRE Agent adds private endpoint ADX query support, the connector is expected to remain unhealthy. + +### Redeploy an existing agent + +To update an existing agent, rerun the [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent) with the same resource group and agent name: + +```bash +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + --resource-group \ + --name \ + --location \ + --cluster-uri https://..kusto.windows.net/Hub \ + [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] +``` + +### Delete the deployment + +To delete Azure resources, delete the resource group that contains the SRE Agent resources after confirming no other resources share it: + +```bash +az group delete --subscription --name +``` + +
+ +## Verify the deployment + +After `bin/deploy.sh` completes, use the template's [post-deployment verification guidance](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent#verify): + +1. Confirm `bin/apply-extras.sh` completed without errors. +2. Open [sre.azure.com](https://sre.azure.com), switch to the directory that contains your subscription, and select your agent. +3. Confirm 5 subagents, 3 skills, and 50 tools appear in **Builder**. +4. Go to **Scheduled tasks** and confirm 19 tasks are listed and active. +5. Ask the agent: `What knowledge documents do you have?` and confirm the shipped knowledge is available. + +
+ +## Configure Teams notifications + +Scheduled tasks can send reports to a Teams channel through the [Teams notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). The connector requires interactive OAuth setup in the portal. + +1. Open [sre.azure.com](https://sre.azure.com), open your agent, then go to **Builder** > **Connectors**. +2. Select **Add connector** > **Send notification (Microsoft Teams)**. +3. Sign in with your Microsoft 365 account and paste the channel URL from **Get link to channel** in Teams. +4. Select the agent's managed identity and save. +5. Test from chat: `Post a test message to our Teams channel saying "FinOps SRE agent connected."` + +Use the built-in `PostTeamsMessage` tool from the [Teams notification guidance](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/recipes/finops-hub/knowledge/teams-notification-guide.md). Don't call the Microsoft Graph API or the connection's `dynamicInvoke` endpoint directly because that path returns a 403 error for this connector configuration. + +For Outlook notifications, follow the same pattern with the **Outlook Tools (Office 365 Outlook)** connector. See [Send notifications](https://learn.microsoft.com/azure/sre-agent/send-notifications) for details. + +
+ +## Review scheduled tasks + +The template deploys 19 scheduled tasks from the [`recipes/finops-hub/automations/scheduled-tasks`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks) folder. When the Teams connector is configured, each task posts its final report to the connected channel: + +| Task | Agent | Schedule | What it reports | +|------|-------|----------|-----------------| +| HubsHealthCheck | finops-practitioner | Daily 6:00 AM | Hub version, data freshness, and pipeline status | +| CapacityDailyMonitor | finops-practitioner | Daily 6:30 AM | Quota usage, CRG utilization, and alert status | +| ComputeUtilizationTrend | finops-practitioner | Weekly Monday 7:00 AM | VM quota utilization trends across subscriptions and regions | +| CostOptimization | finops-practitioner | Weekly Monday 8:00 AM | Orphaned resources, rightsizing, and commitment opportunities | +| CapacityWeeklySupplyReview | finops-practitioner | Weekly Monday 8:00 AM | Quota headroom, CRG cost-waste audit, and benefit recommendations | +| NonComputeQuotaAudit | finops-practitioner | Weekly Tuesday 7:00 AM | Storage, network, and non-compute quota risks | +| DbQuotaAudit | finops-practitioner | Weekly Wednesday 7:00 AM | Database quota and region or zone access risks | +| SkuAvailabilityAudit | finops-practitioner | Weekly Wednesday 7:30 AM | Regional SKU availability and deployment blockers | +| MonitoringScopeValidation | finops-practitioner | Weekly Thursday 9:00 AM | Subscription monitoring coverage and hub freshness | +| BenefitRecommendationReview | finops-practitioner | Weekly Friday 8:00 AM | Reservation and savings plan recommendations with finance framing | +| StoragePaasGrowthForecast | finops-practitioner | Monthly 1st 8:00 AM | Storage and PaaS quota growth forecast | +| AdvisorSuppressionReview | finops-practitioner | Monthly 1st 9:00 AM | Active Advisor suppression age, expiration, and risk | +| CapacityMonthlyPlanning | finops-practitioner | Monthly 1st 9:00 AM | Demand forecast, capacity request pipeline, and governance review | +| AIWorkloadCostAnalysis | finops-practitioner | Monthly 1st 10:00 AM | AI token economics, model efficiency, and cost allocation | +| Monthly | finops-practitioner | Monthly on the 5th at 5:15 PM | Month-over-month cost analysis using Kusto evidence delegated to ftk-database-query | +| BudgetCoverageAudit | finops-practitioner | Monthly 15th 8:00 AM | Subscription budget coverage and missing guardrails | +| AlertCoverageAudit | finops-practitioner | Monthly 16th 8:00 AM | Cost anomaly alert coverage across active subscriptions | +| Semiannual | finops-practitioner | January 5 and July 5 at 9:00 AM | Semiannual year-over-year finance analysis with forecast and CFO consultation | +| CapacityQuarterlyStrategy | finops-practitioner | Quarterly 9:00 AM | FinOps capability maturity, commitment alignment, and architecture review | + +Each scheduled task reads the uploaded knowledge documents before it starts and applies `ftk-output-style.md` for evidence, formatting, FinOps capability mapping, confidence, and caveat conventions. Send financial results to Teams through the configured [notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). Save only operational notes, such as tool errors, workarounds, and patterns, to agent [memory](https://learn.microsoft.com/azure/sre-agent/memory) with `#remember`; don't save financial data. + +
+ +## Troubleshoot B2B tenant environments + +In B2B environments, the Azure subscription and Azure SRE Agent resource can live in a different Microsoft Entra tenant than your Microsoft 365 home tenant. The deployment script sets the active subscription before deployment to align the CLI context with the resource tenant. + +If [sre.azure.com](https://sre.azure.com) shows the agent correctly but `bin/apply-extras.sh` cannot get an SRE Agent data-plane token, use these B2B tenant checks: + +1. Confirm the active Azure CLI context points at the subscription that owns the SRE agent resource. +2. Re-authenticate against the tenant that owns the subscription. +3. Run `az login --scope https://azuresre.dev/.default`, then rerun `bin/deploy.sh` or `bin/apply-extras.sh`. + +Browser success with CLI failure indicates that the CLI token was issued for the wrong tenant. The [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent) runs `az account set --subscription` before deployment to set the target subscription context. + +
+ +## Review built-in capabilities + +Azure SRE Agent includes platform capabilities that are on by default in this template: + +- **Workspace tools**: Azure SRE Agent can run file, terminal, and Python operations in a sandboxed environment for data analysis, chart generation, and report formatting. The [Bicep template](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/infra/modules/sre-agent.bicep) deploys the stable agent API and sets `experimentalSettings.EnableSandboxGroup` and `experimentalSettings.EnableWorkspaceTools`. See [Deep context](https://learn.microsoft.com/azure/sre-agent/workspace-tools). +- **DocsGuide**: DocsGuide provides Azure documentation grounding for agent responses. See [Use DocsGuide](https://learn.microsoft.com/azure/sre-agent/use-docsguide). +- **Visualization**: Built-in chart and table rendering for investigation results. See [Tools](https://learn.microsoft.com/azure/sre-agent/tools). +- **Memory**: Memory stores operational knowledge across sessions. See [Memory and knowledge](https://learn.microsoft.com/azure/sre-agent/memory). + +The analytical subagents include `execute_python` where they need calculations, charts, tables, and downloadable artifacts. `finops-practitioner` orchestrates scheduled analysis, `ftk-database-query` owns Kusto evidence, `azure-capacity-manager` owns Azure capacity evidence, and `chief-financial-officer` provides finance and leadership consultation. + +
+ +## Review supported regions + +The Azure SRE Agent deployment supports `australiaeast`, `canadacentral`, `eastus2`, `francecentral`, `koreacentral`, `swedencentral`, and `uksouth`. The [Bicep template](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/main.bicep) restricts the `location` parameter with `@allowed`. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20FinOps%20hubs%3F/cvaQuestion/How%20valuable%20are%20FinOps%20hubs%3F/surveyId/FTK/bladeName/Hubs/featureName/ConfigureSRE) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20FinOps%20hubs%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Rate optimization](../../framework/optimize/rates.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) + +Related solutions: + +- [Configure AI agents for FinOps hubs](configure-ai.md) +- [FinOps hubs](finops-hubs-overview.md) +- [FinOps toolkit Power BI reports](../power-bi/reports.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/agents.md b/docs-mslearn/toolkit/sre-agent/agents.md new file mode 100644 index 000000000..1257c7b15 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/agents.md @@ -0,0 +1,363 @@ +--- +title: Specialist agents and skills (Azure SRE Agent in the FinOps toolkit) +description: Understand how the FinOps toolkit configures Azure SRE Agent with specialist agents, tools, skills, and knowledge to automate FinOps and capacity management work. +author: msbrett +ms.author: brettwil +ms.date: 06/01/2026 +ms.topic: concept-article +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand how the FinOps toolkit's specialist agents and skills work so that I can route work to the right specialist. +--- + +# Specialist agents and skills (Azure SRE Agent in the FinOps toolkit) + +The FinOps toolkit configures [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) with a multi-agent architecture aligned to the canonical FinOps Framework. One orchestrator receives prompts and scheduled tasks, then delegates work to specialist subagents with focused FinOps, finance, capacity, database, and hub operations expertise. + +The template configures 5 subagents, 3 skills, 50 tools (37 generated Kusto tools and 13 Python tools), and a FinOps hub connector. The orchestrator keeps the experience simple. The specialist agents keep answers grounded in the right domain. + +
+ +## finops-practitioner + +Domain: FinOps practice guidance, cost allocation, optimization, anomaly response, AI cost management, governance, and operating-model design. + +The `finops-practitioner` agent helps teams apply FinOps principles to real Azure cost and usage questions. It assesses business context, maturity, stakeholders, and trade-offs before recommending actions. It leads scheduled FinOps workflows and delegates evidence collection to specialists. + +What it does: + +- Guides cost allocation, shared-cost strategy, showback, and chargeback. +- Orchestrates cost anomaly and cost-driver investigations using evidence from `ftk-database-query`. +- Plans Usage Optimization, Rate Optimization, Governance, Policy & Risk, and practice health improvements. +- Translates FinOps concepts into practical Microsoft Cost Management and FinOps toolkit steps. +- Keeps recommendations maturity-aware across Crawl, Walk, and Run stages. + +Key tool routing: + +- The orchestrator has no direct operational tools. +- Delegation to `ftk-database-query` for every Kusto, FOCUS, `Costs()`, `Prices()`, `Recommendations()`, and `Transactions()` evidence request. +- Delegation to `azure-capacity-manager` for quota, capacity reservation, SKU, region, zone, and AI/GPU capacity evidence. +- Delegation to `ftk-hubs-agent` for Resource Graph, data freshness, hub infrastructure, budget deployment, anomaly alert deployment, and Advisor suppression tools. + +When it's invoked: + +- A user asks for FinOps practice guidance, anomaly triage, allocation, governance, reporting, optimization, or maturity planning. +- A scheduled task needs recurring cost visibility, optimization review, AI cost analysis, or FinOps practice health checks. +- The orchestrator needs a general FinOps owner before handing deeper Kusto or finance work to another specialist. + +Example prompts: + +- "Help me design a showback model for shared platform costs across engineering teams." +- "Investigate why our AI costs increased this month and recommend the first three actions." +- "Create a Crawl-Walk-Run plan for improving tagging, budgets, anomaly response, and optimization." +- "Review our reservation and savings plan opportunities and explain which FinOps capabilities we should mature first." + +Expected output: + +- A practical FinOps recommendation with business context, maturity assumptions, trade-offs, and next steps. +- Evidence-backed cost drivers, optimization opportunities, governance actions, and stakeholder guidance. +- Clear separation between what the agent knows from tool evidence and what needs more data. + +Use this agent versus another: + +- Use `finops-practitioner` first when the question mixes cost analysis, FinOps process, governance, allocation, optimization, and stakeholder planning. +- Use `ftk-database-query` instead when the main deliverable is a specific KQL query, schema explanation, or detailed Hub database result. +- Use `chief-financial-officer` instead when the main deliverable is an executive finance narrative, budget decision, board-ready summary, or capital-allocation recommendation. +- Use `azure-capacity-manager` instead when the constraint is quota, capacity reservation supply, region access, zones, or AKS capacity readiness. +- Use `ftk-hubs-agent` instead when the work is deploying, upgrading, configuring, or troubleshooting a FinOps hub. + +
+ +## azure-capacity-manager + +Domain: Azure capacity evidence for Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization support, Governance, Policy & Risk, and Automation, Tools & Services. + +The `azure-capacity-manager` agent maps Azure quota, region, SKU, zone, capacity reservation, and AKS capacity evidence into the FinOps Framework. It separates capacity guarantees from pricing commitments so teams can make better quota, reservation, and savings decisions. + +What it does: + +- Reviews quota usage, quota increases, quota groups, transfers, and headroom. +- Plans capacity reservation groups, sharing, overallocation, and utilization checks. +- Evaluates region access, zonal enablement, and logical-to-physical zone alignment. +- Checks AKS node pool capacity readiness and non-compute quota constraints. +- Aligns capacity planning with reservation and savings plan recommendations. + +Key tools it uses: + +- Azure CLI tools, such as `RunAzCliReadCommands`, `RunAzCliWriteCommands`, and `GetAzCliHelp` +- Python analysis through `execute_python` +- Capacity tools such as `vm-quota-usage`, `non-compute-quotas`, `db-service-quotas`, `sku-availability`, and `capacity-reservation-groups` +- Azure Resource Graph and benefit recommendation tools where capacity, inventory, and rate-optimization context intersect +- Delegation to `ftk-database-query` for Kusto-backed forecast, commitment utilization, savings, pricing, recommendation, and transaction evidence + +When it's invoked: + +- A user asks about quota, capacity reservations, region access, availability zones, AKS capacity, or capacity governance. +- A scheduled capacity task checks daily quota usage, weekly capacity readiness, monthly planning, or quarterly strategy. +- Another agent needs capacity context before recommending commitments, scaling changes, or regional moves. + +Example prompts: + +- "Check whether we have enough quota and regional capacity for next month's AKS node pool expansion." +- "Plan a capacity reservation strategy for a production workload that needs guaranteed VM supply in two regions." +- "Compare our capacity reservation utilization with savings plan recommendations before we buy more commitments." +- "Explain the zone mapping risks before we move this workload to a multi-zone architecture." + +Expected output: + +- A capacity-readiness assessment with quota, region, zone, reservation, and utilization findings. +- Recommended capacity actions, such as quota requests, reservation group changes, region alternatives, or monitoring tasks. +- Explicit distinction between capacity guarantees and pricing commitments so teams don't treat reservations, savings plans, and quota as interchangeable. + +Use this agent versus another: + +- Use `azure-capacity-manager` when supply availability is the main question: quota, capacity reservations, region access, zones, AKS node pools, or capacity governance. +- Use `finops-practitioner` instead when the question is primarily about FinOps operating model, allocation, anomaly response, or broad cost optimization. +- Use `chief-financial-officer` instead when capacity decisions need executive budget framing, investment trade-offs, or board-ready risk language. +- Use `ftk-database-query` instead when you need exact Hub Kusto results about cost, utilization, recommendations, or pricing before making a capacity decision. +- Use `ftk-hubs-agent` instead when the capacity issue is blocking a hub deployment, upgrade, or configuration workflow. + +
+ +## chief-financial-officer + +Domain: Executive finance, budgeting, forecasting, risk, capital allocation, cloud economics, and board-ready FinOps narratives. + +The `chief-financial-officer` agent turns evidence packages into financial guidance. It focuses on business outcomes, executive summaries, quantified assumptions, and decision-ready recommendations. It is a consultative persona and doesn't own autonomous scheduled tasks or raw data collection. + +What it does: + +- Prepares budgeting, rolling forecasts, variance analysis, and KPI-driven performance views. +- Evaluates investment priorities, capital allocation, risk, controls, and compliance exposure. +- Assesses cloud spend through unit economics, commitment decisions, and value creation. +- Produces recommendations for boards, CEOs, finance leaders, and FinOps stakeholders. +- Calls out missing data, uncertainty, risks, and follow-up steps. + +Key tools it uses: + +- Python analysis through `execute_python` for scenario calculations and executive packaging +- Evidence packages from `finops-practitioner`, `ftk-database-query`, and `azure-capacity-manager` +- Teams tools for final communication when a configured workflow asks for executive delivery + +When it's invoked: + +- A user asks for executive summaries, budget variance, forecast drift, board narratives, or portfolio trade-offs. +- The `finops-practitioner` agent needs finance leadership for executive framing, prioritization, commitment risk, or investment tradeoffs. + +Example prompts: + +- "Summarize cloud spend performance for the CFO with risks, opportunities, and decisions needed this week." +- "Explain the budget variance for the quarter and separate timing issues from structural run-rate changes." +- "Create a board-ready narrative for our AI investment, including unit economics and governance risks." +- "Prioritize these three optimization programs by financial impact, execution risk, and business value." + +Expected output: + +- An executive-ready finance view with quantified assumptions, variance explanations, risks, options, and recommended decisions. +- Budget, forecast, portfolio, or investment guidance that connects cloud spend to business outcomes. +- Clear caveats for missing evidence, confidence level, and follow-up data needed before committing to a decision. + +Use this agent versus another: + +- Use `chief-financial-officer` when the audience is executives, finance leaders, boards, or business owners making budget, forecast, risk, or investment decisions. +- Use `finops-practitioner` instead when the work needs broader FinOps process guidance, practitioner playbooks, or operating-model design. +- Use `ftk-database-query` instead when the deliverable is detailed KQL, data extraction, schema validation, pricing lookup, or recommendation analysis. +- Use `azure-capacity-manager` instead when the core issue is capacity supply, quota, zones, reservation groups, or regional access. +- Use `ftk-hubs-agent` instead when financial reporting is blocked by hub deployment, export, connectivity, version, or health issues. + +
+ +## ftk-database-query + +Domain: FinOps hub database analysis, FOCUS-aligned KQL, schema validation, query diagnostics, pricing, recommendations, and transactions. + +The `ftk-database-query` agent is the KQL specialist. It queries the Hub database, explains schema choices, and adapts catalog queries before writing custom KQL. + +What it does: + +- Uses the Hub database for analytics and avoids the Ingestion database for end-user analysis. +- Starts with the query catalog and adapts the closest existing query when possible. +- Builds scoped custom drill-downs from `costs-enriched-base` when no catalog query fits and uses aggregate tools for full-month or scheduled reports. +- Uses `Costs()`, `Prices()`, `Recommendations()`, and `Transactions()` for FOCUS-aligned analysis. +- Explains filters, functions, metrics, missing data, and data freshness concerns. + +Key tools it uses: + +- Memory and Azure discovery through `SearchMemory`, `RunAzCliReadCommands`, and `GetAzCliHelp` +- Python analysis through `execute_python` +- The full FinOps hub Kusto catalog, including `costs-enriched-base`, `monthly-cost-trend`, `top-services-by-cost`, `cost-by-region-trend`, `cost-anomaly-detection`, `cost-forecasting-model`, `commitment-discount-utilization`, `savings-summary-report`, `top-other-transactions`, and AI cost tools + +When it's invoked: + +- A user asks for a KQL query, schema explanation, pricing lookup, recommendation analysis, transaction analysis, or cost drill-down. +- A scheduled task needs exact FinOps hub data, a focused diagnostic, or FOCUS-aligned query execution. +- Another agent needs live cost data or schema-aware analysis before making a recommendation. + +Example prompts: + +- "Write a FOCUS-aligned KQL query that shows month-over-month cost by service and billing account." +- "Use the Hub database to find the top resources driving last week's cost anomaly." +- "Explain which columns from `Costs()` I should use for amortized cost, list cost, and chargeback reporting." +- "Compare prices for this SKU across regions and show the assumptions in the query." + +Expected output: + +- A query-first answer with the selected catalog query or custom KQL, filters, assumptions, and expected columns. +- Data interpretation that explains schema choices, functions, time windows, aggregation grain, and freshness limitations. +- Diagnostics for query failures or missing results, including what to validate in the Hub database or source exports. + +Use this agent versus another: + +- Use `ftk-database-query` when the question depends on exact FinOps hub data, KQL, schema details, pricing data, recommendations, or transaction records. +- Use `finops-practitioner` instead when you need to turn query results into a broader FinOps plan, operating-model recommendation, or governance approach. +- Use `chief-financial-officer` instead when data results need to become an executive budget, forecast, risk, or portfolio decision narrative. +- Use `azure-capacity-manager` instead when the query is only supporting quota, capacity reservation, regional supply, zone, or AKS readiness decisions. +- Use `ftk-hubs-agent` instead when the problem is that hub data is missing, stale, inaccessible, or caused by deployment or export health issues. + +
+ +## ftk-hubs-agent + +Domain: FinOps hubs deployment, upgrades, configuration, exports, dashboards, connectivity, and health. + +The `ftk-hubs-agent` agent keeps FinOps hubs running. It uses validation-first workflows for deployment, upgrade, maintenance, and troubleshooting. + +What it does: + +- Deploys and upgrades FinOps hubs. +- Maintains hub configuration, exports, dashboards, and connectivity. +- Troubleshoots deployment failures and unhealthy hub environments. +- Checks prerequisites, required resource providers, RBAC, regions, quotas, naming conflicts, and existing resources. +- Runs template validation and what-if checks before deploy or upgrade changes. + +Key tools it uses: + +- Knowledge search through `SearchMemory` +- Azure CLI tools, such as `RunAzCliReadCommands`, `RunAzCliWriteCommands`, and `GetAzCliHelp` +- Direct REST freshness checks through `data-freshness-check`, which treats `Costs()` as the source of truth for hub data freshness + +When it's invoked: + +- A user asks to deploy, upgrade, configure, maintain, or troubleshoot FinOps hubs. +- A scheduled health task checks FinOps hub readiness, export freshness, version status, or connectivity. +- Another agent needs hub health context before trusting query results or scheduled reports. + +Example prompts: + +- "Validate whether my environment is ready to deploy FinOps hubs and list any blocking prerequisites." +- "Troubleshoot why my Cost Management exports are not showing up in the Hub database." +- "Plan a safe FinOps hubs upgrade and include validation, what-if, and rollback checks." +- "Check hub data freshness and explain whether reports should trust the current `Costs()` results." + +Expected output: + +- A deployment, upgrade, configuration, or troubleshooting plan that starts with validation and identifies blockers before changes. +- Hub health findings for prerequisites, RBAC, providers, exports, connectivity, version status, and data freshness. +- Recommended next actions, including safe validation commands, what-if checks, and escalation points when write operations are required. + +Use this agent versus another: + +- Use `ftk-hubs-agent` when the work changes or diagnoses the FinOps hub platform itself: deployment, upgrade, configuration, exports, connectivity, dashboards, or health. +- Use `ftk-database-query` instead when the hub is healthy and the question is about KQL, schema, pricing, recommendations, transactions, or cost drill-downs. +- Use `finops-practitioner` instead when hub data needs to become a FinOps process, optimization, allocation, governance, or anomaly response recommendation. +- Use `chief-financial-officer` instead when hub findings need executive finance framing, budget guidance, or portfolio prioritization. +- Use `azure-capacity-manager` instead when a deployment or scaling issue is primarily about Azure quota, capacity reservation supply, region access, or zones. + +
+ +## Handoff model + +The orchestrator starts with the user's prompt or scheduled task instructions. It selects the agent whose `handoffDescription` best matches the task, then passes the conversation to that specialist. + +Agents can also recommend handoffs when the work crosses domain boundaries: + +- `finops-practitioner` hands executive finance narratives, portfolio prioritization, and board-level recommendations to `chief-financial-officer`. +- `finops-practitioner` hands deep FinOps hub database and KQL work to `ftk-database-query`. +- `finops-practitioner` hands capacity evidence requests to `azure-capacity-manager` when the task involves quota, capacity reservations, region access, zones, AKS capacity, or capacity governance. +- Hub deployment, upgrade, and troubleshooting work routes to `ftk-hubs-agent`. + +Handoffs keep each response focused. The FinOps specialist can frame the business problem, the KQL specialist can gather evidence, the capacity specialist can validate supply constraints, and the finance specialist can turn the findings into an executive decision. + +
+ +## Skills + +Skills give agents a domain reference map. The template applies all three skills to Azure SRE Agent. When a prompt or scheduled task enters one of these domains, the matching skill can load before the agent responds. + +### azure-capacity-management + +Provides Azure capacity management guidance for SaaS ISVs running workloads in their own Azure subscriptions under Enterprise Agreement or Microsoft Customer Agreement billing. It covers quota operations, quota groups, capacity reservation groups, region access, zonal enablement, AKS capacity governance, non-compute quotas, and capacity alerts. In this recipe, those references are used as implementation detail under the canonical FinOps Framework capabilities. + +The `azure-capacity-manager` agent is instructed to load this skill before capacity work. Capacity scheduled tasks also tell the agent to load it before checking quota, capacity reservation, SKU, or supply-readiness signals. + +### azure-cost-management + +Provides Azure cost optimization and financial governance guidance. It covers Advisor recommendations, commitment discounts, budgets, exports, anomaly alerts, credits, Microsoft Azure Consumption Commitment tracking, orphaned resources, VM rightsizing, and Azure retail price lookup. + +FinOps and reporting scheduled tasks load this skill with the `finops-toolkit` skill when they need Microsoft Cost Management context beyond FinOps hub Kusto data. + +### finops-toolkit + +Provides FinOps toolkit and FinOps hubs guidance. It maps tasks to the right references, explains Hub database functions, lists the Kusto query catalog, and covers hub deployment, upgrade, health checks, FOCUS mapping, Power BI, alerts, workbooks, and the FinOps toolkit for PowerShell. + +FinOps hub query, reporting, and AI cost tasks load this skill so agents can use the Hub database, `Costs()`, `Prices()`, `Recommendations()`, `Transactions()`, and the predefined Kusto query catalog correctly. + +
+ +## How agents, tools, skills, and knowledge work together + +The agent combines four layers: + +1. **Agents** route the work to the right specialist. +2. **Skills** load domain guidance and reference maps. +3. **Tools** gather evidence from Azure, FinOps hubs, Python analysis, and Kusto queries. +4. **Knowledge** supplies onboarding guidance, notification patterns, and known issue context. + +Together, these layers help the agent move from a question to an evidence-backed recommendation. The orchestrator delegates, the specialist loads the right skill, tools collect the data, and knowledge keeps the answer aligned with the deployed environment. The FinOps practitioner coordinates the operating model, the database specialist gathers Kusto evidence, the capacity specialist gathers Azure capacity evidence, and the CFO supplies finance and leadership framing. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Anomaly management](../../framework/understand/anomalies.md) +- [Cost allocation](../../framework/understand/allocation.md) +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Architecting for cloud](../../framework/optimize/architecting.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure Monitor](/azure/azure-monitor/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) +- [Azure SRE Agent template reference (FinOps toolkit)](template.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/deploy.md b/docs-mslearn/toolkit/sre-agent/deploy.md new file mode 100644 index 000000000..3e135a6fe --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/deploy.md @@ -0,0 +1,219 @@ +--- +title: Deploy Azure SRE Agent with the FinOps toolkit +description: Deploy the FinOps toolkit Azure SRE Agent template from the Azure portal or CLI, connect it to a FinOps hub Data Explorer cluster, and validate the deployment. +author: msbrett +ms.author: brettwil +ms.date: 06/02/2026 +ms.topic: tutorial +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps hub admin, I want to deploy and configure the FinOps toolkit's Azure SRE Agent so that I can receive scheduled cost reports, anomaly detection, and capacity monitoring. +--- + + + +# Deploy Azure SRE Agent with the FinOps toolkit + +In this tutorial, you learn how to deploy the [FinOps toolkit Azure SRE Agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent), connect it to a [FinOps hub](../hubs/finops-hubs-overview.md), and validate the deployment. + +The deployment flow is copied from the Microsoft SRE Agent starter lab and updated for the FinOps toolkit. The Azure portal path uses the toolkit's packaged ARM template and an embedded deployment script to apply the SRE Agent recipe. The local CLI path uses Azure CLI + Bicep for infrastructure and the supported SRE Agent ARM and data-plane surfaces for recipe configuration. It doesn't use `azd`. + +## What gets deployed + +The FinOps hub recipe (`src/templates/sre-agent/recipes/finops-hub/`) deploys: + +| Component | Count | Notes | +|-----------|-------|-------| +| SRE Agent | 1 | `Microsoft.App/agents` | +| Model provider | 1 | Azure OpenAI provider-level routing (`MicrosoftFoundry` ARM value, `Automatic` model routing) | +| Managed identities | 1-2 | Agent system-assigned managed identity; portal deployments also create a user-assigned identity for the deployment script | +| Log Analytics workspace | 1 | Linked to the agent for telemetry | +| Application Insights | 1 | Linked to Log Analytics | +| Custom agents | 5 | FinOps practitioner orchestrator plus CFO, capacity, database-query, and hubs specialists | +| Skills | 3 | Capacity, cost management, and FinOps Toolkit | +| Tools | 50 | Kusto, capacity, and Hub infrastructure tools | +| Tool overrides | 9 | Enables SRE Agent Log Query and Visualization tools | +| Scheduled tasks | 19 | FinOps, governance, and reporting automations | +| Kusto connector | 0 or 1 | Included when you pass `--cluster-uri` | +| Knowledge docs | 6 | Five recipe knowledge docs plus the FinOps Toolkit output style | + +## Prerequisites + +- A deployed FinOps hub with Data Explorer. +- Permissions to create deployed resources, such as **Contributor** on the subscription when the template creates the agent resource group. +- Permissions to assign roles at subscription, target resource group, and agent scopes, such as **Role Based Access Control Administrator**, **User Access Administrator**, or **Owner** on those scopes. +- The `Microsoft.App` resource provider registered in the subscription. +- For local CLI deployments only: [Azure CLI](/cli/azure/install-azure-cli), `curl`, `jq`, `python3` with `PyYAML`, and Bash 3.2 or newer. + +Run: + +```bash +cd src/templates/sre-agent +bash bin/check-prerequisites.sh --subscription +``` + +## Deploy the FinOps hub recipe + +Use the Azure portal deployment when you want the same one-click experience as other FinOps toolkit templates. The template creates the Azure resources, grants the deployment script identity SRE Agent Administrator on the agent, downloads the packaged recipe assets, and applies connectors, tools, skills, subagents, knowledge, and scheduled tasks. + + +> [!div class="nextstepaction"] +> [Deploy to Azure](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fmicrosoft.github.io%2Ffinops-toolkit%2Fdeploy%2Fsre-agent%2Flatest%2Fazuredeploy.json/createUIDefinitionUri/https%3A%2F%2Fmicrosoft.github.io%2Ffinops-toolkit%2Fdeploy%2Fsre-agent%2Flatest%2FcreateUiDefinition.json) + + +### Deploy from local CLI + +Run one script with explicit parameters: + +```bash +cd src/templates/sre-agent + +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + --resource-group \ + --name \ + --location \ + --cluster-uri https://..kusto.windows.net/Hub \ + [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] \ + [--target-resource-group ...] \ + [--dry-run] \ + [--force] \ + [--no-telemetry] +``` + +`bin/deploy.sh --help` is the CLI contract: + +```text +Usage: bash bin/deploy.sh --recipe [options] + +Required: + --recipe Recipe directory + --subscription Azure subscription + -g, --resource-group Resource group for the agent + -n, --name Agent name + -l, --location Azure region + +Optional: + --target-resource-group Repeatable target resource group. Defaults to --resource-group. + --cluster-uri Kusto connector URI, including database name. + Example: https://..kusto.windows.net/Hub + --cluster-resource-id Optional Kusto cluster ARM resource ID. Real deployments resolve this from --cluster-uri when possible; dry-run requires it. + --no-subscription-reader Do not assign Reader at subscription scope. Default: assign Reader. + --deploy-name Deployment name override. Defaults to a deterministic name. + --dry-run Validate inputs and write parameters without Azure calls. + --force Accepted for compatibility. + --no-telemetry Accepted for compatibility. + -h, --help Show this help. +``` + +## Validation modes + +Dry-run is hermetic and skips live Azure calls: + +```bash +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + -g \ + -n \ + -l \ + --cluster-uri https://..kusto.windows.net/Hub \ + --cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/ \ + --dry-run +``` + +When deploying from the portal, the template runs a subscription-scoped ARM deployment and then runs a `Microsoft.Resources/deploymentScripts` resource to configure the Kusto connector and remaining recipe assets through the supported SRE Agent ARM and data-plane surfaces. When deploying locally, `deploy.sh` runs the same subscription-scoped infrastructure deployment and then runs `bin/apply-extras.sh` for the recipe configuration step. + +The recipe defaults the parent SRE Agent to Azure OpenAI provider-level routing by setting `defaultModel.provider` to `MicrosoftFoundry` and `defaultModel.name` to `Automatic`. Azure SRE Agent automatically selects the model within the configured provider for each task. The template doesn't pin different models for individual custom agents or scheduled tasks because the documented SRE Agent configuration surface is provider-level. + +Resource names are deterministic for the subscription ID, agent resource group ID, and agent name. Use the same values to update an existing deployment. Post-provisioning deletes existing scheduled tasks with the recipe's task names before applying manifests so redeployments don't create duplicate automations. `--deploy-name` only changes the ARM deployment record and local build directory. + +The deployment assigns `Reader` at subscription scope by default so subscription inventory, Resource Graph, capacity, quota, and monitoring-coverage tools can inspect the deployment subscription. Pass `--no-subscription-reader` only when you grant equivalent read access another way. + +If `--cluster-uri` points to an Azure Data Explorer cluster with `publicNetworkAccess` set to `Disabled`, the script still deploys all resources, assigns the agent identity `AllDatabasesViewer`, and creates the `finops-hub-kusto` connector. It also prints a warning with the SRE Agent known-limitations URL because private endpoint ADX blocks direct KQL queries from the hosted agent. The customer can decide whether to enable public query access for the connector after reviewing . + +## Recipe identity defaults + +- Shipped recipes in this repo omit the `identity` block. +- Customer-authored recipes can keep identity defaults in `agent.json`. +- CLI flags always override recipe defaults. + +If you omit `--target-resource-group`, the deploy flow uses the recipe default when present; otherwise it falls back to the agent resource group. + +## Verify the deployment + +```bash +bash bin/verify-agent.sh \ + $(az account show --query id -o tsv) \ + \ + \ + --expected recipes/finops-hub +``` + +Then confirm the agent in [sre.azure.com](https://sre.azure.com). If you passed `--cluster-uri`, verify the `finops-hub-kusto` connector. If the deployment warned that the cluster denies public query access, the connector is expected to remain unhealthy until the customer enables public query access or Microsoft adds private endpoint ADX query support for SRE Agent. + +## Configure notifications + +Scheduled tasks deliver reports to Microsoft Teams and Outlook through Azure SRE Agent notification connectors. Connectors require interactive OAuth setup in [sre.azure.com](https://sre.azure.com), so the portal template and `bin/deploy.sh` don't create them. + +### Configure Teams + +1. Open [sre.azure.com](https://sre.azure.com), open your agent, then go to **Builder** > **Connectors**. +2. Select **Add connector** > **Send notification (Microsoft Teams)**. +3. Sign in with your Microsoft 365 account. +4. Paste the channel URL from **Get link to channel** in Teams. +5. Select the agent's managed identity and save. +6. Test from chat: `Post a test message to our Teams channel saying "Azure SRE Agent connected via the FinOps toolkit."` + +Use the built-in `PostTeamsMessage` tool from the [Teams notification guidance](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/recipes/finops-hub/knowledge/teams-notification-guide.md). Don't call the Microsoft Graph API or the connection's `dynamicInvoke` endpoint directly because that path returns a 403 error for this connector configuration. + +### Configure Outlook + +1. Open [sre.azure.com](https://sre.azure.com), open your agent, then go to **Builder** > **Connectors**. +2. Select **Add connector** > **Outlook Tools (Office 365 Outlook)**. +3. Sign in with a Microsoft 365 account that has mailbox access. +4. Select the agent's managed identity and save. +5. Test from chat: `Send an email to with subject "SRE Agent test" and body "Outlook connector is working."` + +For more information, see [Send notifications in Azure SRE Agent](/azure/sre-agent/send-notifications). + +## GitHub Actions example + +The included GitHub Actions example passes the cluster URI as a deploy flag while leaving secret-only inputs such as `GITHUB_PAT` and `ADO_PAT` in the environment. + +## Migrating from env-var-driven deploys + +The old deploy flow used configuration inputs such as `FINOPS_HUB_CLUSTER_URI`, `FINOPS_HUB_CLUSTER_RESOURCE_ID`, `SRE_AGENT_NO_TELEMETRY`, and `connectors.secrets.env`. Those inputs are no longer supported for identity or config. + +Before: + +```bash +export FINOPS_HUB_CLUSTER_URI="https://..kusto.windows.net/hub" +export FINOPS_HUB_CLUSTER_RESOURCE_ID="/subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/" +export SRE_AGENT_NO_TELEMETRY=1 +bash bin/deploy.sh recipes/finops-hub +``` + +After: + +```bash +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + --resource-group \ + --name \ + --location \ + --cluster-uri https://..kusto.windows.net/Hub \ + [--cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/] \ + --no-telemetry +``` + +The only supported environment-variable inputs are secrets: + +- `GITHUB_PAT` +- `ADO_PAT` +- `ADO_USE_AAD` +- `ADO_USE_MI` +- `ADO_ORG` diff --git a/docs-mslearn/toolkit/sre-agent/get-started.md b/docs-mslearn/toolkit/sre-agent/get-started.md new file mode 100644 index 000000000..7aba04595 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/get-started.md @@ -0,0 +1,135 @@ +--- +title: Get started with the FinOps toolkit on Azure SRE Agent +description: Learn what to do after deploying Azure SRE Agent with the FinOps toolkit — first queries, scheduled tasks, and specialized subagents. +author: flanakin +ms.author: micflan +ms.date: 05/25/2026 +ms.topic: quickstart +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: arclares +# customer intent: As a FinOps practitioner, I want to know what to do after deploying the FinOps toolkit's Azure SRE Agent so I can start getting value from it immediately. +--- + +# Get started with the FinOps toolkit on Azure SRE Agent + +You've deployed [Azure SRE Agent with the FinOps toolkit](overview.md). Here's how to start using it after the [deployment workflow](deploy.md) finishes. + +The [deployment guide](deploy.md) covers how to deploy and configure the agent. This guide focuses on what to do next: post-deployment prompts, [scheduled tasks](scheduled-tasks.md), [specialist agents](agents.md), and customization. + +
+ +## Talk to the agent + +Azure SRE Agent responds to natural language questions about your Azure environment. The [tool catalog](tools.md) describes how Kusto tools query [FinOps hubs](../hubs/finops-hubs-overview.md) data, while Python tools call Azure APIs. + +Ask questions the same way you'd ask another FinOps or platform engineer. The [agent and skills reference](agents.md) explains how the orchestrator routes work to specialist agents that use tools, skills, and knowledge to ground recommendations. + +
+ +## Automation map + +Use this map to connect each post-deployment activity to the agent, task, tool, output, and decision pattern. The [Azure SRE Agent overview](overview.md), [agents reference](agents.md), [tools reference](tools.md), and [scheduled tasks reference](scheduled-tasks.md) document the full catalog. + +| Capability | Agent | Tasks | Tools | Output | You decide | +|------------|-------|-------|-------|--------|------------| +| Cost visibility and anomaly review | [`finops-practitioner`](agents.md#finops-practitioner) | [`Monthly`](scheduled-tasks.md#monthly), [`CostOptimization`](scheduled-tasks.md#costoptimization), and [`AlertCoverageAudit`](scheduled-tasks.md#alertcoverageaudit) | [Cost analysis](tools.md#cost-analysis-and-reporting), [anomaly detection](tools.md#anomaly-detection-and-forecasting), [forecasting](tools.md#anomaly-detection-and-forecasting), and [rate optimization](tools.md#rate-optimization) tools through [`ftk-database-query`](agents.md#ftk-database-query) where Kusto evidence is required | Cost drivers, anomaly findings, forecasts, and prioritized actions from the scheduled task outputs | Which owners investigate, which anomalies are expected, and which optimization actions should move first | +| Capacity and quota posture | [`azure-capacity-manager`](agents.md#azure-capacity-manager) | [`CapacityDailyMonitor`](scheduled-tasks.md#capacitydailymonitor), [`ComputeUtilizationTrend`](scheduled-tasks.md#computeutilizationtrend), [`CapacityWeeklySupplyReview`](scheduled-tasks.md#capacityweeklysupplyreview), and [`NonComputeQuotaAudit`](scheduled-tasks.md#noncomputequotaaudit) | [`vm-quota-usage`](tools.md#capacity-management), [`capacity-reservation-groups`](tools.md#capacity-management), [`non-compute-quotas`](tools.md#capacity-management), and [`sku-availability`](tools.md#capacity-management) | Quota pressure, capacity reservation waste, SKU restrictions, and capacity blockers from the capacity task outputs | Which quota requests, region changes, reservation changes, or workload moves need action | +| Finance and commitment decisions | [`finops-practitioner`](agents.md#finops-practitioner), consulting [`chief-financial-officer`](agents.md#chief-financial-officer) | [`BenefitRecommendationReview`](scheduled-tasks.md#benefitrecommendationreview), [`Semiannual`](scheduled-tasks.md#semiannual), and [`AIWorkloadCostAnalysis`](scheduled-tasks.md#aiworkloadcostanalysis) | [Benefit, savings, commitment, forecasting, and AI cost tools](tools.md#rate-optimization) through [`ftk-database-query`](agents.md#ftk-database-query) where Kusto evidence is required | Executive summaries, savings opportunities, forecast risk, and decision-ready commitment context from FinOps task outputs with CFO framing | Which purchases, deferrals, budget changes, or executive escalations are approved | +| Hub health and data trust | [`ftk-hubs-agent`](agents.md#ftk-hubs-agent) | [`HubsHealthCheck`](scheduled-tasks.md#hubshealthcheck) and [`MonitoringScopeValidation`](scheduled-tasks.md#monitoringscopevalidation) | [`data-freshness-check`](tools.md#data-ingestion-and-health), Azure discovery, and hub configuration tools | Hub version, connectivity, data freshness, and monitoring coverage findings from hub health task outputs | Whether reports are trustworthy, which exports need repair, and when to pause analysis that depends on stale data | + +
+ +## Getting started: first things to try + +Start with focused questions that validate your data, summarize spend, and find common optimization opportunities that map to the documented [tool catalog](tools.md) and [scheduled-task coverage](scheduled-tasks.md#task-details). + +1. Check your data pipeline and scheduled outputs: "Is my FinOps hubs data fresh, which [scheduled tasks](scheduled-tasks.md#task-details) ran recently, and what reports or Teams notifications did they produce?" +2. Review your spending and waste: "What did we spend last month by subscription, and which idle VMs across subscriptions should we investigate first?" +3. Review anomalies: "Show me this week's cost anomalies, explain the likely drivers, and recommend who should investigate each one." +4. Find savings: "What reservation recommendations do I have?" +5. Check capacity posture: "What's my quota utilization in eastus?" + +If a response doesn't have enough context, narrow the question by subscription, management group, billing scope, region, resource type, or reporting period so the agent can select focused tools and filters from the [tool catalog](tools.md). + +
+ +## Scheduled tasks run automatically + +The agent runs [19 scheduled tasks](scheduled-tasks.md) on daily, weekly, monthly, semiannual, and quarterly cadences. The [scheduled tasks reference](scheduled-tasks.md) lists daily, weekly, monthly, semiannual, and quarterly tasks for health, optimization, capacity, planning, finance, and strategy reviews. + +You don't need to trigger scheduled tasks because each task has a cron expression in its task definition, and [task details](scheduled-tasks.md#task-details) describe how reports are formatted for Microsoft Teams when notifications are configured. + +Customize the defaults before you rely on the automation in production. Review each scheduled task's `cron_expression` and prompt thresholds in the [task details](scheduled-tasks.md#task-details), then adjust schedules and thresholds to match your operating rhythm, time zone, reporting calendar, and risk tolerance. + +For example, move the month-over-month report to run after billing data settles. Lower quota headroom thresholds for regions with known capacity pressure. Raise anomaly review thresholds for subscriptions with expected seasonal spikes. The [customization options](scheduled-tasks.md#task-details) cover each task in detail. + +
+ +## Build on the basics + +The agent includes [5 specialized subagents](agents.md), and you can ask the orchestrator to route the work or mention the specialist when you know which domain you need. + +- [`finops-practitioner`](agents.md#finops-practitioner) — cost analysis, optimization, budgets, alerts, and FinOps practice guidance +- [`azure-capacity-manager`](agents.md#azure-capacity-manager) — quota, capacity reservations, SKU availability, and capacity governance +- [`chief-financial-officer`](agents.md#chief-financial-officer) — consultative financial strategy, commitment decisions, budgeting, forecasting, and executive finance narratives +- [`ftk-database-query`](agents.md#ftk-database-query) — direct Kusto queries, schema validation, pricing, recommendations, and transactions against FinOps hubs +- [`ftk-hubs-agent`](agents.md#ftk-hubs-agent) — hub health, data freshness, exports, connectivity, deployment, and upgrade troubleshooting + +Use specialist names when you want a specific lens. For example, ask the [`chief-financial-officer`](agents.md#chief-financial-officer) agent to frame a commitment decision for leadership, or ask the [`ftk-database-query`](agents.md#ftk-database-query) agent to explain the KQL behind a cost trend. + +
+ +## Learn more + +Use these pages as your next steps: + +- [Tools shipped for Azure SRE Agent in the FinOps toolkit](tools.md) +- [Specialist agents and skills](agents.md) +- [Scheduled tasks (Azure SRE Agent in the FinOps toolkit)](scheduled-tasks.md) +- [FinOps toolkit best practices](../../best-practices/library.md) + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/GetStarted) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Architecting for cloud](../../framework/optimize/architecting.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) +- [Microsoft Cost Management](/azure/cost-management-billing/costs/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Tools shipped for Azure SRE Agent in the FinOps toolkit](tools.md) +- [Specialist agents and skills](agents.md) +- [Scheduled tasks (Azure SRE Agent in the FinOps toolkit)](scheduled-tasks.md) +- [FinOps toolkit best practices](../../best-practices/library.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/knowledge.md b/docs-mslearn/toolkit/sre-agent/knowledge.md new file mode 100644 index 000000000..7578736c3 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/knowledge.md @@ -0,0 +1,172 @@ +--- +title: Manage knowledge and memory (Azure SRE Agent in the FinOps toolkit) +description: Learn how knowledge grounds the FinOps toolkit's Azure SRE Agent in your team's context and how memory keeps operational learnings available across sessions and redeployments. +author: msbrett +ms.author: brettwil +ms.date: 05/25/2026 +ms.topic: concept-article +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to manage knowledge and memory for Azure SRE Agent so that the agent can answer with my team's operational context. +--- + +# Manage knowledge and memory (Azure SRE Agent in the FinOps toolkit) + +Knowledge grounds the agent in your team's context. It helps the agent answer with your runbooks, known issues, notification patterns, and deployment details instead of relying on general guidance alone. + +Use knowledge and memory together: + +- **Knowledge** gives the agent trusted reference material, such as runbooks, architecture notes, and connector setup guidance. +- **Memory** keeps useful learnings from investigations, user instructions, and recurring operational patterns. +- **Session insights** help the agent learn from previous work, including what fixed an issue and what did not. + +
+ +## Shipped knowledge docs + +The [Azure SRE Agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent) uploads six knowledge documents during extras configuration. Five are under `recipes/finops-hub/knowledge/`; the shared FinOps Toolkit output style is uploaded from `src/templates/claude-plugin/output-styles/ftk-output-style.md`. The script uploads them as portal-visible Knowledge Sources and verifies the KnowledgeFile sources are indexed before continuing so missing or unindexed documents fail deployment instead of becoming a silent runtime issue. + +| Knowledge doc | What it provides | +|---|---| +| `chart-artifact-verification.md` | Guidance for validating generated charts, tables, and downloadable artifacts before sending reports to stakeholders. | +| `document-index.md` | Index of the shipped FinOps, capacity, and hub-operation documents the agent can use for grounding. | +| `ftk-output-style.md` | Shared report style for evidence-backed financial and capacity-management output, including FinOps capability sections, thresholds, confidence, caveats, and disclaimers. | +| `onboarding-recommendations.md` | First-run guidance for team onboarding, `/learn`, and "What should I do next?" prompts. It reminds the agent to validate Azure access, enable visualization tools, configure FinOps hub data sources, and recommend Outlook and Microsoft Teams connectors when needed. | +| `teams-notification-guide.md` | Delivery guidance for scheduled reports and notifications. It tells the agent to use the built-in `PostTeamsMessage` and `ReplyToTeamsThread` tools, format Teams messages as HTML, and avoid unsupported direct calls to Microsoft Graph or connector endpoints. | +| `known-issues-and-workarounds.md` | Operational workarounds found during scheduled task validation. It covers stale data detection, Resource Graph fallbacks, quota command issues, JMESPath escaping, memory write conflicts, Kusto query errors, and the split between financial data in Teams and operational learnings in memory. | + +> [!TIP] +> Keep these docs short and practical. The agent uses them best when each file gives clear instructions, constraints, and examples. + +
+ +## Memory system + +Azure SRE Agent uses memory to carry context forward between threads. The agent extends that with these memory layers to improve recommendations over time. + +### Session insights + +Session insights are extracted automatically after a thread goes quiet. They capture useful details from the conversation, such as: + +- Symptoms observed +- Resolution steps +- Root cause +- Pitfalls to avoid + +For FinOps operations, this helps the agent remember patterns like stale export data, commands that failed, fallbacks that worked, and report delivery issues. Session insights are most useful when users correct or rate responses after an investigation. + +### User memories + +User memories are explicit facts that you ask the agent to save. Use them for stable details the agent should remember, such as team preferences, environment constraints, or recurring operational notes. + +Use these commands in chat: + +- `#remember` to save a fact +- `#retrieve` to find saved facts +- `#forget` to delete a saved fact + +> [!IMPORTANT] +> Save operational context, not sensitive financial figures. Send costs, savings, forecasts, and grade results to Teams reports instead of persisting them in memory. + +### Proactive knowledge persistence + +The agent also maintains synthesized knowledge files under `memories/synthesizedKnowledge/`. + +- `overview.md` is loaded when a conversation starts and acts as an at-a-glance summary. +- Topic files store deeper notes, such as team context, architecture, deployment patterns, logs, auth, debugging notes, and reusable queries. + +The agent updates these files by merging new information and removing outdated details. This gives the agent a durable, compact summary of what your team has learned. + +
+ +## Knowledge sources in the portal + +You can add more knowledge in [sre.azure.com](https://sre.azure.com) from **Builder** > **Knowledge sources**. + +Knowledge sources can include: + +- **Files**: Upload runbooks, architecture docs, escalation guides, API docs, and team procedures. +- **Web pages**: Connect stable documentation pages that the agent should cite. +- **Repositories**: Connect source repositories when code, configuration, or markdown docs should ground agent responses. + +Use uploaded files for stable content. Use connected sources for content that changes often, such as a wiki, repository, or live documentation site. + +The template upload path uses the same SRE Agent data-plane contract as the portal file upload flow: `PUT /api/v2/extendedAgent/connectors/{name}` with `type: KnowledgeItem` and `dataConnectorType: KnowledgeFile`. Validate the shipped knowledge with `bin/verify-agent.sh`, the `bin/apply-extras.sh` output, or **Builder** > **Knowledge sources**. + +
+ +## Knowledge across redeployments + +Knowledge from the template persists across redeployments through the extras configuration step. + +When you run `bin/deploy.sh`, the template provisions Azure resources and then runs `bin/apply-extras.sh`. The extras script uploads everything under `recipes/finops-hub/knowledge/`, uploads the shared output style, and waits for the expected KnowledgeFile sources to appear as indexed: + +```bash +for file in "$REPO_ROOT"/src/templates/sre-agent/recipes/finops-hub/knowledge/*.md; do + PUT "$SRE_AGENT_ENDPOINT/api/v2/extendedAgent/connectors/$(basename "$file")" +done +PUT "$SRE_AGENT_ENDPOINT/api/v2/extendedAgent/connectors/ftk-output-style.md" +curl -H "Authorization: Bearer $TOKEN" "$SRE_AGENT_ENDPOINT/api/v2/extendedAgent/connectors" +``` + +This keeps the shipped onboarding, artifact verification, Teams notification, document index, output-style, and known-issues guidance available after the agent is redeployed. If you add your own files to `recipes/finops-hub/knowledge/`, they are uploaded by the same step. + +
+ +## Best practices + +Use knowledge for information the agent should trust and cite. + +- Upload runbooks, architecture guides, escalation paths, known issues, connector setup notes, and service-specific troubleshooting guides. +- Name files by task or topic, such as `aks-scale-out-runbook.md`, `finops-hub-kusto-queries.md`, or `teams-report-delivery.md`. +- Keep one purpose per file so the agent can retrieve the right source quickly. +- Include owner, date, scope, prerequisites, and last review notes in operational docs. +- Avoid secrets, credentials, personal data, and raw financial figures. +- Review knowledge quarterly to remove stale workarounds, retire old commands, and add new operational learnings. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +
+ +## Vote on or suggest ideas + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Workload management](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Microsoft Teams](https://learn.microsoft.com/microsoftteams/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) +- [FinOps toolkit Power BI reports](../power-bi/reports.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/kusto-tools.md b/docs-mslearn/toolkit/sre-agent/kusto-tools.md new file mode 100644 index 000000000..7c2ca749b --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/kusto-tools.md @@ -0,0 +1,497 @@ +--- +title: Kusto tools +description: Review the FinOps hub Kusto tools the FinOps toolkit ships for Azure SRE Agent and learn when to use each tool for cost, commitment discount, anomaly, forecast, AI, and price analysis. +author: msbrett +ms.author: brettwil +ms.date: 06/01/2026 +ms.topic: reference +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand each Kusto tool the FinOps toolkit ships for Azure SRE Agent so that I can choose the right query for cost and optimization analysis. +--- + +# Kusto tools + +The FinOps toolkit deployment configures Azure SRE Agent with 37 Kusto tools that query your FinOps hub Azure Data Explorer database through the `finops-hub-kusto` connector. Each tool is configured as a `KustoTool` and generated from the FinOps hub query catalog to ground agent responses in cost, price, recommendation, transaction, KPI, and AI usage data. Query source lives at [`src/queries/catalog`](../../../src/queries/catalog/). The SRE Agent recipe rejects explicit Kusto YAML files so the query catalog stays the only source for Kusto tool definitions. + +This reference also calls out related optimization tools that appear in scheduled-task requirements when they affect the same analysis path. Those tools aren't Kusto tools unless explicitly marked as `KustoTool`. + +> [!IMPORTANT] +> Kusto tools require the hosted Azure SRE Agent to reach the Azure Data Explorer query endpoint. If the FinOps hub cluster has `publicNetworkAccess` set to `Disabled`, the toolkit still deploys the agent, assigns `AllDatabasesViewer`, and creates the connector, but the connector is expected to remain unhealthy. Review the [Azure SRE Agent VNET known limitations](https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations), then decide whether to enable public query access for the cluster. + +Use this reference when you want to understand which tool fits a prompt, scheduled task, or custom agent workflow. For a summary of all the agent's tools, see [Tools shipped for Azure SRE Agent in the FinOps toolkit](tools.md). + +
+ +## Source validation + +The template generates every FinOps hub Kusto tool from the 37 `.kql` files in [`src/queries/catalog`](../../../src/queries/catalog/). The recipe keeps 13 `PythonTool` YAML files in [`src/templates/sre-agent/recipes/finops-hub/config/tools`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/). Build validation fails if an explicit Kusto YAML file is added, if a catalog query doesn't generate exactly one Kusto tool, if a KPI-linked query isn't generated as a Kusto tool, or if a KPI-linked query isn't requested by any scheduled task. + +| Source category | Count | Evidence | +|-----------------|------:|----------| +| FinOps hub Kusto tools | 37 | Generated from [`src/queries/catalog/*.kql`](../../../src/queries/catalog/) by [`build-extras.py`](../../../src/templates/sre-agent/bin/build-extras.py). The catalog is indexed in [`src/queries/INDEX.md`](../../../src/queries/INDEX.md), and KPI-linked tools are mapped in [`src/queries/KPI.md`](../../../src/queries/KPI.md). | +| Related Python tools | 13 | [`benefit-recommendations`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/benefit-recommendations.yaml), [`capacity-reservation-groups`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/capacity-reservation-groups.yaml), [`data-freshness-check`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/data-freshness-check.yaml), [`db-service-quotas`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/db-service-quotas.yaml), [`deploy-anomaly-alert`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-anomaly-alert.yaml), [`deploy-budget`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-budget.yaml), [`deploy-bulk-anomaly-alerts`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-anomaly-alerts.yaml), [`deploy-bulk-budgets`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-budgets.yaml), [`non-compute-quotas`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/non-compute-quotas.yaml), [`resource-graph-query`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/resource-graph-query.yaml), [`sku-availability`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/sku-availability.yaml), [`suppress-advisor-recommendations`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/suppress-advisor-recommendations.yaml), and [`vm-quota-usage`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/vm-quota-usage.yaml) | + +
+ +## Cost analysis + +Use cost analysis tools to review cost and usage from different reporting angles, including time, service, resource group, region, billing hierarchy, and resource type. + +### costs-enriched-base + +Source query: [`costs-enriched-base.kql`](../../../src/queries/catalog/costs-enriched-base.kql). + +Queries a guarded, enriched row-level cost and usage sample with tags, resource details, savings fields, commitment fields, and FinOps toolkit metadata. + +Use it only for narrow detail drill-downs after an aggregate result identifies the scope to inspect. The tool rejects windows greater than one day to avoid Azure Data Explorer result truncation. For full-month, fiscal-period, scheduled report, dashboard export, allocation, showback, chargeback, tag-coverage, or broad custom analysis, use aggregate tools first, such as `monthly-cost-trend`, `cost-by-financial-hierarchy`, `top-services-by-cost`, `top-resource-groups-by-cost`, or `top-resource-types-by-cost`. + +Example prompt: "Show me enriched cost details for yesterday's top resource group, including tags and resource group." + +Sample output shape: One row per cost record with fields such as `ChargePeriodStart`, `SubAccountName`, `ResourceId`, `ResourceName`, `ResourceType`, `ServiceName`, `x_ResourceGroupName`, `BilledCost`, `EffectiveCost`, `ContractedCost`, `ListCost`, `PricingQuantity`, `Tags`, `CommitmentDiscountType`, `CommitmentDiscountStatus`, `x_TotalSavings`, and `x_FreeReason`. + +### monthly-cost-trend + +Source query: [`monthly-cost-trend.kql`](../../../src/queries/catalog/monthly-cost-trend.kql). + +Queries monthly billed and effective cost totals to show cost trends over time. + +Use it when you need a month-by-month view for budget reviews, executive summaries, or recurring FinOps reporting. It helps identify whether spend is increasing, decreasing, or stabilizing. + +Example prompt: "Show the monthly cost trend for the last six months." + +Sample output shape: One row per month with `x_ChargeMonth`, `BilledCost`, and `EffectiveCost`. + +### monthly-cost-change-percentage + +Source query: [`monthly-cost-change-percentage.kql`](../../../src/queries/catalog/monthly-cost-change-percentage.kql). + +Queries month-over-month billed and effective cost changes as percentages. + +Use it when stakeholders ask how much costs changed between months or when you need to find volatility quickly. It works well for variance reviews and cost spike triage. + +Example prompt: "Which months had the largest percentage increase in effective cost?" + +Sample output shape: One row per month with `ChargePeriodStart`, `BilledCost`, `EffectiveCost`, `PreviousBilledCost`, `PreviousEffectiveCost`, billed-cost change percentage, and effective-cost change percentage. + +### quarterly-cost-by-resource-group + +Source query: [`quarterly-cost-by-resource-group.kql`](../../../src/queries/catalog/quarterly-cost-by-resource-group.kql). + +Queries quarterly cost by resource group, subscription, and month for a reporting window. + +Use it when preparing quarterly business reviews or resource-group-level accountability reports. It helps teams connect quarterly cost movement to resource ownership and subscription context. + +Example prompt: "Break down quarterly costs by resource group for the last quarter." + +Sample output shape: One row per subscription, resource group, and month with `SubAccountName`, `x_ResourceGroupName`, `x_ChargeMonth`, and `EffectiveCost`. + +### cost-by-region-trend + +Source query: [`cost-by-region-trend.kql`](../../../src/queries/catalog/cost-by-region-trend.kql). + +Queries effective cost trends by Azure region. + +Use it when you need to understand regional cost distribution, investigate regional growth, or evaluate whether workloads are shifting between regions. It can also support capacity and placement discussions. + +Example prompt: "Show cost trends by Azure region over the last three months." + +Sample output shape: One row per region with `RegionName` and `EffectiveCost`. + +### cost-by-financial-hierarchy + +Source query: [`cost-by-financial-hierarchy.kql`](../../../src/queries/catalog/cost-by-financial-hierarchy.kql). + +Queries costs organized by billing profile, invoice section, team, product, application, environment, and other financial hierarchy fields. + +Use it when you need a finance-aligned view for allocation, showback, chargeback, or executive reporting. It helps translate resource-level usage into business ownership. + +Example prompt: "Summarize costs by billing profile, team, product, and application." + +Sample output shape: One row per financial hierarchy combination with `x_BillingProfileName`, `x_InvoiceSectionName`, `x_Team`, `x_Product`, `x_Application`, `x_Environment`, `EffectiveCost`, and `PercentOfTotal`. + +### top-services-by-cost + +Source query: [`top-services-by-cost.kql`](../../../src/queries/catalog/top-services-by-cost.kql). + +Queries the Azure services with the highest effective cost. + +Use it when you need to prioritize service-level optimization or identify which services drive overall spend. Start here for broad cost reviews before drilling into resources or resource groups. + +Example prompt: "What are the top 10 Azure services by cost this month?" + +Sample output shape: One row per service with `ServiceName` and `EffectiveCost`. + +### top-resource-types-by-cost + +Source query: [`top-resource-types-by-cost.kql`](../../../src/queries/catalog/top-resource-types-by-cost.kql). + +Queries the resource types with the highest effective cost and resource counts. + +Use it when you need to understand which resource categories are driving spend, such as virtual machines, disks, databases, or networking resources. It helps identify optimization themes across many resources. + +Example prompt: "List the top resource types by effective cost and resource count." + +Sample output shape: One row per resource type with `ResourceType`, `ResourceCount`, and `EffectiveCost`. + +### top-resource-groups-by-cost + +Source query: [`top-resource-groups-by-cost.kql`](../../../src/queries/catalog/top-resource-groups-by-cost.kql). + +Queries the resource groups with the highest effective cost. + +Use it when you need an owner-friendly cost view or want to focus optimization work on the most expensive resource groups. It is useful for team accountability and workload-level reviews. + +Example prompt: "Which resource groups had the highest costs in the last 30 days?" + +Sample output shape: One row per subscription and resource group with `SubAccountName`, `x_ResourceGroupName`, and `EffectiveCost`. + +
+ +## Commitment discounts + +Use commitment discount tools to review reservation and savings plan utilization, recommendations, realized savings, and purchase transactions. + +### commitment-discount-utilization + +Source query: [`commitment-discount-utilization.kql`](../../../src/queries/catalog/commitment-discount-utilization.kql). + +Queries consumed core hours by commitment discount type, including reservation, savings plan, and on-demand usage. + +Use it when you need to understand how well commitments are being used and whether uncovered on-demand usage remains. It helps compare capacity planning, usage patterns, and commitment coverage. + +Example prompt: "Show reservation and savings plan utilization for the last month." + +Sample output shape: One row per commitment category with `CommitmentDiscountType`, `TotalConsumedCoreHours`, and `PercentOfTotal`. Empty commitment types are reported as `On Demand`. + +### reservation-recommendation-breakdown + +Source query: [`reservation-recommendation-breakdown.kql`](../../../src/queries/catalog/reservation-recommendation-breakdown.kql). + +Queries detailed reservation recommendations, including savings, break-even dates, normalized sizes, scope, and term details. + +Use it when evaluating whether to buy reservations or when preparing a recommendation package for finance and workload owners. It helps compare potential savings with commitment risk. + +Example prompt: "Break down reservation purchase recommendations by service, term, and expected savings." + +Sample output shape: One row per reservation recommendation with fields such as `RegionId`, normalized size or group details, `x_SkuMeterId`, `x_SkuTerm`, expected before and after effective cost, `x_BreakEvenMonths`, and `x_BreakEvenDate`. + +### benefit-recommendations + +Source query: [`benefit-recommendations.kql`](../../../src/queries/catalog/benefit-recommendations.kql). + +Gets Microsoft Cost Management benefit recommendations for savings plans and reserved instances at a billing scope. + +This is a related optimization tool, but it's a `PythonTool`, not a Kusto tool. Use it when the agent needs current Cost Management recommendation API results by billing scope, lookback period, and term. Use `reservation-recommendation-breakdown` when you need FinOps hub recommendation data from `Recommendations()`. + +Example prompt: "Get current savings plan and reservation benefit recommendations for this billing profile." + +Sample output shape: A JSON object with `billing_scope`, `lookback_period`, `term`, `count`, and `recommendations`. Each recommendation includes fields such as `type`, `savings`, `cost`, `total_cost`, `cost_without_benefit`, `term`, `break_even`, `id`, and `name`. If the request can't run, the object includes an `error` field. + +### savings-summary-report + +Source query: [`savings-summary-report.kql`](../../../src/queries/catalog/savings-summary-report.kql). + +Queries list cost, effective cost, negotiated savings, commitment savings, total savings, and savings rate. + +Use it when you need a summary of savings from discounts and commitments compared with pay-as-you-go pricing. It works well for executive reporting and rate optimization reviews. + +Example prompt: "Summarize total savings from negotiated rates and commitment discounts this month." + +Sample output shape: One row per billing currency with `BillingCurrency`, `ListCost`, `ContractedCost`, `EffectiveCost`, `x_NegotiatedDiscountSavings`, `x_CommitmentDiscountSavings`, `x_TotalSavings`, and `x_EffectiveSavingsRate`. + +### top-commitment-transactions + +Source query: [`top-commitment-transactions.kql`](../../../src/queries/catalog/top-commitment-transactions.kql). + +Queries the largest non-usage commitment discount purchase transactions, including reservations and savings plans. + +Use it when investigating major commitment-related charges, purchase timing, or renewal activity. It helps separate commitment purchases from normal usage costs. + +Example prompt: "Show the largest reservation and savings plan transactions this quarter." + +Sample output shape: One row per commitment purchase transaction with `ChargePeriodStart`, `ChargeCategory`, `BilledCost`, `BillingCurrency`, `CommitmentDiscountName`, `CommitmentDiscountNameUnique`, `CommitmentDiscountType`, `SubAccountName`, `SubAccountNameUnique`, `ResourceNameUnique`, and `x_ResourceGroupNameUnique`. + +
+ +## Anomaly detection + +Use anomaly detection tools to identify unusual cost patterns that need investigation. + +### cost-anomaly-detection + +Source query: [`cost-anomaly-detection.kql`](../../../src/queries/catalog/cost-anomaly-detection.kql). + +Queries cost time series and detects unusual spikes or drops across a configurable history window. + +Use it when you need to triage unexpected spend changes, monitor recurring cost health, or explain why costs moved outside the normal pattern. Pair it with cost drill-down tools to find the affected service, region, or resource group. + +Example prompt: "Detect cost anomalies over the last 90 days and explain the biggest spikes." + +Sample output shape: One time-series row with `ChargePeriodStart`, `CostSeries`, and `anomalies`, where the series arrays represent the analyzed interval and the anomaly markers. + +
+ +## Forecasting + +Use forecasting tools to project future cost based on historical patterns. + +### cost-forecasting-model + +Source query: [`cost-forecasting-model.kql`](../../../src/queries/catalog/cost-forecasting-model.kql). + +Queries historical cost trends and projects future effective cost. + +Use it when preparing budgets, rolling forecasts, or expected run-rate discussions. It is most helpful when recent historical usage is representative of near-term demand. + +Example prompt: "Forecast effective cost for the next three months based on recent trends." + +Sample output shape: One time-series row with `ChargePeriodStart`, `EffectiveCostSeries`, and `forecast`, where the forecast array extends the historical cost series for the requested future periods. + +
+ +## AI/ML costs + +Use AI/ML cost tools to analyze Azure OpenAI and related AI service costs, token usage, model efficiency, and application ownership. + +### ai-cost-by-application + +Source query: [`ai-cost-by-application.kql`](../../../src/queries/catalog/ai-cost-by-application.kql). + +Queries AI and machine learning costs by application, team, and environment tags. + +Use it when you need showback, chargeback, or ownership analysis for AI workloads. It helps map AI spend to the applications and teams consuming it. + +Example prompt: "Break down AI costs by application and environment for this month." + +Sample output shape: One row per application, team, environment, and cost center with fields such as `Application`, `Team`, `Environment`, `CostCenter`, `EffectiveCost`, `TokenCount`, and `CostPer1KTokens`. + +### ai-daily-trend + +Source query: [`ai-daily-trend.kql`](../../../src/queries/catalog/ai-daily-trend.kql). + +Queries daily AI and machine learning cost trends. + +Use it when you need to monitor day-to-day AI spend, spot sudden changes, or prepare daily operating reports. It can also provide context before investigating token or model-level drivers. + +Example prompt: "Show the daily AI cost trend for the last 30 days." + +Sample output shape: One row per day with `ChargePeriodStart`, daily AI cost, daily token count, and cost per 1,000 tokens. + +### ai-model-cost-comparison + +Source query: [`ai-model-cost-comparison.kql`](../../../src/queries/catalog/ai-model-cost-comparison.kql). + +Queries AI model costs so the agent can compare costs across models. + +Use it when evaluating model efficiency, unit economics, or opportunities to shift workloads to lower-cost models. It is useful for comparing model choices before changing application behavior. + +Example prompt: "Compare costs across AI models and identify the most expensive models per 1,000 tokens." + +Sample output shape: One row per model with `Model`, `TokenCount`, `EffectiveCost`, `ListCost`, `CostPer1KTokens`, `ListPer1KTokens`, and `DiscountPercent`. + +### ai-token-usage-breakdown + +Source query: [`ai-token-usage-breakdown.kql`](../../../src/queries/catalog/ai-token-usage-breakdown.kql). + +Queries AI token usage by model, model version, and input or output direction. + +Use it when token consumption is the suspected cost driver or when you need to separate prompt and completion usage. It helps connect AI cost changes to usage behavior. + +Example prompt: "Break down token usage by model and input versus output tokens for the last week." + +Sample output shape: One row per model and token direction with `Model`, `Direction`, `TokenCount`, `EffectiveCost`, `UnitCostPerToken`, and `CostPer1KTokens`. + +
+ +## FinOps KPI tools + +FinOps KPI tools are generated from the query catalog and map to query links in [`src/queries/KPI.md`](../../../src/queries/KPI.md). Scheduled tasks request these tools through `ftk-database-query` for monthly, semiannual, health, anomaly, capacity, storage, monitoring, AI, and benefit-review scorecards. + +### percentage-unallocated-costs + +Source query: [`percentage-unallocated-costs.kql`](../../../src/queries/catalog/percentage-unallocated-costs.kql). + +Measures the share of effective cost that lacks required allocation evidence for the reporting window. + +### percentage-untagged-costs + +Source query: [`percentage-untagged-costs.kql`](../../../src/queries/catalog/percentage-untagged-costs.kql). + +Measures the share of effective cost on resources that have no tags. + +### tagging-policy-compliance + +Source query: [`tagging-policy-compliance.kql`](../../../src/queries/catalog/tagging-policy-compliance.kql). + +Measures cost-weighted compliance with required tag keys. + +### allocation-accuracy-index + +Source query: [`allocation-accuracy-index.kql`](../../../src/queries/catalog/allocation-accuracy-index.kql). + +Measures directly attributed cost as a share of total effective cost. + +### anomaly-detection-rate + +Source query: [`anomaly-detection-rate.kql`](../../../src/queries/catalog/anomaly-detection-rate.kql). + +Measures the share of effective spend in anomaly-flagged daily buckets. + +### anomaly-variance-total + +Source query: [`anomaly-variance-total.kql`](../../../src/queries/catalog/anomaly-variance-total.kql). + +Quantifies signed and absolute unpredicted spend variance for detected anomaly events. + +### cost-visibility-delay + +Source query: [`cost-visibility-delay.kql`](../../../src/queries/catalog/cost-visibility-delay.kql). + +Measures cost data visibility delay from charge period end to Hub ingestion. + +### data-update-frequency + +Source query: [`data-update-frequency.kql`](../../../src/queries/catalog/data-update-frequency.kql). + +Measures FinOps hub ingestion update cadence from distinct ingestion timestamps. + +### commitment-utilization-score + +Source query: [`commitment-utilization-score.kql`](../../../src/queries/catalog/commitment-utilization-score.kql). + +Computes commitment utilization amount, potential, and score by commitment and currency. + +### commitment-discount-waste + +Source query: [`commitment-discount-waste.kql`](../../../src/queries/catalog/commitment-discount-waste.kql). + +Measures unused commitment value as a share of total commitment cost. + +### compute-spend-commitment-coverage + +Source query: [`compute-spend-commitment-coverage.kql`](../../../src/queries/catalog/compute-spend-commitment-coverage.kql). + +Measures compute spend covered by commitment discounts. + +### compute-cost-per-core + +Source query: [`compute-cost-per-core.kql`](../../../src/queries/catalog/compute-cost-per-core.kql). + +Computes hourly and effective average compute cost per consumed vCPU core hour. + +### cost-optimization-index + +Source query: [`cost-optimization-index.kql`](../../../src/queries/catalog/cost-optimization-index.kql). + +Computes the Hub-wide cost optimization index from current recommendations and cost context. + +### cost-per-gb-stored + +Source query: [`cost-per-gb-stored.kql`](../../../src/queries/catalog/cost-per-gb-stored.kql). + +Calculates storage cost per normalized GB-month. + +### macc-consumption-vs-commitment + +Source query: [`macc-consumption-vs-commitment.kql`](../../../src/queries/catalog/macc-consumption-vs-commitment.kql). + +Measures Microsoft Azure Consumption Commitment drawdown by billing profile and month. + +### storage-tier-distribution + +Source query: [`storage-tier-distribution.kql`](../../../src/queries/catalog/storage-tier-distribution.kql). + +Summarizes storage cost and GB-month distribution by access-tier bucket. + +
+ +## Usage optimization + +Use Usage Optimization tools to identify idle, orphaned, or wasteful resources before starting cleanup work. + +### idle-resource-sweep + +Source status: No `idle-resource-sweep.yaml` file appears in the source inventory for [`src/templates/sre-agent/recipes/finops-hub/config/tools`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/). + +Reviews idle or orphaned resource candidates for Usage Optimization. + +This Gate-named tool is a required analysis path, but the current template doesn't include an `idle-resource-sweep` Kusto tool YAML file. Until a dedicated tool is added, ground idle-resource reviews with `top-resource-types-by-cost`, `top-resource-groups-by-cost`, and narrow `costs-enriched-base` drill-downs. Then correlate candidates with Azure Resource Graph or Azure Advisor data through the relevant Python or built-in Azure tools before recommending cleanup. + +Example prompt: "Find likely idle or orphaned resources and group them by resource type, subscription, and estimated monthly cost." + +Sample output shape: A candidate list with fields such as `SubAccountName`, `ResourceId`, `ResourceName`, `ResourceType`, `x_ResourceGroupName`, `RegionName`, `ServiceName`, `EffectiveCost`, `LastUsageSignal`, `IdleReason`, `RecommendedAction`, and `Confidence`. When using the current template, this shape is assembled from existing cost aggregates, enriched cost rows, and external Azure inventory or recommendation signals rather than returned by a single shipped Kusto tool. + +
+ +## Price analysis + +Use price analysis tools to compare prices, savings, and non-commitment transactions that affect total cost. + +### service-price-benchmarking + +Source query: [`service-price-benchmarking.kql`](../../../src/queries/catalog/service-price-benchmarking.kql). + +Queries service price benchmarks, including list cost, contracted cost, effective cost, negotiated savings, commitment savings, and total savings. + +Use it when you need to compare prices across services or understand how negotiated and commitment discounts affect effective rates. It helps identify services with the largest rate optimization opportunity. + +Example prompt: "Benchmark service prices and show where negotiated or commitment savings are highest." + +Sample output shape: One row per service with `ServiceName`, `ListCost`, `ContractedCost`, `EffectiveCost`, negotiated savings, commitment discount savings, total savings, and savings percentages. + +### top-other-transactions + +Source query: [`top-other-transactions.kql`](../../../src/queries/catalog/top-other-transactions.kql). + +Queries the largest non-usage and non-commitment transactions, such as Marketplace or miscellaneous charges. + +Use it when costs don't reconcile to normal usage or commitment purchases. It helps isolate large one-time or nonstandard transactions that can distort monthly cost trends. + +Example prompt: "Show the largest non-usage and non-commitment transactions this month." + +Sample output shape: One row per non-usage, non-commitment transaction with `ChargePeriodStart`, `ChargeCategory`, `BilledCost`, `BillingCurrency`, `SubAccountName`, `x_InvoiceSectionName`, `PricingCategory`, `PricingQuantity`, `PricingUnit`, `ProviderName`, and `PublisherName`. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/KustoTools) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Anomaly management](../../framework/understand/anomalies.md) +- [Cost allocation](../../framework/understand/allocation.md) +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Rate optimization](../../framework/optimize/rates.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Microsoft Cost Management](/azure/cost-management-billing/costs/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Tools shipped for Azure SRE Agent in the FinOps toolkit](tools.md) +- [Python tools](python-tools.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/overview.md b/docs-mslearn/toolkit/sre-agent/overview.md new file mode 100644 index 000000000..97a739e9e --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/overview.md @@ -0,0 +1,151 @@ +--- +title: Azure SRE Agent in the FinOps toolkit +description: Learn how the FinOps toolkit deploys Azure SRE Agent with FinOps and capacity management automation on top of FinOps hubs. +author: msbrett +ms.author: brettwil +ms.date: 06/02/2026 +ms.topic: concept-article +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand what the FinOps toolkit's Azure SRE Agent deployment provides so that I can automate cost, capacity, and operations workflows. +--- + +# Azure SRE Agent in the FinOps toolkit + +The FinOps toolkit ships a Deploy to Azure template and a local Azure CLI + Bicep wrapper that deploy [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) and configure it for FinOps and capacity management workflows on top of [FinOps hubs](../hubs/finops-hubs-overview.md). The deployment includes specialist subagents, FOCUS-aligned Kusto and Python tools, scheduled tasks, and grounded knowledge so the agent can investigate cost changes, monitor quota and capacity signals, prepare executive summaries, and deliver scheduled updates. The deployment focuses on three core design principles: + +- **Automate the rhythm**
_Run daily, weekly, monthly, and quarterly FinOps workflows without waiting for manual report requests._ +- **Ground every answer**
_Use FinOps hub data, FOCUS-aligned Kusto tools, and Azure platform context to keep recommendations tied to evidence._ +- **Act with experts**
_Route work to specialized FinOps, finance, capacity, database, and hubs agents instead of a single generic assistant._ + +The FinOps toolkit deployment helps teams move from dashboards and alerts to an operating model where the agent investigates cost changes, monitors quota and capacity signals, prepares executive summaries, and delivers scheduled updates through Azure SRE Agent. + + +> [!NOTE] +> Estimated cost: Varies by Azure SRE Agent preview pricing, telemetry ingestion, and your existing FinOps hub footprint. +> +> The template provisions an Azure SRE Agent with a system-assigned managed identity, Log Analytics workspace, and Application Insights resource. Costs depend on the selected region, Azure SRE Agent pricing, Log Analytics and Application Insights ingestion and retention, and the Azure Data Explorer footprint you connect to. The managed identity and RBAC assignments don't typically add direct cost. + + + +> [!IMPORTANT] +> The FinOps toolkit deploys all SRE Agent resources even when the connected Azure Data Explorer cluster uses private endpoints. If the cluster has `publicNetworkAccess` set to `Disabled`, hosted Azure SRE Agent can't run direct KQL queries against the cluster. The deployment warns and links to the [Azure SRE Agent VNET known limitations](https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations) so the customer can decide whether to enable public query access. + + +
+ + +> [!div class="nextstepaction"] +> [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) + + +
+ +## What you get + +The FinOps toolkit's Azure SRE Agent template deploys and configures these resources and Azure SRE Agent objects: + +| Component | Count | Description | +|-----------|-------|-------------| +| Azure SRE Agent | 1 | `Microsoft.App/agents` resource in autonomous mode | +| Model provider | 1 | Azure OpenAI provider-level routing (`MicrosoftFoundry` ARM value, `Automatic` model routing) | +| Managed identities | 1-2 | System-assigned managed identity for the agent; portal deployments also create a user-assigned identity for the deployment script | +| Log Analytics | 1 | Workspace for agent telemetry | +| Application Insights | 1 | Linked to Log Analytics for monitoring | +| Target resource group RBAC | 3-4 per target group | Reader, Monitoring Reader, Log Analytics Reader, and Contributor when `accessLevel` is `High` | +| Azure Data Explorer role | Optional | `AllDatabasesViewer` when Azure Data Explorer parameters are provided | +| Custom agents | 5 | `azure-capacity-manager`, `chief-financial-officer`, `finops-practitioner`, `ftk-database-query`, and `ftk-hubs-agent` | +| Skills | 3 | `azure-capacity-management`, `azure-cost-management`, and `finops-toolkit` | +| Tools | 50 | Kusto, capacity, and Hub infrastructure tools | +| Tool overrides | 9 | Enables SRE Agent Log Query and Visualization tools | +| Scheduled tasks | 19 | Daily, weekly, monthly, semiannual, and quarterly recurring workflows | +| Connectors | 1 | Optional Kusto connector to your FinOps hub Azure Data Explorer cluster | +| Knowledge docs | 6 | Five recipe knowledge docs plus the FinOps Toolkit output style | +| Notification connectors | 0 by default | Outlook and Teams can be added after deployment in the Azure SRE Agent portal | + +
+ +## Architecture overview + +The FinOps toolkit deployment is copied from the Microsoft SRE Agent starter-lab pattern and updated to use the toolkit's packaged Deploy to Azure flow or Azure CLI + Bicep directly. It doesn't use `azd`. The deployment runs in this order: + +1. The Azure portal or `bin/deploy.sh` starts a subscription-scoped ARM deployment. +2. The deployment creates the agent resource group when needed. +3. Bicep creates monitoring resources and Azure SRE Agent. +4. Bicep assigns target resource group RBAC and can optionally assign `AllDatabasesViewer` on your FinOps hub Azure Data Explorer cluster. +5. A deployment script in the portal path, or `bin/apply-extras.sh` in the local CLI path, creates the Kusto connector and applies skills, custom agents, tools, knowledge, and scheduled tasks through the supported SRE Agent ARM and data-plane surfaces. +6. You optionally add Outlook and Teams connectors in [sre.azure.com](https://sre.azure.com) when you want scheduled reports delivered outside the agent chat. + +The result is a single Azure SRE Agent with a FinOps Framework-aligned operating model layered on top. The `finops-practitioner` agent owns the FinOps operating rhythm and scheduled analysis, has no direct tools, and delegates evidence collection to specialists. The `ftk-database-query` agent owns all Kusto and FOCUS evidence collection. The `azure-capacity-manager` agent maps Azure capacity signals into Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization support, Governance, Policy & Risk, and Automation, Tools & Services. The `chief-financial-officer` agent provides finance and leadership consultation, and the `ftk-hubs-agent` monitors FinOps hub health and data freshness. + +The template defaults the parent SRE Agent to Azure OpenAI provider-level routing (`MicrosoftFoundry` in ARM) with automatic model selection inside that provider. Individual custom agents don't pin model names; they inherit the parent agent provider and use SRE Agent's automatic model routing. + +
+ +## When to use the agent + +FinOps teams often have the data they need but not the time to run every investigation on schedule. The agent gives the team an automated operating rhythm that can review cost changes, check commitment coverage, monitor capacity headroom, and summarize action items before the next stakeholder meeting. + +Use the agent when you want to: + +- Review FinOps hub data through conversational and scheduled agent workflows. +- Monitor cost anomalies, budget variance, and forecast drift. +- Track quota usage, capacity reservation utilization, region access, and zone readiness. +- Prepare daily, weekly, monthly, and quarterly cost and capacity summaries. +- Route questions to specialized agents with FinOps, finance, capacity, database, and hubs context. + +
+ +## Get started + +Deploy the agent when you have a FinOps hub with an Azure Data Explorer cluster and an Azure subscription where you can deploy Azure SRE Agent resources. After deployment, open the agent in [sre.azure.com](https://sre.azure.com), verify the subagents, skills, tools, and scheduled tasks, and add notification connectors if you want reports sent to Teams or Outlook. + + +> [!div class="nextstepaction"] +> [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) + + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Anomaly management](../../framework/understand/anomalies.md) +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Architecting for cloud](../../framework/optimize/architecting.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure Monitor](/azure/azure-monitor/) + +Related solutions: + +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) +- [Azure SRE Agent template reference (FinOps toolkit)](template.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/python-tools.md b/docs-mslearn/toolkit/sre-agent/python-tools.md new file mode 100644 index 000000000..7def2af39 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/python-tools.md @@ -0,0 +1,514 @@ +--- +title: Python tools +description: Review the Python tools the FinOps toolkit ships for Azure SRE Agent for Azure quota, capacity, budgets, anomaly alerts, Resource Graph, FinOps hub health, and Advisor suppressions. +author: msbrett +ms.author: brettwil +ms.date: 05/25/2026 +ms.topic: reference +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand which Python tools the FinOps toolkit ships for Azure SRE Agent so that I can use the right Azure API-backed tool for capacity, cost governance, and operations work. +--- + +# Python tools + +The FinOps toolkit deployment configures Azure SRE Agent with 13 Python tools that call Azure APIs through the agent's managed identity. These tools complement the Kusto tools by checking Azure platform state, deploying Cost Management controls, and automating governance tasks that aren't stored in FinOps hub data. + +Use Python tools when the agent needs live Azure Resource Manager, Resource Graph, Cost Management, Azure Data Explorer, or Advisor data instead of historical cost and usage data from the FinOps hub. + +> [!NOTE] +> The agent managed identity must have enough permission at the target scope to read or update the resources each tool touches. Read tools typically need Reader permissions. Deployment and suppression tools need permissions to create or update the target Cost Management or Advisor resources. + +## Source inventory + +The following table maps the 13 Python tools documented on this page to their source YAML files. Use this inventory to audit this reference page against the template source. It doesn't assert that no other YAML files exist under `src/templates/sre-agent/recipes/finops-hub/config/tools/`. + +| Tool | Source file | +|------|-------------| +| `vm-quota-usage` | `src/templates/sre-agent/recipes/finops-hub/config/tools/vm-quota-usage.yaml` | +| `capacity-reservation-groups` | `src/templates/sre-agent/recipes/finops-hub/config/tools/capacity-reservation-groups.yaml` | +| `sku-availability` | `src/templates/sre-agent/recipes/finops-hub/config/tools/sku-availability.yaml` | +| `non-compute-quotas` | `src/templates/sre-agent/recipes/finops-hub/config/tools/non-compute-quotas.yaml` | +| `deploy-budget` | `src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-budget.yaml` | +| `deploy-bulk-budgets` | `src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-budgets.yaml` | +| `deploy-anomaly-alert` | `src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-anomaly-alert.yaml` | +| `deploy-bulk-anomaly-alerts` | `src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-anomaly-alerts.yaml` | +| `resource-graph-query` | `src/templates/sre-agent/recipes/finops-hub/config/tools/resource-graph-query.yaml` | +| `benefit-recommendations` | `src/templates/sre-agent/recipes/finops-hub/config/tools/benefit-recommendations.yaml` | +| `data-freshness-check` | `src/templates/sre-agent/recipes/finops-hub/config/tools/data-freshness-check.yaml` | +| `db-service-quotas` | `src/templates/sre-agent/recipes/finops-hub/config/tools/db-service-quotas.yaml` | +| `suppress-advisor-recommendations` | `src/templates/sre-agent/recipes/finops-hub/config/tools/suppress-advisor-recommendations.yaml` | + +
+ +## Capacity and quota + +Use capacity and quota tools to check VM family quota, capacity reservation group utilization, SKU restrictions, and non-compute service limits before deployment or during recurring capacity reviews. + +### `vm-quota-usage` + +- **Azure API:** Azure Resource Manager Compute usages API: `Microsoft.Compute/locations/usages`. +- **When to use it:** Use this tool to query VM family quota usage across one or more regions in a subscription. It calculates utilization percentages and flags VM families above warning or critical thresholds. +- **Example prompt:** "Check VM quota usage for subscription `` in eastus and westus2, and call out any families above 80% utilization." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "locations": ["eastus", "westus2"], + "quotas": [ + { + "location": "eastus", + "name": "Standard DSv5 Family vCPUs", + "current": 80, + "limit": 100, + "utilization_pct": 80, + "at_risk_80": false, + "at_risk_95": false + } + ], + "warning_count": 0, + "critical_count": 0, + "suppressed_error_count": 0, + "suppressed_errors": [], + "errors": [] + } + ``` + +### `capacity-reservation-groups` + +- **Azure API:** Azure Resource Manager Compute capacity reservation group API: `Microsoft.Compute/capacityReservationGroups`, including capacity reservation instance view and associated virtual machines. +- **When to use it:** Use this tool to list capacity reservation groups in a subscription and compare reserved capacity with allocated virtual machines. It helps find unused capacity, overallocated groups, and zone-specific capacity reservation waste. +- **Example prompt:** "List capacity reservation groups in subscription `` and identify groups with unused reserved capacity." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "capacity_reservation_groups": [ + { + "name": "crg-prod-eastus", + "id": "/subscriptions//resourceGroups//providers/Microsoft.Compute/capacityReservationGroups/crg-prod-eastus", + "resource_group": "", + "location": "eastus", + "zones": ["1"], + "zone": "1", + "reserved_count": 10, + "allocated_count": 8, + "utilization_pct": 80, + "waste": true, + "waste_count": 2, + "overallocated": false, + "capacity_reservations": ["crg-prod-eastus/Standard_D8s_v5"], + "virtual_machines_allocated": ["/subscriptions//resourceGroups//providers/Microsoft.Compute/virtualMachines/vm01"], + "virtual_machines_associated": [] + } + ], + "errors": [] + } + ``` + +### `sku-availability` + +- **Azure API:** Azure Resource Manager SKU APIs for Azure Compute and Azure Data Explorer: `Microsoft.Compute/skus` and `Microsoft.Kusto/locations/skus`. +- **When to use it:** Use this tool to verify whether a VM or Azure Data Explorer SKU is available in a region and whether zone or subscription restrictions could block deployment. +- **Example prompt:** "Check whether Standard_D8s_v5 is available in eastus2, including zone support and any restriction reasons." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "location": "eastus2", + "sku_filter": "Standard_D8s_v5", + "resource_provider": "compute", + "service": "Azure Compute", + "source_endpoint": "https://management.azure.com/subscriptions//providers/Microsoft.Compute/skus?api-version=2021-07-01&$filter=location eq 'eastus2'", + "skus": [ + { + "name": "Standard_D8s_v5", + "family": "standardDSv5Family", + "size": "D8s_v5", + "zones_available": ["1", "2", "3"], + "restrictions": [] + } + ], + "restriction_summary": { + "total_skus": 1, + "restricted_skus": 0, + "restriction_count": 0, + "reason_codes": {} + } + } + ``` + +### `non-compute-quotas` + +- **Azure API:** Azure Resource Manager provider usage APIs for supported services, with Azure Resource Graph fallbacks for services that don't expose a direct usage API. +- **When to use it:** Use this tool to review storage, networking, and PaaS quota usage that can block growth even when compute quota is healthy. It marks whether each limit came from an API-reported quota or an estimated fallback. +- **Example prompt:** "Audit non-compute quota usage for subscription `` in eastus and summarize storage or network limits above 80% utilization." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "services": [ + { + "service_name": "Storage", + "resource_type": "Microsoft.Storage/locations/usages", + "quota_name": "StorageAccounts", + "current_count": 100, + "limit": 250, + "utilization_pct": 40, + "at_risk": false, + "count_source": "arm_provider_usages_api", + "limit_source": "api_reported_limit", + "limit_type": "api_reported", + "source_endpoint": "https://management.azure.com/subscriptions//providers/Microsoft.Storage/locations/eastus/usages?api-version=2023-05-01", + "location": "eastus", + "scope": "regional" + } + ], + "quotas": [ + { + "subscription_id": "", + "service_name": "Storage", + "service": "Storage", + "resource_type": "Microsoft.Storage/locations/usages", + "quota_name": "StorageAccounts", + "name": "StorageAccounts", + "location": "eastus", + "scope": "regional", + "current_count": 100, + "current": 100, + "limit": 250, + "utilization_pct": 40, + "at_risk": false, + "at_risk_80": false, + "at_risk_95": false, + "count_source": "arm_provider_usages_api", + "limit_source": "api_reported_limit", + "limit_type": "api_reported", + "source_endpoint": "https://management.azure.com/subscriptions//providers/Microsoft.Storage/locations/eastus/usages?api-version=2023-05-01" + } + ], + "at_risk_count": 0, + "api_reported_limit_count": 1, + "estimated_limit_count": 0, + "suppressed_count": 0, + "errors": [] + } + ``` + +
+ +## Budget and alert deployment + +Use budget and alert deployment tools to create Cost Management controls for a single subscription or apply the same control across enabled subscriptions in a management group. + +### `deploy-budget` + +- **Azure API:** Azure Resource Manager Consumption budgets API: `Microsoft.Consumption/budgets`. +- **When to use it:** Use this tool to create or update a subscription-level Cost Management budget with notification thresholds and contact emails. +- **Example prompt:** "Create a monthly budget named SubscriptionBudget for subscription `` with an amount of 50000 and notify finops@example.com." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "budget_name": "SubscriptionBudget", + "amount": 50000, + "time_grain": "Monthly", + "contact_emails": ["finops@example.com"], + "status_code": 201, + "budget": { + "id": "/subscriptions//providers/Microsoft.Consumption/budgets/SubscriptionBudget", + "name": "SubscriptionBudget", + "type": "Microsoft.Consumption/budgets" + }, + "status": "created" + } + ``` + +### `deploy-bulk-budgets` + +- **Azure API:** Azure Resource Graph to discover enabled subscriptions, then Azure Resource Manager Consumption budgets API: `Microsoft.Consumption/budgets`. +- **When to use it:** Use this tool to deploy the same Cost Management budget across all enabled subscriptions under a management group. +- **Example prompt:** "Deploy a monthly 50000 budget named SubscriptionBudget to every enabled subscription in management group `` and notify finops@example.com." +- **Sample output shape:** + + ```json + { + "management_group": "", + "budget_name": "SubscriptionBudget", + "amount": 50000, + "contact_emails": ["finops@example.com"], + "subscription_count": 2, + "created_or_updated": 2, + "failed": 0, + "deployments": [ + { + "subscription_id": "", + "subscription_name": "Production", + "budget_name": "SubscriptionBudget", + "status": "created", + "status_code": 201, + "error": null + } + ] + } + ``` + +### `deploy-anomaly-alert` + +- **Azure API:** Azure Resource Manager Cost Management scheduled actions API: `Microsoft.CostManagement/scheduledActions`. +- **When to use it:** Use this tool to create or update a daily Cost Management anomaly alert scheduled action for one subscription. +- **Example prompt:** "Create a cost anomaly alert for subscription `` that sends daily anomaly notifications to finops@example.com." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "scheduled_action_name": "cost-anomaly-alert", + "email_recipients": ["finops@example.com"], + "status_code": 201, + "anomaly_alert": { + "id": "/subscriptions//providers/Microsoft.CostManagement/scheduledActions/cost-anomaly-alert", + "name": "cost-anomaly-alert", + "kind": "InsightAlert" + }, + "status": "created" + } + ``` + +### `deploy-bulk-anomaly-alerts` + +- **Azure API:** Azure Resource Graph to discover enabled subscriptions, then Azure Resource Manager Cost Management scheduled actions API: `Microsoft.CostManagement/scheduledActions`. +- **When to use it:** Use this tool to deploy the same cost anomaly alert configuration across enabled subscriptions under a management group. +- **Example prompt:** "Deploy cost anomaly alerts to all enabled subscriptions in management group `` and send notifications to finops@example.com." +- **Sample output shape:** + + ```json + { + "management_group": "", + "email_recipients": ["finops@example.com"], + "subscription_count": 2, + "created_or_updated": 2, + "failed": 0, + "deployments": [ + { + "subscription_id": "", + "subscription_name": "Production", + "scheduled_action_name": "cost-anomaly-alert", + "status": "updated", + "status_code": 200, + "error": null + } + ] + } + ``` + +
+ +## Resource analysis + +Use resource analysis tools when the agent needs live Azure inventory, configuration, or commitment discount recommendation data outside the FinOps hub. + +### `resource-graph-query` + +- **Azure API:** Azure Resource Graph resources API: `Microsoft.ResourceGraph/resources`. +- **When to use it:** Use this tool to run Azure Resource Graph KQL across one or more subscriptions for inventory, configuration drift, governance checks, and subscription-scale troubleshooting. +- **Example prompt:** "Run a Resource Graph query across my subscriptions to list unattached managed disks by subscription, resource group, size, and age." +- **Sample output shape:** + + ```json + { + "rows": [ + { + "subscriptionId": "", + "resourceGroup": "", + "name": "disk01", + "type": "microsoft.compute/disks" + } + ], + "count": 1, + "errors": [], + "total_records": 1, + "result_truncated": false, + "subscriptions": [""] + } + ``` + +### `benefit-recommendations` + +- **Azure API:** Azure Resource Manager Cost Management benefit recommendations API: `Microsoft.CostManagement/benefitRecommendations`. +- **When to use it:** Use this tool to retrieve reservation and savings plan recommendations at a billing scope, including recommendation type, term, savings, cost, and break-even details. +- **Example prompt:** "Get three-year benefit recommendations for billing account scope `` using a Last30Days lookback and summarize the largest savings opportunities." +- **Sample output shape:** + + ```json + { + "billing_scope": "", + "lookback_period": "Last30Days", + "term": "P3Y", + "recommendations": [ + { + "type": "SP", + "savings": 12000, + "cost": 30000, + "total_cost": 30000, + "cost_without_benefit": 42000, + "term": "P3Y", + "break_even": "P8M", + "id": "/providers/Microsoft.Billing/billingAccounts//providers/Microsoft.CostManagement/benefitRecommendations/", + "name": "" + } + ], + "count": 1 + } + ``` + +
+ +## Hub management + +Use hub management tools to verify whether FinOps hub data is current enough for reliable scheduled reports and agent answers. Use `data-freshness-check` as the source of truth for hub freshness before relying on stale memory, raw KQL rollups, or ingestion timestamp checks. + +### `data-freshness-check` + +- **Azure API:** Azure Data Explorer REST query API (`/v1/rest/query` or `/v2/rest/query`) on the configured FinOps hub cluster. +- **When to use it:** Use this tool to check data freshness for FinOps hub functions such as `Costs()`, `Prices()`, `Recommendations()`, and `Transactions()`. It reports latest data dates, stale functions, and functions without data. Treat `Costs()` as the authoritative freshness signal. If `Costs()` is 3 days old or newer, don't report the hub as stale even if older memory, raw KQL, or ingestion timestamp checks disagree. +- **Example prompt:** "Check data freshness for the FinOps hub at `` in the hub database and tell me which functions are stale." +- **Sample output shape:** + + ```json + { + "cluster_uri": "https://.kusto.windows.net", + "database": "hub", + "functions": [ + { + "function_name": "Costs()", + "source_dataset": "Costs", + "expected_export_dataset": "focuscost", + "row_count": 100000, + "latest_data_date": "2026-05-01T00:00:00Z", + "latest_ingestion_time": null, + "staleness_days": 1, + "is_stale": false, + "has_data": true, + "schema_status": "ok", + "schema_column_count": 120, + "required_for_hub_health": true, + "diagnostic_code": "OK", + "diagnostic_message": null + } + ], + "total_functions": 4, + "stale_count": 0, + "empty_count": 0, + "error_count": 0, + "hub_data_stale": false, + "attention_required": false, + "status": "healthy", + "diagnostics": [], + "freshest_function": {}, + "stalest_function": {}, + "authoritative_freshness_signal": { + "function_name": "Costs()", + "latest_data_date": "2026-05-01T00:00:00Z", + "staleness_days": 1, + "is_stale": false, + "has_data": true, + "row_count": 100000 + }, + "source_of_truth": { + "tool": "data-freshness-check", + "method": "direct_adx_rest_query", + "endpoint": "/v2/rest/query", + "authoritative_function": "Costs()", + "freshness_threshold_days": 3, + "supersedes": ["stale memory conclusions", "raw KQL freshness rollups", "Kusto ingestion timestamp checks"] + } + } + ``` + +
+ +## Advisor + +Use Advisor tools when the agent needs to apply governance decisions to Azure Advisor recommendations. + +### `suppress-advisor-recommendations` + +- **Azure API:** Azure Resource Graph to find Advisor recommendations, then Azure Resource Manager Advisor suppressions API: `Microsoft.Advisor/recommendations/suppressions`. +- **When to use it:** Use this tool to suppress selected Azure Advisor recommendation types across subscriptions under a management group for a limited time to live. +- **Example prompt:** "Suppress the default Advisor recommendation types for management group `` for 30 days and report how many recommendations were suppressed." +- **Sample output shape:** + + ```json + { + "management_group_id": "", + "days": 30, + "ttl": "P30D", + "recommendation_type_ids": ["89515250-1243-43d1-b4e7-f9437cedffd8"], + "found_count": 10, + "suppressed_count": 10, + "failed_count": 0, + "suppressions": [ + { + "subscription_id": "", + "recommendation_id": "/subscriptions//providers/Microsoft.Advisor/recommendations/", + "recommendation_type_id": "89515250-1243-43d1-b4e7-f9437cedffd8", + "suppression_id": "", + "ttl": "P30D", + "status": "suppressed", + "status_code": 201, + "error": null + } + ] + } + ``` + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/PythonTools) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Anomaly management](../../framework/understand/anomalies.md) +- [Budgeting](../../framework/quantify/budgeting.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Resource Graph](/azure/governance/resource-graph/) +- [Microsoft Cost Management](/azure/cost-management-billing/costs/) +- [Azure Advisor](/azure/advisor/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Tools shipped for Azure SRE Agent in the FinOps toolkit](tools.md) +- [Kusto tools](kusto-tools.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md new file mode 100644 index 000000000..7862eaa6c --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md @@ -0,0 +1,277 @@ +--- +title: Scheduled tasks (Azure SRE Agent in the FinOps toolkit) +description: Learn how the FinOps toolkit's scheduled tasks automate daily, weekly, monthly, and quarterly FinOps operating rhythms on Azure SRE Agent. +author: msbrett +ms.author: brettwil +ms.date: 05/25/2026 +ms.topic: concept-article +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand the scheduled tasks the FinOps toolkit deploys to Azure SRE Agent so that I can plan recurring cost, capacity, and finance reviews. +--- + +# Scheduled tasks (Azure SRE Agent in the FinOps toolkit) + +The FinOps toolkit ships scheduled tasks that run recurring FinOps operating-rhythm workflows on Azure SRE Agent. They turn common reviews into autonomous checks that gather data, route work to the right specialist agent, generate charts where the data supports them, and post completed reports to Microsoft Teams when a Teams notification connector is configured. + +The template deploys 19 scheduled tasks from `src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/`. These tasks cover daily health checks, weekly optimization and capacity reviews, monthly planning and finance reports, semiannual year-over-year analysis, and quarterly strategy. + +
+ +## Daily tasks + +Daily tasks run every morning to validate FinOps hub health and monitor Azure capacity signals that feed Planning & Estimating, Architecting & Workload Placement, Usage Optimization, Governance, Policy & Risk, and Automation, Tools & Services. They keep cost and capacity surprises visible before each business day. + +| Task | Agent | Schedule | Description | +|------|-------|----------|-------------| +| `HubsHealthCheck` | `ftk-hubs-agent` | Daily at 6:00 AM
`0 6 * * *` | FinOps hub version and data freshness validation | +| `CapacityDailyMonitor` | `azure-capacity-manager` | Daily at 6:30 AM
`30 6 * * *` | Daily capacity health check — quota usage, CRG utilization, zone capacity | + +
+ +## Weekly tasks + +Weekly tasks summarize cost optimization, Azure capacity evidence, and benefit recommendation activity for the previous week. They give the team a recurring rhythm for deeper analysis without manual report requests. + +| Task | Agent | Schedule | Description | +|------|-------|----------|-------------| +| `ComputeUtilizationTrend` | `azure-capacity-manager` | Weekly on Monday at 7:00 AM
`0 7 * * 1` | Weekly VM quota utilization trend review across subscriptions and regions | +| `CostOptimization` | `finops-practitioner` | Weekly on Monday at 8:00 AM
`0 8 * * 1` | Comprehensive cost optimization report with orphaned resources, rightsizing, and commitment analysis | +| `CapacityWeeklySupplyReview` | `azure-capacity-manager` | Weekly on Monday at 8:00 AM
`0 8 * * 1` | Weekly capacity evidence review — quota headroom, CRG cost optimization, SKU availability, benefit recommendations | +| `NonComputeQuotaAudit` | `azure-capacity-manager` | Weekly on Tuesday at 7:00 AM
`0 7 * * 2` | Weekly audit of storage, network, and non-compute quota usage at risk | +| `DbQuotaAudit` | `azure-capacity-manager` | Weekly on Wednesday at 7:00 AM
`0 7 * * 3` | Weekly audit of database quota and region or zone access risks | +| `SkuAvailabilityAudit` | `azure-capacity-manager` | Weekly on Wednesday at 7:30 AM
`30 7 * * 3` | Weekly audit of regional SKU availability and restrictions that could block deployments | +| `MonitoringScopeValidation` | `ftk-hubs-agent` | Weekly on Thursday at 9:00 AM
`0 9 * * 4` | Weekly validation that FinOps hub monitoring covers all active subscriptions | +| `BenefitRecommendationReview` | `finops-practitioner` | Weekly on Friday at 8:00 AM
`0 8 * * 5` | Weekly review of reservation and savings plan recommendations, with CFO consultation for decision framing | + +
+ +## Monthly tasks + +Monthly tasks run after billing data finalizes to produce year-to-date analysis, capacity planning forecasts, AI workload cost reviews, and audit reports for budget and alert coverage. Use them to anchor monthly business reviews. + +| Task | Agent | Schedule | Description | +|------|-------|----------|-------------| +| `StoragePaasGrowthForecast` | `azure-capacity-manager` | Monthly on the 1st at 8:00 AM
`0 8 1 * *` | Monthly storage and PaaS quota growth forecast across active subscriptions | +| `AdvisorSuppressionReview` | `finops-practitioner` | Monthly on the 1st at 9:00 AM
`0 9 1 * *` | Monthly review of active Advisor recommendation suppressions for stale or expired decisions | +| `CapacityMonthlyPlanning` | `azure-capacity-manager` | Monthly on the 1st at 9:00 AM
`0 9 1 * *` | Monthly capacity planning cycle — demand forecast, capacity request pipeline, governance review | +| `Monthly` | `finops-practitioner` | Monthly on the 5th at 5:15 PM
`15 17 5 * *` | Autonomous month-over-month cost analysis with FinOps hub tools | +| `AIWorkloadCostAnalysis` | `finops-practitioner` | Monthly on the 1st at 10:00 AM
`0 10 1 * *` | Monthly AI workload cost analysis — token economics, model efficiency, and cost allocation for Azure OpenAI | +| `Semiannual` | `finops-practitioner` | January 5 and July 5 at 9:00 AM
`0 9 5 1,7 *` | Semiannual year-over-year finance analysis with forecast and CFO consultation | +| `BudgetCoverageAudit` | `finops-practitioner` | Monthly on the 15th at 8:00 AM
`0 8 15 * *` | Monthly audit of subscription budget coverage and missing budget controls | +| `AlertCoverageAudit` | `finops-practitioner` | Monthly on the 16th at 8:00 AM
`0 8 16 * *` | Monthly audit of cost anomaly alert coverage across active subscriptions | + +
+ +## Quarterly tasks + +Quarterly tasks run at the start of each calendar quarter to summarize capacity-related FinOps capability maturity, commitment alignment, and architecture evolution. Use them to feed leadership reviews and the next quarter's planning cycle. + +| Task | Agent | Schedule | Description | +|------|-------|----------|-------------| +| `CapacityQuarterlyStrategy` | `azure-capacity-manager` | Quarterly on January 1, April 1, July 1, and October 1 at 9:00 AM
`0 9 1 1,4,7,10 *` | Quarterly capacity strategy review — FinOps capability maturity, commitment alignment, architecture evolution | + +
+ +## Task details + +Each scheduled task is defined in YAML under `src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/`. You can customize the schedule by changing the `cron_expression` in the task definition before deployment. You can also tune the task prompt to change thresholds, scope, report sections, and recommended actions for your operating model. + +### HubsHealthCheck + +- **Data sources queried:** GitHub release metadata for the latest FinOps hub version, Azure resource discovery for deployed hub resources, and the `data-freshness-check` tool for the latest `Costs()` update date. The task also validates hub connectivity before trusting downstream scheduled reports. +- **Output format and content:** A daily health summary that reports deployed version status, latest available version, data refresh status, connectivity findings, and any blocking hub issues. The report is formatted for Teams when notifications are configured. +- **Recommended actions generated:** Upgrade FinOps hubs when the deployed version is behind, investigate stale exports or ingestion failures, restore connectivity, and delay cost analysis that depends on stale hub data. +- **Customization options:** Change the daily cron from `0 6 * * *`, adjust how many days of data freshness lag is acceptable, add organization-specific hub resource filters, and add required escalation steps for stale data or version drift. + +### CapacityDailyMonitor + +- **Data sources queried:** VM quota usage through `vm-quota-usage`, capacity reservation group data through `capacity-reservation-groups`, non-compute quota context through `non-compute-quotas`, Azure CLI discovery for AKS and regional resources, and hub freshness checks where cost context is needed. +- **Output format and content:** A daily capacity health report with quota pressure, capacity reservation utilization, AKS node pool readiness, alert status, and urgent capacity blockers mapped to FinOps capability impact. +- **Recommended actions generated:** File quota increases, redistribute workload demand, adjust capacity reservation groups, investigate underutilized reservations, validate AKS node pool capacity, and escalate imminent deployment blockers. +- **Customization options:** Change the daily cron from `30 6 * * *`, tune warning and critical quota-utilization thresholds, define target capacity reservation utilization bands, scope monitored subscriptions or regions, and add workload-specific AKS node pool checks. + +### Monthly + +- **Data sources queried:** `finops-practitioner` delegates FinOps hub Kusto evidence to `ftk-database-query`, including `data-freshness-check`, `monthly-cost-trend`, `monthly-cost-change-percentage`, `top-services-by-cost`, `top-resource-groups-by-cost`, `cost-by-region-trend`, `cost-anomaly-detection`, `savings-summary-report`, `commitment-discount-utilization`, `cost-forecasting-model`, `reservation-recommendation-breakdown`, `top-resource-types-by-cost`, `service-price-benchmarking`, and `top-other-transactions`. Capacity-risk evidence is delegated to `azure-capacity-manager`. +- **Output format and content:** A daily month-over-month cost analysis with executive summary, service and resource group drivers, anomalies, forecasts, savings and commitment signals, regional distribution, tag coverage, marketplace or other purchases, charts where data supports them, and action items. +- **Recommended actions generated:** Investigate anomalies, correct cost allocation gaps, prioritize cost drivers, act on savings opportunities, review commitment utilization, address forecast risk, and validate tags or financial hierarchy gaps. +- **Customization options:** Change the monthly cron from `15 17 5 * *`, adjust anomaly and variance thresholds, change the comparison window, scope the analysis to selected subscriptions or billing entities, and add or remove Kusto sections from the report. + +### ComputeUtilizationTrend + +- **Data sources queried:** VM quota utilization through `vm-quota-usage`, Azure Resource Graph subscription and VM inventory, and prior-period utilization signals from the scheduled analysis prompt. +- **Output format and content:** A weekly trend report that lists quota families, subscriptions, regions, current utilization, week-over-week movement, and quota lines approaching defined risk thresholds. +- **Recommended actions generated:** Request quota increases for growing usage, move demand to lower-pressure regions or quota families, validate planned deployments against headroom, and close stale quota allocations that are no longer needed. +- **Customization options:** Change the weekly cron from `0 7 * * 1`, tune warning and critical utilization thresholds, choose the trend lookback window, filter to production subscriptions or priority regions, and add business-unit routing for quota owners. + +### CostOptimization + +- **Data sources queried:** Azure Resource Graph for orphaned and idle resources, Advisor cost recommendations, commitment and benefit recommendation tools, Azure CLI resource validation, optional VM utilization data, and FinOps hub data when available. +- **Output format and content:** A weekly cost optimization report with executive summary, quick wins, orphaned resources, rightsizing candidates, commitment discount status, effort and risk categories, estimated savings, and charts for major opportunities. +- **Recommended actions generated:** Delete or remediate orphaned resources, resize underutilized workloads, buy or adjust reservations and savings plans, validate Advisor recommendations, and assign owners for high-value optimization actions. +- **Customization options:** Change the weekly cron from `0 8 * * 1`, tune savings and utilization thresholds, exclude protected resource groups or tags, change effort and risk categories, and modify recommendation ranking or minimum savings filters. + +### CapacityWeeklySupplyReview + +- **Data sources queried:** VM quota usage, `capacity-reservation-groups`, `non-compute-quotas`, `sku-availability`, benefit and reservation recommendations, Azure CLI regional discovery, and commitment-related cost signals. +- **Output format and content:** A weekly capacity evidence review covering quota headroom, capacity reservation waste, SKU and zone availability, region access, non-compute constraints, and capacity-to-rate optimization opportunities mapped to FinOps capabilities. +- **Recommended actions generated:** Increase quota, rebalance capacity reservations, release or resize underused CRGs, validate alternate SKUs or regions, align capacity reservations with reservation or savings opportunities, and escalate SKU restrictions. +- **Customization options:** Change the weekly cron from `0 8 * * 1`, tune quota and CRG utilization thresholds, set approved regions and SKU allowlists, scope the review to critical workloads, and adjust how benefit recommendations are ranked. + +### NonComputeQuotaAudit + +- **Data sources queried:** `non-compute-quotas` for storage, network, and other service quota usage; subscription scope from Azure discovery; and service-specific quota values returned by Azure APIs when available. +- **Output format and content:** A weekly audit that separates reported and estimated limits, lists services and regions near limits, highlights quotas with missing limit telemetry, and summarizes risk by subscription. +- **Recommended actions generated:** Request quota increases, reduce or redistribute usage, add missing quota monitoring, validate estimated limits with service owners, and escalate high-risk storage or network quotas before deployments fail. +- **Customization options:** Change the weekly cron from `0 7 * * 2`, tune at-risk utilization thresholds, choose monitored services, scope subscriptions or regions, and define how to handle quotas that report current usage but not limits. + +### DbQuotaAudit + +- **Data sources queried:** `db-service-quotas` for SQL DB, SQL Managed Instance, Cosmos DB, PostgreSQL Flexible Server, and MySQL Flexible Server quota, region, and availability-zone access signals. +- **Output format and content:** A weekly database quota report that separates service limits, regional access, zone access, estimated or missing evidence, and workload impact by subscription and region. +- **Recommended actions generated:** Request database quota increases, validate region or zone access, adjust database placement plans, add owner routing for capacity risks, and escalate blockers before deployment or scale events. +- **Customization options:** Change the weekly cron from `0 7 * * 3`, choose database services or regions to inspect, tune risk thresholds, and define owner metadata requirements. + +### SkuAvailabilityAudit + +- **Data sources queried:** `sku-availability` for regional SKU availability and restrictions, Azure subscription and region discovery, and workload-provided SKU filters when present. +- **Output format and content:** A weekly availability report that lists requested SKUs by region, availability status, restrictions, deployment blockers, and recommended fallback regions or SKU families. +- **Recommended actions generated:** Change deployment region or SKU, request regional access where possible, update landing-zone allowed SKU lists, revise deployment plans, and escalate blockers that affect production capacity. +- **Customization options:** Change the weekly cron from `30 7 * * 3`, tune the SKU and region scope, add required workload SKUs, define preferred fallback regions, and change the severity threshold for restricted or unavailable SKUs. + +### MonitoringScopeValidation + +- **Data sources queried:** Azure Resource Graph for active subscription inventory, FinOps hub `data-freshness-check`, hub database and cluster configuration, and subscription coverage comparisons between Azure and hub data. +- **Output format and content:** A weekly monitoring coverage report showing active subscriptions, subscriptions with fresh hub data, subscriptions missing from monitoring, stale coverage, and evidence for scope gaps. +- **Recommended actions generated:** Add missing subscriptions to exports or hub monitoring, fix stale export configuration, validate hub permissions, update subscription onboarding processes, and pause unsupported financial analysis for missing scopes. +- **Customization options:** Change the weekly cron from `0 9 * * 4`, tune data freshness thresholds, filter excluded or retired subscriptions, change the required coverage percentage, and add owner routing for missing subscription remediation. + +### BenefitRecommendationReview + +- **Data sources queried:** `benefit-recommendations` for reservation and savings plan opportunities, billing-scope context, plus Kusto-backed commitment utilization and savings evidence delegated to `ftk-database-query`. +- **Output format and content:** A weekly executive report with total savings opportunity, recommendation categories, term and scope assumptions, purchase candidates, risk notes, and decision-ready next steps. +- **Recommended actions generated:** Approve high-confidence purchases, reject or defer recommendations that conflict with demand forecasts, adjust commitment coverage, request validation from workload owners, and document finance approval decisions. +- **Customization options:** Change the weekly cron from `0 8 * * 5`, tune minimum savings and confidence thresholds, set preferred commitment terms, scope recommendations by billing profile or subscription, and add finance approval rules. + +### StoragePaasGrowthForecast + +- **Data sources queried:** `non-compute-quotas` for current storage and PaaS quota usage, Azure Resource Graph for service inventory, subscription scope from Azure discovery, and historical growth signals derived from current usage where available. +- **Output format and content:** A monthly forecast that identifies storage and PaaS services approaching limits, current usage and limit signals, projected growth risk, and subscriptions needing quota planning. +- **Recommended actions generated:** Request quota increases, archive or clean up unused capacity, move demand to less constrained subscriptions or regions, add service-specific monitoring, and validate growth assumptions with workload owners. +- **Customization options:** Change the monthly cron from `0 8 1 * *`, tune forecast horizon and risk thresholds, select included PaaS services, define acceptable headroom, and add workload-specific growth assumptions. + +### AdvisorSuppressionReview + +- **Data sources queried:** Azure Resource Graph for Advisor suppression resources and metadata, subscription inventory, suppression age and expiration fields, and related recommendation context where available. +- **Output format and content:** A monthly suppression inventory with active, stale, expired, and undocumented suppressions; affected recommendations; age; owner information; and remediation status. +- **Recommended actions generated:** Remove expired suppressions, renew justified suppressions with documentation, restore important Advisor recommendations, assign owners for stale decisions, and create follow-up work for risky suppressed savings. +- **Customization options:** Change the monthly cron from `0 9 1 * *`, tune stale-age and expiration thresholds, scope suppression review by subscription or owner tag, add required justification fields, and define exception approval rules. + +### CapacityMonthlyPlanning + +- **Data sources queried:** `azure-capacity-manager` uses `vm-quota-usage`, `capacity-reservation-groups`, `resource-graph-query`, and benefit recommendations directly, then asks `ftk-database-query` for Kusto-backed forecast, commitment utilization, and savings evidence. +- **Output format and content:** A monthly capacity planning packet with demand forecast, capacity request pipeline, quota and CRG allocation review, cost impact, governance findings, and planning decisions. +- **Recommended actions generated:** Submit quota and capacity requests, adjust capacity reservations, align capacity requests with forecasted demand, rebalance allocation across subscriptions, and update governance controls for capacity planning. +- **Customization options:** Change the monthly cron from `0 9 1 * *`, tune forecast horizon and growth thresholds, choose capacity planning regions and SKUs, set acceptable CRG utilization bands, and add capacity request workflow fields. + +### Semiannual + +- **Data sources queried:** `finops-practitioner` delegates FinOps hub Kusto evidence to `ftk-database-query`, including `monthly-cost-trend`, `quarterly-cost-by-resource-group`, `cost-anomaly-detection`, `savings-summary-report`, `commitment-discount-utilization`, `cost-by-financial-hierarchy`, `cost-forecasting-model`, `reservation-recommendation-breakdown`, `cost-by-region-trend`, `top-resource-types-by-cost`, `service-price-benchmarking`, `monthly-cost-change-percentage`, `top-commitment-transactions`, and `top-other-transactions`. +- **Output format and content:** A semiannual year-over-year finance report with spend trend, forward forecast, quarterly trends, service portfolio analysis, anomaly narrative, savings realization, commitment performance, hierarchy views, and executive actions. +- **Recommended actions generated:** Reforecast budgets, address variance drivers, approve savings actions, adjust commitments, escalate financial hierarchy gaps, and document finance risks before fiscal reviews. +- **Customization options:** Change the semiannual cron from `0 9 5 1,7 *`, align fiscal calendar assumptions, tune variance and forecast thresholds, scope the report by billing or management group hierarchy, and add finance-specific KPI sections. + +### AIWorkloadCostAnalysis + +- **Data sources queried:** `finops-practitioner` delegates AI cost Kusto evidence to `ftk-database-query`, including `ai-token-usage-breakdown`, `ai-model-cost-comparison`, `ai-daily-trend`, and `ai-cost-by-application`, plus cost and capacity context from Azure discovery and `azure-capacity-manager` when needed. +- **Output format and content:** A monthly AI cost report covering token economics, model mix, application allocation, daily trends, input and output ratios, month-over-month AI cost movement, optimization opportunities, and charts. +- **Recommended actions generated:** Substitute models where quality allows, optimize prompts, rightsize environments, improve application cost allocation, assess commitment coverage, and prioritize workloads with high token cost growth. +- **Customization options:** Change the monthly cron from `0 10 1 * *`, tune token-cost and growth thresholds, choose model families or applications in scope, add quality or latency guardrails for model substitution, and change chargeback allocation rules. + +### BudgetCoverageAudit + +- **Data sources queried:** Azure Resource Graph for subscription inventory and budget resources, subscription metadata, and budget configuration details such as amount, period, contact, and scope. +- **Output format and content:** A monthly budget coverage report with active subscriptions, configured budgets, missing or incomplete budgets, coverage gaps, and budget-control remediation items. +- **Recommended actions generated:** Create missing budgets, update budget contacts and thresholds, align budget scopes to subscription ownership, retire budgets for inactive subscriptions, and escalate subscriptions without financial guardrails. +- **Customization options:** Change the monthly cron from `0 8 15 * *`, define required budget coverage thresholds, exclude sandbox or retired subscriptions, set minimum alert percentages, and add owner or cost-center routing. + +### AlertCoverageAudit + +- **Data sources queried:** Azure Resource Graph for active subscriptions and anomaly alert resources, cost alert configuration, and subscription metadata for ownership and scope validation. +- **Output format and content:** A monthly alert coverage report that lists subscriptions with and without cost anomaly alerts, stale or incomplete alert configuration, missing contacts, and remediation priority. +- **Recommended actions generated:** Create missing anomaly alerts, repair alert scopes or contacts, standardize alert thresholds, remove obsolete alerts, and assign owners for unmonitored high-spend subscriptions. +- **Customization options:** Change the monthly cron from `0 8 16 * *`, tune required alert coverage and severity thresholds, exclude low-risk subscriptions, set required notification contacts, and customize anomaly alert policy standards. + +### CapacityQuarterlyStrategy + +- **Data sources queried:** VM quota usage, reservation and savings recommendations, Kusto-backed commitment and savings evidence delegated to `ftk-database-query`, Azure Resource Graph, Azure CLI architecture signals, and non-compute quota context. +- **Output format and content:** A quarterly strategy report covering FinOps capability maturity, commitment alignment, architecture evolution, region and quota strategy, governance health, risk register, and executive recommendations. +- **Recommended actions generated:** Mature capacity governance, align reservations and savings plans with demand, update regional architecture, address non-compute quota constraints, revise capacity request processes, and set quarterly capacity objectives. +- **Customization options:** Change the quarterly cron from `0 9 1 1,4,7,10 *`, tune maturity scoring and risk thresholds, set strategic regions and SKU families, align with quarterly business review dates, and add organization-specific governance criteria. + +
+ +## Notification behavior + +Scheduled tasks deliver final reports through Azure SRE Agent notification connectors. When you configure the Microsoft Teams connector, each task posts only the completed summary to the connected Teams channel. The task prompts explicitly avoid posting intermediate findings so the channel stays focused on ready-to-use results. + +The prompts also split what goes to Teams and what goes to the agent knowledge base: + +- **Teams** receives financial, status, capacity, and strategy results. This includes charts, executive summaries, action items, savings opportunities, quota risks, and capacity recommendations. +- **Knowledge base** receives operational learnings only. Examples include tool errors, query patterns, API workarounds, pipeline failure modes, and troubleshooting steps that worked. +- **Financial detail stays out of memory.** Prompts tell the agents not to save customer financial data, cost amounts, savings numbers, token costs, or similar financial details to the knowledge base. + +For connector setup, see [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md#configure-notifications). + +
+ +## Roadmap + +The deployed template includes the 19 scheduled tasks listed on this page. The repository also includes the detailed current task catalog in [CATALOG.md](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/CATALOG.md). + +The catalog is a roadmap for future automation ideas. It includes more than 74 potential daily, weekly, monthly, quarterly, and annual tasks across FinOps, capacity management, FinOps for AI, governance, optimization, benchmarking, and executive reporting. Those catalog entries are planned ideas, not deployed scheduled tasks, unless they are listed in the deployed task catalog above. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/ScheduledTasks) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Anomaly management](../../framework/understand/anomalies.md) +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure Monitor](/azure/azure-monitor/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [Azure SRE Agent template reference (FinOps toolkit)](template.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/security.md b/docs-mslearn/toolkit/sre-agent/security.md new file mode 100644 index 000000000..3aa3109bb --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/security.md @@ -0,0 +1,200 @@ +--- +title: Security and permissions for Azure SRE Agent in the FinOps toolkit +description: Review the permissions, identities, run modes, and data flows the FinOps toolkit configures on Azure SRE Agent before you deploy it in your environment. +author: msbrett +ms.author: brettwil +ms.date: 06/01/2026 +ms.topic: concept-article +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps hub admin, I want to understand the security and permissions the FinOps toolkit configures on Azure SRE Agent so that I can deploy it with least privilege. +--- + +# Security and permissions for Azure SRE Agent in the FinOps toolkit + +The FinOps toolkit deployment configures Azure SRE Agent with managed identity, Azure RBAC, Azure Data Explorer permissions, and optional Microsoft Teams or Outlook connectors to run FinOps and capacity workflows. Review these permissions before deployment so you can keep the agent scoped to the data and actions it needs. + +> [!IMPORTANT] +> The agent is designed for least privilege. The template grants read, monitoring, Kusto viewer, and zone mapping permissions. It doesn't grant broad write access to Azure resources. + +
+ +## Deployment permissions + +To deploy the template, the deploying user or service principal needs one of these permission sets on the target subscription: + +- **Owner** +- **User Access Administrator** and **Contributor** + +These permissions are needed because deployment creates a resource group, creates Azure resources, assigns Azure RBAC roles, and assigns the deploying principal the Azure SRE Agent Administrator role on the agent resource. + +> [!TIP] +> Use a dedicated deployment identity for production environments. After deployment, review role assignments and remove any temporary permissions the deployment identity no longer needs. + +
+ +## Managed identity permissions + +The template creates an Azure SRE Agent with a system-assigned managed identity. + +The system-assigned managed identity is the primary identity the template manages. The template uses it for Azure resource operations, action execution, the knowledge graph configuration, and connector setup. The deployment grants the system-assigned managed identity these permissions: + +| Role | Scope | What it grants | Why it's needed | +|------|-------|----------------|-----------------| +| Reader | Subscription | Read access to Azure resources and metadata | Lets the agent inspect resource configuration, cost scopes, quota context, and related Azure inventory | +| Reader | Target resource groups | Read access to scoped resource groups | Lets the agent inspect explicitly targeted resources | +| Monitoring Reader | Target resource groups | Read access to Azure Monitor settings and telemetry | Lets the agent use monitoring context for investigations and health checks | +| Log Analytics Reader | Target resource groups | Read access to Log Analytics resources | Lets the agent query scoped workspace telemetry when configured | +| Contributor | Target resource groups when `accessLevel` is `High` | Resource-group write access | Lets remediation tools create or update approved alerts and budgets in targeted scopes | +| AllDatabasesViewer | Azure Data Explorer cluster | Viewer access across databases in the cluster | Lets the Kusto connector query FinOps hub cost data | +| SRE Agent Administrator | Agent resource | Administer the Azure SRE Agent resource | Lets the deploying principal manage the agent after deployment | + +With this default scope, the managed identity can read Azure resource metadata, monitoring context, and FinOps hub data. It can write approved remediation resources only in explicitly targeted resource groups when `accessLevel` is `High`, and it can send messages or email only through connectors you configure. + +
+ +## Data Explorer permissions + +The agent reads FinOps hub data through an Azure Data Explorer connector. When you provide the optional cluster name and cluster resource group parameters, the deployment assigns `AllDatabasesViewer` on the target Azure Data Explorer cluster to the system-assigned managed identity. + +This permission lets the agent query hub data, including cost, usage, commitment, allocation, anomaly, and forecast datasets exposed through the FinOps toolkit Kusto tools. It doesn't grant database administration permissions. + +> [!NOTE] +> If you don't grant `AllDatabasesViewer` during deployment, a cluster administrator can grant the equivalent viewer permission later. The Kusto connector won't return FinOps hub results until the managed identity has permission on the cluster. + +
+ +## Connector permissions + +The agent doesn't create Teams or Outlook notification connectors during deployment. You add them interactively in [sre.azure.com](https://sre.azure.com) after deployment. + +To configure a Teams or Outlook connector, the configuring user needs **Contributor** on the agent resource group, including these actions: + +| Permission | Why it's needed | +|------------|-----------------| +| `Microsoft.Web/connections/write` | Creates or updates the connector resource that stores the connection configuration | +| `Microsoft.Authorization/roleAssignments/write` | Assigns the selected managed identity permission to use the connector resource | + +Communication connectors use both OAuth and managed identity: + +1. You sign in with a Microsoft 365 account through OAuth. +2. You select the agent's managed identity. +3. The connector stores the OAuth token securely in the connector resource. +4. The agent uses the managed identity at runtime to access the connector resource and send messages or email. + +For Teams, the account that signs in must have access to the target channel and the channel's **Get link to channel** URL. The connector can post messages to the configured channel, reply to threads, and read channel messages for context. + +
+ +## Run modes + +Azure SRE Agent supports two run modes: + +| Mode | Security behavior | Use with the FinOps toolkit deployment | +|------|-------------------|---------------------------| +| Review | The agent proposes Azure infrastructure write actions, and an SRE Agent Administrator approves or denies them | Best for production response plans and any workflow that might change resources | +| Autonomous | The agent runs allowed actions without waiting for approval | Best for trusted recurring reports, health checks, and scheduled FinOps summaries | + +The template sets the agent action configuration to **Autonomous** so scheduled cost and capacity reports can run and post results without manual approval. + +> [!IMPORTANT] +> Run mode doesn't replace permissions. The agent can act only when its managed identity, connector, and data source permissions allow the action. Review mode adds an approval step for Azure infrastructure write actions, but other actions, such as querying data or posting to Teams, run based on available tools and permissions. + +Start with Review for workflows that could affect production resources. Use Autonomous for read-only reporting tasks after you confirm the prompts, tools, and destination channels are correct. + +
+ +## B2B tenant considerations + +In B2B environments, the Azure subscription and Azure SRE Agent resource can be in a different Microsoft Entra tenant than your Microsoft 365 home tenant. + +Use these checks when deployment, Azure MCP Server, or connector configuration fails: + +1. Confirm the active Azure CLI context points to the subscription that owns the SRE Agent resource. +2. Re-authenticate against the tenant that owns the subscription. +3. When using Azure MCP Server `sreagent` tools, pass the resource tenant, subscription, resource group, and agent name explicitly. +4. If Azure MCP Server returns `403` from its SRE Agent path, verify the same identity can read the ARM resource and data-plane endpoint before changing agent permissions. + +Browser access can succeed while a local tool returns `401`, `403`, or `Forbidden` if the token was issued for the wrong tenant. The deployment script sets the active subscription before deployment to reduce this risk. + +Connector setup can also cross identity boundaries. The Azure resource permissions come from the resource tenant, while Teams or Outlook OAuth uses the Microsoft 365 account that signs in to the connector. + +
+ +## Data flow + +The agent reads operational and cost data from these sources: + +- FinOps hub cost and usage data in Azure Data Explorer. +- Azure resource metadata through Reader permissions. +- Azure Monitor and Log Analytics context through target resource group reader permissions. +- Uploaded knowledge documents that describe FinOps toolkit tools, Teams notification patterns, report output style, and known issues. + +Scheduled reports and investigation summaries can be sent to: + +- The Azure SRE Agent chat experience. +- A configured Microsoft Teams channel. +- Outlook, if you add the Outlook connector. + +Don't save financial data to agent memory. Save only operational notes, such as tool errors, workarounds, and repeatable patterns. + +Data residency follows the Azure resources and Microsoft 365 services you connect. FinOps hub data stays in your Azure Data Explorer cluster until queried. Agent telemetry is written to the deployed Log Analytics and Application Insights resources. Teams or Outlook reports are delivered to the channel or mailbox you configure, and OAuth tokens are stored in the connector resource rather than in the agent prompt or knowledge files. + +
+ +## Least privilege checklist + +Use this checklist before you move from test to production: + +- Grant the deployment identity only the permissions needed for deployment. +- Keep the agent managed identity scoped to subscription Reader, target resource group reader/remediation permissions, and Azure Data Explorer viewer permissions unless your own workflows require more. +- Use Review mode for production workflows that can change Azure resources. +- Use Autonomous mode only for trusted reports, health checks, and read-only tasks. +- Configure Teams and Outlook connectors with accounts that are allowed to send to the target audience. +- Send reports only to channels or mailboxes approved for cost and capacity information. +- Review Data Explorer access when hub databases or clusters change. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Run modes in Azure SRE Agent](/azure/sre-agent/run-modes) +- [Azure Data Explorer](/azure/data-explorer/) +- [Azure Monitor](/azure/azure-monitor/) + +Related solutions: + +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Azure SRE Agent template reference (FinOps toolkit)](template.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/template.md b/docs-mslearn/toolkit/sre-agent/template.md new file mode 100644 index 000000000..79e4c00a7 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/template.md @@ -0,0 +1,209 @@ +--- +title: Azure SRE Agent template reference (FinOps toolkit) +description: Review the FinOps toolkit's Azure SRE Agent deployment template, parameters, outputs, script flags, and Bicep module structure. +author: msbrett +ms.author: brettwil +ms.date: 06/02/2026 +ms.topic: reference +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps hub admin, I want to understand the FinOps toolkit's Azure SRE Agent template so that I can deploy and customize it safely. +--- + +# Azure SRE Agent template reference (FinOps toolkit) + +This reference summarizes the [FinOps toolkit's Azure SRE Agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent). Use it to review deployment prerequisites, Bicep parameters, script options, and module structure before you deploy or customize the template. + +
+ +## Prerequisites + +Ensure the following prerequisites are met before you deploy the template: + + +- You must have permissions to create the deployed resources and assign roles. + + | Task | Minimum permission | + | ---- | ------------------ | + | Deploy the subscription-scoped Bicep template and create the target resource group | [Contributor](/azure/role-based-access-control/built-in-roles#contributor) on the subscription | + | Assign subscription and target resource group roles to the agent managed identity | [Role Based Access Control Administrator](/azure/role-based-access-control/built-in-roles#role-based-access-control-administrator), [User Access Administrator](/azure/role-based-access-control/built-in-roles#user-access-administrator), or [Owner](/azure/role-based-access-control/built-in-roles#owner) on the assignment scopes | + | Assign Azure Data Explorer access when cluster parameters are set | Permission to create `Microsoft.Kusto/clusters/principalAssignments` on the target cluster | + | Apply Azure SRE Agent objects with the portal deployment script or `bin/apply-extras.sh` | SRE Agent Administrator on the deployed Azure SRE Agent resource | + +- The `Microsoft.App` resource provider must be registered in the subscription. +- For local CLI deployments only: [Azure CLI](/cli/azure/install-azure-cli), `curl`, `jq`, Bash 3.2 or newer, and `python3` with PyYAML must be available locally. +- A FinOps hub with Azure Data Explorer is required when you want the agent to query hub data. + + +
+ +## Parameters + +Here are the parameters you can use to customize the deployment: + +| Parameter | Type | Default value | Allowed values | Description | +| --------- | ---- | ------------- | -------------- | ----------- | +| **resourceGroupName** | String | None | Any string | Required. Resource group that contains the SRE Agent resources. | +| **agentName** | String | None | Any string | Required. Azure SRE Agent name. | +| **location** | String | `eastus2` | `australiaeast`, `canadacentral`, `eastus2`, `francecentral`, `koreacentral`, `swedencentral`, `uksouth` | Optional. Primary location for all resources. | +| **targetResourceGroups** | Array | `[]` | Resource group names | Optional. Resource groups the agent can observe or act on. Defaults to the agent resource group. | +| **targetResourceGroupNames** | String | `""` | Comma-separated resource group names | Optional. Portal form input for target resource groups. Defaults to the agent resource group. | +| **accessLevel** | String | `High` | `Low`, `High` | Optional. Agent access level. | +| **actionMode** | String | `autonomous` | `review`, `autonomous`, `readOnly` | Optional. Agent action mode. | +| **upgradeChannel** | String | `Preview` | `Stable`, `Preview` | Optional. Agent upgrade channel. | +| **defaultModelProvider** | String | `MicrosoftFoundry` | `MicrosoftFoundry`, `Anthropic` | Optional. Parent SRE Agent model provider. `MicrosoftFoundry` maps to Azure OpenAI in the SRE Agent portal. | +| **defaultModelName** | String | `Automatic` | Any supported model name | Optional. Parent SRE Agent model name. Use `Automatic` so SRE Agent routes to the appropriate model inside the selected provider. | +| **monthlyAgentUnitLimit** | Int | `10000` | 1 or higher | Optional. Monthly agent unit limit. | +| **experimentalSettings** | Object | `{ "EnableSandboxGroup": true, "EnableWorkspaceTools": true }` | Object | Optional. Agent sandbox and workspace tool settings for the stable SRE Agent runtime. | +| **finopsHubKustoConnectorUri** | String | `""` | Database-qualified Kusto URI | Optional. Kusto connector URI for the FinOps hub database, such as `https://cluster.region.kusto.windows.net/Hub`. | +| **finopsHubKustoClusterResourceId** | String | `""` | Azure resource ID | Optional. Azure Data Explorer cluster resource ID for the FinOps hub role assignment. | +| **enableSubscriptionReaderRole** | Boolean | `true` | `true`, `false` | Optional. Assigns Reader at subscription scope to the agent managed identity. | +| **recipePackageUri** | String | Derived from the template URI | Public URI | Optional. URI for the packaged recipe assets used by the portal deployment script. | +| **forceUpdateTag** | String | Current deployment timestamp | Any string | Optional. Forces the portal deployment script to rerun during redeployment. | + +
+ +## Deployment values + +The portal template receives values from `createUiDefinition.json`, then runs a subscription-scoped ARM deployment directly from the published toolkit deploy artifacts. `bin/deploy.sh` writes a deployment parameter file under the local SRE Agent deployment cache, then runs `az deployment sub create` directly. Neither path uses Azure Developer CLI environments. + +| Value | Source | Description | +| ----- | ------ | ----------- | +| **subscription** | `--subscription` | Azure subscription ID. | +| **resourceGroupName** | `--resource-group` | Resource group that contains the SRE Agent resources. | +| **agentName** | `--name` | Azure SRE Agent name. | +| **location** | `--location` | Azure location for the deployment. | +| **targetResourceGroups** | `--target-resource-group` | Target resource group names. Defaults to the agent resource group. | +| **enableSubscriptionReaderRole** | Default, unless `--no-subscription-reader` is passed | Whether the deployment assigns subscription-scope Reader to the agent managed identity. | +| **defaultModelProvider** | `agent.json` | Parent SRE Agent model provider. The FinOps hub recipe defaults to Azure OpenAI provider-level routing with `MicrosoftFoundry`. | +| **defaultModelName** | `agent.json` | Parent SRE Agent model name. The FinOps hub recipe defaults to `Automatic` model routing. | +| **finopsHubKustoClusterResourceId** | `--cluster-resource-id` | Optional cluster resource ID used to assign `AllDatabasesViewer`. | +| **FinOps Hub Kusto connector URI** | `--cluster-uri` | Database-qualified Kusto URI, such as `https://cluster.region.kusto.windows.net/Hub`. | + +
+ +## Portal recipe configuration + +The Deploy to Azure path packages `azuredeploy.json`, `createUiDefinition.json`, and `sre-agent-recipe.zip` under `docs/deploy/sre-agent//`. The `recipePackageUri` parameter defaults to a file beside the linked template by using the ARM deployment template-link URI. The deployment script downloads that package, reads `extras.json`, and applies the same recipe objects as `bin/apply-extras.sh`. + +The deployment script uses a user-assigned managed identity. Bicep grants that identity SRE Agent Administrator on the agent resource before the script runs, then the script uses ARM for connectors and the SRE Agent data plane for built-in tools, knowledge, tools, skills, subagents, and scheduled tasks. + +
+ +## Azure Data Explorer network access + +When `--cluster-uri` points to an Azure Data Explorer cluster, the deployment inspects the cluster's network access setting before creating the agent. If `publicNetworkAccess` is `Disabled`, the deployment doesn't stop. It still deploys all resources, assigns the agent managed identity `AllDatabasesViewer`, and creates the `finops-hub-kusto` connector. + +The deployment prints a warning with the [Azure SRE Agent VNET known limitations](https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations) because hosted Azure SRE Agent can't run direct KQL queries against private endpoint ADX clusters. The customer must decide whether to enable public query access for the cluster. Until public query access is enabled or Azure SRE Agent adds private endpoint ADX query support, the connector is expected to remain unhealthy. + +
+ +## Outputs + +Here are the outputs generated by the deployment: + +| Output | Type | Description | +| ------ | ---- | ----------- | +| **AZURE_RESOURCE_GROUP** | String | Name of the Azure resource group that contains the SRE Agent resources. | +| **AZURE_LOCATION** | String | Azure location used for the SRE Agent resources. | +| **SRE_AGENT_NAME** | String | Name of the deployed Azure SRE Agent resource. | +| **SRE_AGENT_ENDPOINT** | String | Endpoint of the deployed Azure SRE Agent resource. | + +
+ +## Script flags + +The template includes Bash scripts for one-shot deployment and extras configuration. + +### Deployment wrapper + +Use `bin/deploy.sh` to write deterministic ARM parameters, deploy `infra/main.bicep` with Azure CLI, and run `bin/apply-extras.sh`. + +Supporting resource names are deterministic for the subscription ID, agent resource group ID, and agent name. Rerunning the script with the same tuple updates the same Log Analytics workspace, Application Insights component, system-assigned managed identity RBAC assignments, and SRE Agent instead of creating timestamped duplicates. The optional `--deploy-name` only names the ARM deployment record and local build directory. + +| Bash flag | Required | Description | +| --------- | -------- | ----------- | +| `--recipe ` | Yes | Recipe directory. Use `recipes/finops-hub`. | +| `--subscription ` | Yes | Azure subscription ID. | +| `--resource-group ` | Yes | Resource group for SRE Agent resources. | +| `--name ` | Yes | Azure SRE Agent name. | +| `--location ` | Yes | Azure region. | +| `--target-resource-group ` | No | Repeatable target resource group. Defaults to `--resource-group`. | +| `--cluster-uri ` | No | Database-qualified FinOps hub Kusto URI, such as `https://cluster.region.kusto.windows.net/Hub`. | +| `--cluster-resource-id ` | Optional with `--cluster-uri` for real deployments; required for `--dry-run` | Kusto cluster ARM resource ID for `AllDatabasesViewer`. Real deployments resolve it from `--cluster-uri` when the cluster is in the target subscription. | +| `--no-subscription-reader` | No | Skips the default subscription-scope Reader assignment. Use only when equivalent read access is granted another way. | +| `--deploy-name ` | No | Deployment name override. Defaults to a deterministic name from subscription ID, resource group, and agent name. | +| `--dry-run` | No | Validate inputs and write parameters without Azure calls. | +| `--force`, `--no-telemetry` | No | Compatibility flags accepted by the wrapper. | +| `-h`, `--help` | No | Show script help. | + +### Extras configuration + +Use `bin/apply-extras.sh` to configure the Kusto connector through ARM when requested, upload KnowledgeFile sources, and apply custom agents, skills, tools, and scheduled tasks through the SRE Agent data plane. `bin/post-provision.sh` remains as a deprecated compatibility wrapper that forwards to `bin/apply-extras.sh`. + +| Bash flag | Required | Description | +| --------- | -------- | ----------- | +| `--endpoint ` | Yes | SRE Agent endpoint returned by deployment. | +| `--recipe ` | Yes | Recipe directory. | +| `--subscription ` | Yes | Azure subscription that contains the SRE Agent. | +| `--resource-group ` | Yes | Resource group that contains the SRE Agent. | +| `--name ` | Yes | SRE Agent name. | +| `--build-dir ` | Yes | Working directory for generated extras request and response files. | +| `--kusto-connector-uri ` | No | Database-qualified Kusto connector URI. | + +
+ +## Module structure + +The template uses a subscription-scoped entry point and resource group modules: + +| File | Scope | Deploys or configures | +| ---- | ----- | --------------------- | +| `infra/main.bicep` | Subscription | Creates the target resource group, calls the resource group deployment, assigns subscription and target resource group RBAC, and optionally assigns Azure Data Explorer roles. | +| `infra/resources.bicep` | Resource group | Orchestrates identity, monitoring, and Azure SRE Agent modules, then surfaces outputs to the subscription deployment. | +| `infra/modules/monitoring.bicep` | Resource group | Creates the Log Analytics workspace and workspace-based Application Insights component for telemetry. | +| `infra/modules/sre-agent.bicep` | Resource group | Creates the `Microsoft.App/agents@2026-01-01` resource, configures action mode, model provider, sandbox, and workspace tool settings, assigns SRE Agent Administrator to the deployer, and exposes the agent endpoint for `bin/apply-extras.sh`. | +| `infra/modules/resource-group-rbac.bicep` | Resource group | Assigns Reader, Monitoring Reader, Log Analytics Reader, and optionally Contributor to the agent system-assigned managed identity. | +| `infra/modules/kusto-all-databases-viewer-rbac.bicep` | Resource group | Assigns `AllDatabasesViewer` on an existing Azure Data Explorer cluster to the system-assigned managed identity when cluster parameters are provided. | + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Rate optimization](../../framework/optimize/rates.md) + +Related products: + +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) + +Related solutions: + +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/tools.md b/docs-mslearn/toolkit/sre-agent/tools.md new file mode 100644 index 000000000..429a08d50 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/tools.md @@ -0,0 +1,186 @@ +--- +title: Tools shipped for Azure SRE Agent in the FinOps toolkit +description: Review the Kusto and Python tools the FinOps toolkit ships for Azure SRE Agent for cost analysis, anomaly detection, rate optimization, capacity management, and operations. +author: msbrett +ms.author: brettwil +ms.date: 06/01/2026 +ms.topic: reference +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand which tools the FinOps toolkit ships for Azure SRE Agent so that I can choose the right agent workflow for cost, capacity, and operations analysis. +--- + +# Tools shipped for Azure SRE Agent in the FinOps toolkit + +The FinOps toolkit deployment configures Azure SRE Agent with tools that ground agent responses in live Azure and FinOps hub data. [Kusto tools](kusto-tools.md) query the FinOps hub Azure Data Explorer database, and [Python tools](python-tools.md) call Azure APIs through the agent's managed identity. + +Use this article as a catalog of the tools included with the template. For deeper implementation details, review the [Kusto tools](kusto-tools.md) and [Python tools](python-tools.md) references. + +The template configures 50 tools: 37 Kusto query tools generated from the FinOps hub query catalog and 13 Python tools, as documented in the [Kusto tools](kusto-tools.md) and [Python tools](python-tools.md) references. All Kusto tools are assigned only to `ftk-database-query`; other agents request Kusto evidence from that specialist instead of querying FinOps hub directly. + +> [!NOTE] +> The agent list shows subagents that reference each tool in `recipes/finops-hub/config/subagents`. Tools marked "Not assigned" are included in the tool catalog, but aren't referenced by a subagent configuration. For agent roles and tool usage, see [agents and skills](agents.md). + +
+ +## AI cost management + +AI cost management tools help agents analyze Azure OpenAI spend, token usage, model efficiency, and application-level allocation, as described in [AI/ML costs](kusto-tools.md#aiml-costs). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `ai-cost-by-application` | `Kusto` | Breaks down Azure OpenAI costs by application, team, and environment tags for chargeback, showback, and allocation; see [ai-cost-by-application](kusto-tools.md#ai-cost-by-application). | `ftk-database-query` | +| `ai-daily-trend` | `Kusto` | Shows daily Azure OpenAI cost and token trends for AI cost anomaly detection and forecasting; see [ai-daily-trend](kusto-tools.md#ai-daily-trend). | `ftk-database-query` | +| `ai-model-cost-comparison` | `Kusto` | Compares Azure OpenAI model cost per 1,000 tokens to identify model efficiency opportunities; see [ai-model-cost-comparison](kusto-tools.md#ai-model-cost-comparison). | `ftk-database-query` | +| `ai-token-usage-breakdown` | `Kusto` | Breaks down Azure OpenAI token consumption by model version and input or output direction; see [ai-token-usage-breakdown](kusto-tools.md#ai-token-usage-breakdown). | `ftk-database-query` | + +
+ +## Cost analysis and reporting + +Cost analysis and reporting tools summarize FinOps hub cost data by service, region, resource group, financial hierarchy, transaction type, and time period, as described in [Cost analysis](kusto-tools.md#cost-analysis) and [Price analysis](kusto-tools.md#price-analysis). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `costs-enriched-base` | `Kusto` | Returns a guarded row-level enriched cost and usage sample for narrow drill-downs; see [costs-enriched-base](kusto-tools.md#costs-enriched-base). Use aggregate tools for full-month, fiscal-period, scheduled report, and tag-coverage rollup requests. | `ftk-database-query` | +| `cost-by-financial-hierarchy` | `Kusto` | Reports top costs across billing profile, invoice section, team, product, application, and environment; see [cost-by-financial-hierarchy](kusto-tools.md#cost-by-financial-hierarchy). | `ftk-database-query` | +| `cost-by-region-trend` | `Kusto` | Summarizes effective cost by Azure region to identify regional spend distribution and optimization opportunities; see [cost-by-region-trend](kusto-tools.md#cost-by-region-trend). | `ftk-database-query` | +| `monthly-cost-change-percentage` | `Kusto` | Calculates month-over-month billed and effective cost changes to spot spikes, drops, and volatility; see [monthly-cost-change-percentage](kusto-tools.md#monthly-cost-change-percentage). | `ftk-database-query` | +| `monthly-cost-trend` | `Kusto` | Returns billed and effective cost totals by month for trend review and budget analysis; see [monthly-cost-trend](kusto-tools.md#monthly-cost-trend). | `ftk-database-query` | +| `quarterly-cost-by-resource-group` | `Kusto` | Returns top resource-group cost rows by subscription and month for quarterly reporting windows; see [quarterly-cost-by-resource-group](kusto-tools.md#quarterly-cost-by-resource-group). | `ftk-database-query` | +| `top-other-transactions` | `Kusto` | Lists top non-usage, non-commitment purchase transactions, such as Marketplace or miscellaneous charges; see [top-other-transactions](kusto-tools.md#top-other-transactions). | `ftk-database-query` | +| `top-resource-groups-by-cost` | `Kusto` | Returns top resource groups by effective cost for focused reporting and optimization; see [top-resource-groups-by-cost](kusto-tools.md#top-resource-groups-by-cost). | `ftk-database-query` | +| `top-resource-types-by-cost` | `Kusto` | Returns top resource types by resource count and effective cost to identify costly categories; see [top-resource-types-by-cost](kusto-tools.md#top-resource-types-by-cost). | `ftk-database-query` | +| `top-services-by-cost` | `Kusto` | Returns top Azure services by effective cost to prioritize service-level optimization; see [top-services-by-cost](kusto-tools.md#top-services-by-cost). | `ftk-database-query` | + +
+ +## FinOps KPI scorecard + +FinOps KPI scorecard tools are generated from [`src/queries/catalog`](../../../src/queries/catalog/) and map directly to query links in [`src/queries/KPI.md`](../../../src/queries/KPI.md). Scheduled monthly, semiannual, health, anomaly, capacity, storage, monitoring, and benefit-review tasks request these tools through `ftk-database-query`. + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `allocation-accuracy-index` | `Kusto` | Measures directly attributed cost as a share of total effective cost. | `ftk-database-query` | +| `anomaly-detection-rate` | `Kusto` | Measures the share of spend in anomaly-flagged daily buckets. | `ftk-database-query` | +| `anomaly-variance-total` | `Kusto` | Quantifies unpredicted spend variance for detected anomaly events. | `ftk-database-query` | +| `commitment-discount-waste` | `Kusto` | Measures unused commitment value as a share of total commitment cost. | `ftk-database-query` | +| `commitment-utilization-score` | `Kusto` | Computes commitment utilization score by commitment and currency. | `ftk-database-query` | +| `compute-cost-per-core` | `Kusto` | Calculates effective and hourly compute cost per consumed vCPU core hour. | `ftk-database-query` | +| `compute-spend-commitment-coverage` | `Kusto` | Measures compute spend covered by commitment discounts. | `ftk-database-query` | +| `cost-optimization-index` | `Kusto` | Computes a cost optimization index from current recommendations and cost context. | `ftk-database-query` | +| `cost-per-gb-stored` | `Kusto` | Calculates storage cost per normalized GB-month. | `ftk-database-query` | +| `cost-visibility-delay` | `Kusto` | Measures cost data visibility delay for data-ingestion KPI reporting. | `ftk-database-query` | +| `data-update-frequency` | `Kusto` | Measures FinOps hub ingestion update cadence. | `ftk-database-query` | +| `macc-consumption-vs-commitment` | `Kusto` | Measures Microsoft Azure Consumption Commitment drawdown against commitment. | `ftk-database-query` | +| `percentage-unallocated-costs` | `Kusto` | Measures the share of cost missing required allocation evidence. | `ftk-database-query` | +| `percentage-untagged-costs` | `Kusto` | Measures the share of cost on resources with no tags. | `ftk-database-query` | +| `storage-tier-distribution` | `Kusto` | Summarizes storage cost and GB-month distribution by access-tier bucket. | `ftk-database-query` | +| `tagging-policy-compliance` | `Kusto` | Measures cost-weighted compliance with required tag keys. | `ftk-database-query` | + +
+ +## Anomaly detection and forecasting + +Anomaly detection and forecasting tools help agents identify unexpected cost changes, project future spend, and deploy alerting automation, as described in [Anomaly detection](kusto-tools.md#anomaly-detection), [Forecasting](kusto-tools.md#forecasting), and [Budget and alert deployment](python-tools.md#budget-and-alert-deployment). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `cost-anomaly-detection` | `Kusto` | Detects cost spikes and drops with time-series anomaly detection over a configurable history window; see [cost-anomaly-detection](kusto-tools.md#cost-anomaly-detection). | `ftk-database-query` | +| `cost-forecasting-model` | `Kusto` | Forecasts future effective cost from historical cost data for budgeting and trend projection; see [cost-forecasting-model](kusto-tools.md#cost-forecasting-model). | `ftk-database-query` | +| `deploy-anomaly-alert` | `Python` | Creates or updates a Cost Management scheduled action for anomaly detection in a subscription after explicit remediation approval; see [deploy-anomaly-alert](python-tools.md#deploy-anomaly-alert). | `finops-practitioner` | +| `deploy-bulk-anomaly-alerts` | `Python` | Discovers enabled subscriptions in a management group and deploys anomaly alert scheduled actions per subscription after explicit remediation approval; see [deploy-bulk-anomaly-alerts](python-tools.md#deploy-bulk-anomaly-alerts). | `finops-practitioner` | + +
+ +## Rate optimization + +Rate optimization tools help agents review reservations, savings plans, pricing benchmarks, commitment transactions, and Advisor recommendation suppression workflows, as described in [Commitment discounts](kusto-tools.md#commitment-discounts), [Price analysis](kusto-tools.md#price-analysis), [Resource analysis](python-tools.md#resource-analysis), and [Advisor](python-tools.md#advisor). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `benefit-recommendations` | `Python` | Gets Microsoft Cost Management benefit recommendations for savings plans and reserved instances at a billing scope; see [benefit-recommendations](python-tools.md#benefit-recommendations). | `finops-practitioner`, `azure-capacity-manager` | +| `commitment-discount-utilization` | `Kusto` | Analyzes consumed core hours by commitment discount type, including on-demand usage, for a reporting window; see [commitment-discount-utilization](kusto-tools.md#commitment-discount-utilization). | `ftk-database-query` | +| `reservation-recommendation-breakdown` | `Kusto` | Analyzes reservation recommendations, savings, break-even dates, normalized sizes, scope, and term details; see [reservation-recommendation-breakdown](kusto-tools.md#reservation-recommendation-breakdown). | `ftk-database-query` | +| `savings-summary-report` | `Kusto` | Summarizes list cost, effective cost, negotiated savings, commitment savings, total savings, and savings rate; see [savings-summary-report](kusto-tools.md#savings-summary-report). | `ftk-database-query` | +| `service-price-benchmarking` | `Kusto` | Benchmarks services by list cost, contracted cost, effective cost, negotiated savings, commitment savings, and total savings; see [service-price-benchmarking](kusto-tools.md#service-price-benchmarking). | `ftk-database-query` | +| `suppress-advisor-recommendations` | `Python` | Suppresses selected Azure Advisor recommendations across subscriptions under a management group with a time to live after explicit remediation approval; see [suppress-advisor-recommendations](python-tools.md#suppress-advisor-recommendations). | `finops-practitioner` | +| `top-commitment-transactions` | `Kusto` | Returns top non-usage commitment discount purchase transactions for reservation and savings plan review; see [top-commitment-transactions](kusto-tools.md#top-commitment-transactions). | `ftk-database-query` | + +
+ +## Capacity management + +Capacity management tools help agents inspect quota, capacity reservations, SKU availability, and non-compute service limits before planning or deployment, as described in [Capacity and quota](python-tools.md#capacity-and-quota) and the [azure-capacity-manager](agents.md#azure-capacity-manager) agent reference. + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `capacity-reservation-groups` | `Python` | Lists capacity reservation groups and compares reserved capacity with allocated virtual machines; see [capacity-reservation-groups](python-tools.md#capacity-reservation-groups). | `azure-capacity-manager` | +| `non-compute-quotas` | `Python` | Checks non-compute service quota usage with provider usage APIs and estimated Resource Graph fallbacks; see [non-compute-quotas](python-tools.md#non-compute-quotas). | `azure-capacity-manager` | +| `sku-availability` | `Python` | Lists Azure Compute or Azure Data Explorer SKU availability, zones, and regional restriction reasons before planning or deployment; see [sku-availability](python-tools.md#sku-availability). | `azure-capacity-manager`, `ftk-hubs-agent` | +| `vm-quota-usage` | `Python` | Reports VM family quota usage by region and flags families above 80% or 95% utilization; see [vm-quota-usage](python-tools.md#vm-quota-usage). | `azure-capacity-manager` | + +
+ +## Governance and automation + +Governance and automation tools help agents deploy budget guardrails and run Resource Graph queries for inventory, configuration, and operational checks, as described in [Budget and alert deployment](python-tools.md#budget-and-alert-deployment) and [Resource analysis](python-tools.md#resource-analysis). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `deploy-budget` | `Python` | Creates or updates a subscription-level Cost Management budget with notification contacts after explicit remediation approval; see [deploy-budget](python-tools.md#deploy-budget). | `finops-practitioner` | +| `deploy-bulk-budgets` | `Python` | Discovers enabled subscriptions in a management group and creates or updates a Cost Management budget in each subscription after explicit remediation approval; see [deploy-bulk-budgets](python-tools.md#deploy-bulk-budgets). | `finops-practitioner` | +| `resource-graph-query` | `Python` | Runs Azure Resource Graph KQL queries across subscriptions for inventory and configuration troubleshooting; see [resource-graph-query](python-tools.md#resource-graph-query). | `finops-practitioner`, `azure-capacity-manager`, `ftk-hubs-agent` | + +
+ +## Data ingestion and health + +Data ingestion and health tools help agents validate whether FinOps hub data is fresh enough to trust for analysis and reporting, as described in [Hub management](python-tools.md#hub-management). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `data-freshness-check` | `Python` | Checks FinOps hub function data freshness through direct Azure Data Explorer REST queries. Treats `Costs()` as the authoritative freshness signal with a three-day threshold and supersedes conflicting stale-memory or raw-KQL conclusions; see [data-freshness-check](python-tools.md#data-freshness-check). | `ftk-hubs-agent` | + +
+ +## Give feedback + +Let us know how we're doing with a [quick review](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent). We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +If you're looking for something specific, [vote for an existing or create a new idea](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc). Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Rate optimization](../../framework/optimize/rates.md) + +Related products: + +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) +- [Microsoft Cost Management](/azure/cost-management-billing/costs/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/troubleshooting.md b/docs-mslearn/toolkit/sre-agent/troubleshooting.md new file mode 100644 index 000000000..4f029c16a --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/troubleshooting.md @@ -0,0 +1,252 @@ +--- +title: Troubleshoot Azure SRE Agent deployments from the FinOps toolkit +description: Resolve common deployment, tenant, connector, data, and query issues for Azure SRE Agent deployments from the FinOps toolkit. +author: msbrett +ms.author: brettwil +ms.date: 06/02/2026 +ms.topic: how-to +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to troubleshoot the FinOps toolkit's Azure SRE Agent deployment so that I can restore scheduled cost, capacity, and operations workflows. +--- + +# Troubleshoot Azure SRE Agent deployments from the FinOps toolkit + +Use this guide when the agent deploys, but Azure MCP Server `sreagent` commands, scheduled tasks, connectors, or data queries don't behave as expected. Start with tenant and deployment checks, then use the known issue sections to match the symptom, cause, and workaround. + +
+ +## Troubleshoot B2B tenant environments + +In B2B environments, the Azure subscription and Azure SRE Agent resource can live in a different Microsoft Entra tenant than your Microsoft 365 home tenant. If [sre.azure.com](https://sre.azure.com) shows the agent correctly but Azure MCP Server `sreagent` commands return `401`, `403`, `AccessDenied`, or `Forbidden`, treat the issue as tenant selection first. + +**Symptom:** Browser access works, but Azure MCP Server `sreagent_agents_list`, `sreagent_agents_get`, `sreagent_agents_tools_list`, or related SRE Agent commands fail with `401`, `403`, `AccessDenied`, or `Forbidden`. + +**Cause:** The tool token can be issued for the wrong tenant or the tool can route the SRE Agent discovery call through a tenant-scoped Resource Graph path. The browser session can use your Microsoft 365 home tenant, while the Azure SRE Agent resource belongs to a different tenant. + +**Workaround:** + +1. Confirm the active Azure CLI context points at the subscription that owns the Azure SRE Agent resource. +1. Re-authenticate Azure CLI against the tenant that owns the subscription and resource. +1. Pass the resource tenant, subscription, resource group, and agent name explicitly to Azure MCP Server `sreagent` commands. +1. Verify the same identity can read the ARM resource with `az resource show` and can call the SRE Agent data-plane endpoint with a token for `https://azuresre.dev`. +1. If ARM and direct data-plane calls work but Azure MCP Server `sreagent` commands still return `AccessDenied`, capture the timestamp and correlation ID from the tool response and route it as an Azure MCP Server or Azure SRE Agent B2B access issue. + +> [!TIP] +> Browser success with Azure MCP Server failure usually means the agent might be healthy, but the tool credential or SRE Agent discovery path needs tenant-specific verification. + +
+ +## Fix common deployment failures + +Use these checks after `bin/deploy.sh` or post-provisioning fails. + +### Unsupported region + +**Symptom:** The Bicep deployment fails during validation or resource creation. + +**Cause:** The template only supports `australiaeast`, `canadacentral`, `eastus2`, `francecentral`, `koreacentral`, `swedencentral`, and `uksouth`. + +**Workaround:** Redeploy in a supported region. + +### Resource provider not registered + +**Symptom:** Azure Resource Manager fails to create the Azure SRE Agent resource. + +**Cause:** The `Microsoft.App` resource provider isn't registered on the target subscription. + +**Workaround:** Register the provider, wait for registration to complete, and rerun deployment. + +```bash +az provider register --namespace Microsoft.App +``` + +### Missing deployment permissions + +**Symptom:** Deployment or role assignment steps fail with authorization errors. + +**Cause:** The deploying user doesn't have enough permissions to create resources or assign roles. + +**Workaround:** Use an account with permissions to create resources and assign roles at the affected scopes. Contributor can create the deployed resources; Role Based Access Control Administrator, User Access Administrator, or Owner can assign the required roles. If you configure notification connectors later, make sure the configuring user can write connections and role assignments in the agent resource group. + +### Zone mapping API returns 404 + +**Symptom:** Capacity or zone-mapping checks fail when the agent calls `checkZonePeers`. + +**Cause:** The `AvailabilityZonePeering` feature isn't registered for the subscription or management group scope. + +**Workaround:** Register the feature and re-register the resource provider. + +```bash +az feature register --namespace Microsoft.Resources --name AvailabilityZonePeering +az provider register --namespace Microsoft.Resources +``` + +### Post-provision hook fails + +**Symptom:** Azure resources deploy, but skills, agents, tools, scheduled tasks, knowledge documents, or the Kusto connector don't appear in [sre.azure.com](https://sre.azure.com). + +**Cause:** The post-provision step couldn't resolve the endpoint, get an SRE Agent data-plane token, configure the Kusto connector, or apply the SRE configuration through the supported ARM and data-plane APIs. + +**Workaround:** Check that Azure CLI, `python3`, `jq`, `curl`, and `bash` are available locally. Then rerun `bin/apply-extras.sh` from `src/templates/sre-agent`. + +### Connector setup is missing + +**Symptom:** Scheduled tasks run, but Teams or Outlook delivery doesn't work. + +**Cause:** `bin/deploy.sh` does not create notification connectors because Teams and Outlook require interactive OAuth setup. + +**Workaround:** Add the Teams or Outlook connector in [sre.azure.com](https://sre.azure.com), select the agent managed identity, and send a test message. + +### Kusto connector is unhealthy for a private endpoint cluster + +**Symptom:** The SRE Agent deployment succeeds and the `finops-hub-kusto` connector is created, but the connector doesn't become healthy. The deployment output may warn that the Azure Data Explorer cluster denies public query access. + +**Cause:** Hosted Azure SRE Agent runs outside your VNET. Azure SRE Agent can use ARM for resource discovery, health, metrics, and management operations, but direct KQL queries to private endpoint Azure Data Explorer clusters are a documented limitation when `publicNetworkAccess` is `Disabled`. + +**Workaround:** Review the [Azure SRE Agent VNET known limitations](https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations), then decide whether to enable public query access for the Azure Data Explorer cluster. The FinOps toolkit deployment doesn't change customer cluster networking automatically. Until public query access is enabled or Azure SRE Agent adds private endpoint ADX query support, Kusto tools that depend on `finops-hub-kusto` are expected to fail while ARM-based health and metrics operations continue to work. + +
+ +## Review known issues + +The following issues were observed during scheduled task testing. They don't always indicate a broken deployment. + +### Teams tool discovery + +**Symptom:** A subagent reports that `PostTeamsChannelMessage` isn't available or that it couldn't find the Teams posting function. + +**Cause:** Subagents invoked directly for manual testing might not inherit Teams connector tools. Connector tools are available to the base agent or when the platform triggers a scheduled task. + +**Workaround:** + +- Use the platform cron schedule for production scheduled tasks. +- For manual testing, invoke the base agent without the `--agent` flag, then delegate with `@subagent` in the prompt. +- Use the built-in `PostTeamsMessage` tool. Don't call Microsoft Graph or dynamic invoke endpoints directly because that path can return `403`. + +### Data pipeline staleness + +**Symptom:** Reports show incomplete or missing recent cost data, and forecasts look distorted. + +**Cause:** The FinOps hub data pipeline or Cost Management export may be stale, so the Azure Data Explorer cluster might not have current data. Older memory notes, raw KQL checks, or ingestion timestamp checks can also report stale data incorrectly after the pipeline has recovered. + +**Workaround:** + +- Run `data-freshness-check` or the hubs health check task to confirm freshness before escalating. Treat the direct REST `Costs()` result as the source of truth. +- If `Costs()` is 3 days old or newer, mark conflicting stale-memory, raw-KQL, or ingestion timestamp conclusions as superseded and don't report the hub as stale. +- If `Costs()` has no rows, has a query error, or is more than 3 days old, let reports call out stale data clearly and check Cost Management exports in the Azure portal and pipeline runs in Azure Data Factory. + +### Resource Graph failures + +**Symptom:** `az graph query` returns an unknown error, and Resource Graph-based analysis fails. + +**Cause:** The managed identity may not have Reader permissions at the right scope, or complex query expressions may fail in the code interpreter shell environment. + +**Workaround:** + +- Fall back to scoped `az resource list` queries against specific subscriptions. +- Confirm the agent managed identity has Reader at the management group or subscription scope. +- Simplify query expressions. + +### Quota CLI failures + +**Symptom:** `az quota usage list` or `az vm list-usage` fails in the agent execution environment. + +**Cause:** The `az quota` extension might be missing, or the managed identity might not have permission to read quota data. + +**Workaround:** + +- Use `az vm list-usage --location ` as a compute quota fallback. +- For broader quota checks, use Azure Resource Manager REST calls from code interpreter. +- Track persistent CLI failures so the quota tool can be updated. + +### JMESPath escaping + +**Symptom:** Azure CLI commands fail when `--query` uses backticks, brackets, or property names with dots. + +**Cause:** Shell escaping conflicts with JMESPath syntax in the code interpreter environment. + +**Workaround:** + +- Prefer `--output json`, then parse the result with Python. +- Use only simple JMESPath selections when you need `--query`. +- Avoid nested expressions that rely on backtick-escaped property names. + +### Memory file conflicts + +**Symptom:** A scheduled task returns `File write failed` and says a memory file already exists. + +**Cause:** A repeated task run tried to create the same memory file again. The memory system requires an edit operation for existing files. + +**Workaround:** + +- Use an edit operation for subsequent writes to the same memory file. +- Treat the first failure as recoverable. Agents can usually switch from create to edit and continue. + +### Kusto query errors + +**Symptom:** A tool returns `Error executing query on cluster`. + +**Cause:** A Kusto tool may reference a function, table, or column that doesn't exist in your FinOps hub version, or the query syntax may need a version-specific update. + +**Workaround:** + +- Try a simpler query. +- Check the FinOps hub version. +- Capture the failing tool name and query so the tool YAML can be fixed. + +
+ +## Get support + +If the workaround doesn't resolve the issue, [open a GitHub issue](https://github.com/microsoft/finops-toolkit/issues/new/choose) and include: + +- The deployment region and target subscription tenant +- The failing command, task, or tool name +- The exact error message +- Whether [sre.azure.com](https://sre.azure.com) can open the agent successfully +- Whether the issue affects deployment, Azure MCP Server `sreagent` commands, scheduled tasks, connectors, or FinOps hub data + +For product ideas or known gaps, [vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc). + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgentTroubleshooting) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Rate optimization](../../framework/optimize/rates.md) + +Related products: + +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) + +Related solutions: + +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) +- [Azure SRE Agent template reference (FinOps toolkit)](template.md) + +
diff --git a/docs/deploy/sre-agent/14.0/azuredeploy.json b/docs/deploy/sre-agent/14.0/azuredeploy.json new file mode 100644 index 000000000..4b6a6d0eb --- /dev/null +++ b/docs/deploy/sre-agent/14.0/azuredeploy.json @@ -0,0 +1,1119 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "2403415415579441400" + } + }, + "parameters": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group that holds the SRE Agent resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "location": { + "type": "string", + "defaultValue": "eastus2", + "allowedValues": [ + "australiaeast", + "canadacentral", + "eastus2", + "francecentral", + "koreacentral", + "swedencentral", + "uksouth" + ], + "metadata": { + "description": "Primary location for all resources." + } + }, + "targetResourceGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Resource groups the agent can observe or act on. The agent resource group is always included." + } + }, + "targetResourceGroupNames": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Comma-separated resource groups the agent can observe or act on. Used by the Azure portal form." + } + }, + "finopsHubKustoConnectorUri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional database-qualified FinOps Hub Kusto connector URI. Example: https://..kusto.windows.net/Hub" + } + }, + "finopsHubKustoClusterResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment." + } + }, + "accessLevel": { + "type": "string", + "defaultValue": "High", + "allowedValues": [ + "Low", + "High" + ], + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "defaultValue": "autonomous", + "allowedValues": [ + "review", + "autonomous", + "readOnly" + ], + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "defaultValue": "Preview", + "allowedValues": [ + "Stable", + "Preview" + ], + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "defaultValue": "MicrosoftFoundry", + "allowedValues": [ + "MicrosoftFoundry", + "Anthropic" + ], + "metadata": { + "description": "Default SRE Agent model provider. MicrosoftFoundry maps to the Azure OpenAI provider in the SRE Agent portal." + } + }, + "defaultModelName": { + "type": "string", + "defaultValue": "Automatic", + "metadata": { + "description": "Default SRE Agent model name. Automatic lets SRE Agent route to the appropriate model within the selected provider." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "defaultValue": 10000, + "minValue": 1, + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "defaultValue": { + "EnableSandboxGroup": true, + "EnableWorkspaceTools": true + }, + "metadata": { + "description": "Agent experimental settings." + } + }, + "enableSubscriptionReaderRole": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Assign Reader on the deployment subscription to the agent managed identity." + } + }, + "recipePackageUri": { + "type": "string", + "defaultValue": "[uri(deployment().properties.templateLink.uri, 'sre-agent-recipe.zip')]", + "metadata": { + "description": "Public URI for the generated SRE Agent recipe package. Deploy-to-Azure links derive this from the template URI." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Forces the recipe deployment script to run when the template is redeployed." + } + }, + "tags": { + "type": "object", + "defaultValue": { + "finops-toolkit": "sre-agent", + "source": "microsoft-finops-toolkit" + }, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "copy": [ + { + "name": "targetRgIds", + "count": "[length(variables('targetRgs'))]", + "input": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('targetRgs')[copyIndex('targetRgIds')])]" + } + ], + "rawTargetResourceGroups": "[split(replace(parameters('targetResourceGroupNames'), ' ', ''), ',')]", + "parsedTargetResourceGroups": "[filter(variables('rawTargetResourceGroups'), lambda('rgName', not(empty(lambdaVariables('rgName')))))]", + "targetRgs": "[union(createArray(parameters('resourceGroupName')), parameters('targetResourceGroups'), variables('parsedTargetResourceGroups'))]", + "agentResourceGroupId": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]", + "namingSeed": "[toLower(format('{0}|{1}|{2}', subscription().subscriptionId, variables('agentResourceGroupId'), parameters('agentName')))]", + "readerRoleId": "acdd72a7-3385-48ef-bd42-f606fba81ae7", + "hasKustoCluster": "[not(empty(parameters('finopsHubKustoClusterResourceId')))]", + "kustoClusterSubscriptionId": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[2], '')]", + "kustoClusterResourceGroupName": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[4], '')]", + "kustoClusterName": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[8], '')]" + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2024-03-01", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + { + "condition": "[parameters('enableSubscriptionReaderRole')]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(subscription().id, variables('namingSeed'), variables('readerRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('readerRoleId'))]", + "principalId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "resources-deployment", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "agentName": { + "value": "[parameters('agentName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "namingSeed": { + "value": "[variables('namingSeed')]" + }, + "targetResourceGroupIds": { + "value": "[variables('targetRgIds')]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + }, + "actionMode": { + "value": "[parameters('actionMode')]" + }, + "upgradeChannel": { + "value": "[parameters('upgradeChannel')]" + }, + "defaultModelProvider": { + "value": "[parameters('defaultModelProvider')]" + }, + "defaultModelName": { + "value": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": { + "value": "[parameters('monthlyAgentUnitLimit')]" + }, + "experimentalSettings": { + "value": "[parameters('experimentalSettings')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11748842726639098374" + } + }, + "parameters": { + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location for all resources." + } + }, + "namingSeed": { + "type": "string", + "metadata": { + "description": "Deterministic naming seed built from subscription ID, agent resource group ID, and agent name." + } + }, + "targetResourceGroupIds": { + "type": "array", + "metadata": { + "description": "Resource group IDs shown as managed resources in the SRE Agent." + } + }, + "accessLevel": { + "type": "string", + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model provider." + } + }, + "defaultModelName": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model name." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "metadata": { + "description": "Agent experimental settings." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "uniqueSuffix": "[uniqueString(parameters('namingSeed'))]", + "logAnalyticsName": "[format('law-{0}', variables('uniqueSuffix'))]", + "appInsightsName": "[format('appi-{0}', variables('uniqueSuffix'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "monitoring", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsName": { + "value": "[variables('logAnalyticsName')]" + }, + "appInsightsName": { + "value": "[variables('appInsightsName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "9164683275614055037" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for resources" + } + }, + "logAnalyticsName": { + "type": "string", + "metadata": { + "description": "Log Analytics Workspace name" + } + }, + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Application Insights name" + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsName')]", + "location": "[parameters('location')]", + "properties": { + "sku": { + "name": "PerGB2018" + }, + "retentionInDays": 30 + } + }, + { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('appInsightsName')]", + "location": "[parameters('location')]", + "kind": "web", + "properties": { + "Application_Type": "web", + "Request_Source": "IbizaAIExtension", + "WorkspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + }, + "dependsOn": [ + "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + ] + } + ], + "outputs": { + "logAnalyticsWorkspaceId": { + "type": "string", + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "value": "[parameters('logAnalyticsName')]" + }, + "appInsightsId": { + "type": "string", + "value": "[resourceId('Microsoft.Insights/components', parameters('appInsightsName'))]" + }, + "appInsightsAppId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('appInsightsName')), '2020-02-02').AppId]" + }, + "appInsightsConnectionString": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('appInsightsName')), '2020-02-02').ConnectionString]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "sre-agent", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "agentName": { + "value": "[parameters('agentName')]" + }, + "appInsightsAppId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsAppId.value]" + }, + "appInsightsConnectionString": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsConnectionString.value]" + }, + "appInsightsId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsId.value]" + }, + "managedResourceGroupIds": { + "value": "[parameters('targetResourceGroupIds')]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + }, + "actionMode": { + "value": "[parameters('actionMode')]" + }, + "upgradeChannel": { + "value": "[parameters('upgradeChannel')]" + }, + "defaultModelProvider": { + "value": "[parameters('defaultModelProvider')]" + }, + "defaultModelName": { + "value": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": { + "value": "[parameters('monthlyAgentUnitLimit')]" + }, + "experimentalSettings": { + "value": "[parameters('experimentalSettings')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6562535881153200016" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "appInsightsAppId": { + "type": "string", + "metadata": { + "description": "Application Insights App ID." + } + }, + "appInsightsConnectionString": { + "type": "securestring", + "metadata": { + "description": "Application Insights connection string." + } + }, + "appInsightsId": { + "type": "string", + "metadata": { + "description": "Application Insights resource ID." + } + }, + "managedResourceGroupIds": { + "type": "array", + "metadata": { + "description": "Resource group IDs to add as managed resources." + } + }, + "accessLevel": { + "type": "string", + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model provider." + } + }, + "defaultModelName": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model name." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "metadata": { + "description": "Agent experimental settings." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "sreAgentAdminRoleId": "e79298df-d852-4c6d-84f9-5d13249d1e55" + }, + "resources": [ + { + "type": "Microsoft.App/agents", + "apiVersion": "2026-01-01", + "name": "[parameters('agentName')]", + "location": "[parameters('location')]", + "tags": "[union(parameters('tags'), createObject('hidden-link: /app-insights-resource-id', parameters('appInsightsId'), 'source', 'microsoft-sre-agent-starter-lab', 'finops-toolkit', 'sre-agent'))]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "knowledgeGraphConfiguration": { + "managedResources": "[parameters('managedResourceGroupIds')]", + "identity": "system" + }, + "actionConfiguration": { + "mode": "[parameters('actionMode')]", + "identity": "system", + "accessLevel": "[parameters('accessLevel')]" + }, + "upgradeChannel": "[parameters('upgradeChannel')]", + "defaultModel": { + "provider": "[parameters('defaultModelProvider')]", + "name": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": "[parameters('monthlyAgentUnitLimit')]", + "experimentalSettings": "[parameters('experimentalSettings')]", + "mcpServers": [], + "logConfiguration": { + "applicationInsightsConfiguration": { + "appId": "[parameters('appInsightsAppId')]", + "connectionString": "[parameters('appInsightsConnectionString')]" + } + } + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/agents', parameters('agentName'))]", + "name": "[guid(resourceId('Microsoft.App/agents', parameters('agentName')), deployer().objectId, variables('sreAgentAdminRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('sreAgentAdminRoleId'))]", + "principalId": "[deployer().objectId]", + "principalType": "User" + }, + "dependsOn": [ + "[resourceId('Microsoft.App/agents', parameters('agentName'))]" + ] + } + ], + "outputs": { + "agentName": { + "type": "string", + "value": "[parameters('agentName')]" + }, + "agentId": { + "type": "string", + "value": "[resourceId('Microsoft.App/agents', parameters('agentName'))]" + }, + "agentEndpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01').agentEndpoint]" + }, + "agentPortalUrl": { + "type": "string", + "value": "[format('https://sre.azure.com/#/agent/{0}/{1}/{2}', subscription().subscriptionId, resourceGroup().name, parameters('agentName'))]" + }, + "agentPrincipalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01', 'full').identity.principalId]" + }, + "agentTenantId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01', 'full').identity.tenantId]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'monitoring')]" + ] + } + ], + "outputs": { + "agentName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentName.value]" + }, + "agentEndpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "agentPortalUrl": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentPortalUrl.value]" + }, + "agentPrincipalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "agentTenantId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentTenantId.value]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.logAnalyticsWorkspaceId.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]" + ] + }, + { + "copy": { + "name": "targetRbac", + "count": "[length(variables('targetRgs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('target-rbac-{0}', uniqueString(toLower(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('targetRgs')[copyIndex()])), variables('namingSeed')))]", + "resourceGroup": "[variables('targetRgs')[copyIndex()]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6305641259472431615" + } + }, + "parameters": { + "principalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the managed identity to assign roles to." + } + }, + "accessLevel": { + "type": "string", + "allowedValues": [ + "Low", + "High" + ], + "metadata": { + "description": "Agent access level." + } + } + }, + "variables": { + "readerRoleId": "acdd72a7-3385-48ef-bd42-f606fba81ae7", + "monitoringReaderRoleId": "43d0d8ad-25c7-4714-9337-8ba259a9fe05", + "logAnalyticsReaderRoleId": "73c42c96-874c-492b-b04d-ab87d138a893", + "contributorRoleId": "b24988ac-6180-42a0-ab88-20f7382dd24c", + "roleIds": "[if(equals(parameters('accessLevel'), 'High'), createArray(variables('readerRoleId'), variables('monitoringReaderRoleId'), variables('logAnalyticsReaderRoleId'), variables('contributorRoleId')), createArray(variables('readerRoleId'), variables('monitoringReaderRoleId'), variables('logAnalyticsReaderRoleId')))]" + }, + "resources": [ + { + "copy": { + "name": "roleAssignments", + "count": "[length(variables('roleIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(resourceGroup().id, parameters('principalId'), variables('roleIds')[copyIndex()])]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleIds')[copyIndex()])]", + "principalId": "[parameters('principalId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "condition": "[variables('hasKustoCluster')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('kusto-rbac-{0}', uniqueString(parameters('finopsHubKustoClusterResourceId'), variables('namingSeed')))]", + "subscriptionId": "[variables('kustoClusterSubscriptionId')]", + "resourceGroup": "[variables('kustoClusterResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "clusterName": { + "value": "[variables('kustoClusterName')]" + }, + "principalApplicationId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "principalTenantId": { + "value": "[tenant().tenantId]" + }, + "principalAssignmentName": { + "value": "[format('sre-agent-{0}', uniqueString(parameters('finopsHubKustoClusterResourceId'), variables('namingSeed'), 'all-db-viewer'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15341408879505554256" + } + }, + "parameters": { + "clusterName": { + "type": "string", + "metadata": { + "description": "Kusto cluster name." + } + }, + "principalApplicationId": { + "type": "string", + "metadata": { + "description": "Microsoft Entra application/client ID to assign to the Kusto cluster." + } + }, + "principalTenantId": { + "type": "string", + "metadata": { + "description": "Principal tenant ID." + } + }, + "principalAssignmentName": { + "type": "string", + "metadata": { + "description": "Stable principal assignment name." + } + } + }, + "resources": [ + { + "type": "Microsoft.Kusto/clusters/principalAssignments", + "apiVersion": "2024-04-13", + "name": "[format('{0}/{1}', parameters('clusterName'), parameters('principalAssignmentName'))]", + "properties": { + "principalId": "[parameters('principalApplicationId')]", + "principalType": "App", + "role": "AllDatabasesViewer", + "tenantId": "[parameters('principalTenantId')]" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "apply-extras", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "agentName": { + "value": "[parameters('agentName')]" + }, + "agentEndpoint": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "subscriptionId": { + "value": "[subscription().subscriptionId]" + }, + "recipePackageUri": { + "value": "[parameters('recipePackageUri')]" + }, + "kustoConnectorUri": { + "value": "[parameters('finopsHubKustoConnectorUri')]" + }, + "forceUpdateTag": { + "value": "[parameters('forceUpdateTag')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "5168893811325309322" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for the deployment script resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "agentEndpoint": { + "type": "string", + "metadata": { + "description": "SRE Agent data-plane endpoint." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "Subscription that contains the SRE Agent." + } + }, + "recipePackageUri": { + "type": "string", + "metadata": { + "description": "Public URI for the generated SRE Agent recipe package." + } + }, + "kustoConnectorUri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional database-qualified Kusto connector URI." + } + }, + "forceUpdateTag": { + "type": "string", + "metadata": { + "description": "Forces the deployment script to run when the template is redeployed." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "$fxv#0": "# Copyright (c) Microsoft Corporation.\n# Licensed under the MIT License.\n\n$ErrorActionPreference = 'Stop'\n\nfunction Get-RequiredEnv($Name) {\n $value = [Environment]::GetEnvironmentVariable($Name)\n if ([string]::IsNullOrWhiteSpace($value)) {\n throw \"Missing required environment variable: $Name\"\n }\n return $value\n}\n\nfunction Get-OptionalEnv($Name) {\n return [Environment]::GetEnvironmentVariable($Name)\n}\n\nfunction ConvertTo-BodyJson($Value) {\n return ($Value | ConvertTo-Json -Depth 100 -Compress)\n}\n\nfunction Get-PropertyValue($Object, [string[]]$Names, $Default = '') {\n foreach ($name in $Names) {\n if ($null -ne $Object -and $Object.PSObject.Properties[$name] -and $null -ne $Object.$name) {\n return $Object.$name\n }\n }\n return $Default\n}\n\nfunction Get-HttpStatusCode($Exception) {\n if ($Exception.Response -and $Exception.Response.StatusCode) {\n return [int]$Exception.Response.StatusCode\n }\n return $null\n}\n\nfunction Invoke-WithRetry([scriptblock]$Action, [string]$Label, [int]$MaxAttempts = 5, [int]$DelaySeconds = 15) {\n for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {\n try {\n return & $Action\n }\n catch {\n $statusCode = Get-HttpStatusCode $_.Exception\n if ($statusCode -and $statusCode -notin @(401, 403, 408, 429, 500, 502, 503, 504)) {\n throw\n }\n if ($attempt -eq $MaxAttempts) {\n throw\n }\n Write-Output \"$Label attempt $attempt/$MaxAttempts failed: $($_.Exception.Message)\"\n Start-Sleep -Seconds $DelaySeconds\n }\n }\n}\n\nfunction Invoke-JsonRest([string]$Method, [string]$Uri, [string]$Token, $Body = $null) {\n $headers = @{\n Authorization = \"Bearer $Token\"\n 'Content-Type' = 'application/json'\n }\n $parameters = @{\n Method = $Method\n Uri = $Uri\n Headers = $headers\n }\n if ($null -ne $Body) {\n $parameters.Body = ConvertTo-BodyJson $Body\n }\n return Invoke-RestMethod @parameters\n}\n\nfunction Get-KnowledgeSourceName([string]$FileName) {\n $name = [IO.Path]::GetFileName($FileName).ToLowerInvariant() -replace '[^a-z0-9-]+', '-'\n $name = $name -replace '-+', '-'\n return $name.Trim('-')\n}\n\nfunction Get-Collection($Value) {\n if ($null -eq $Value) {\n return @()\n }\n return @($Value)\n}\n\nfunction Convert-TokenToString($Token) {\n if ($Token -is [Security.SecureString]) {\n $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token)\n try {\n return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)\n }\n finally {\n [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)\n }\n }\n return [string]$Token\n}\n\nfunction Get-ArmAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://management.azure.com/').Token\n}\n\nfunction Get-SreAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://azuresre.dev').Token\n}\n\n$subscriptionId = Get-RequiredEnv 'subscriptionId'\n$resourceGroupName = Get-RequiredEnv 'resourceGroupName'\n$agentName = Get-RequiredEnv 'agentName'\n$agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/')\n$recipePackageUri = Get-RequiredEnv 'recipePackageUri'\n$kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri'\n$armApiVersion = '2025-05-01-preview'\n$armBase = \"https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName\"\n\nWrite-Output 'Connecting with deployment script managed identity...'\nConnect-AzAccount -Identity | Out-Null\nSet-AzContext -Subscription $subscriptionId | Out-Null\n\n$workRoot = Join-Path $env:TEMP 'sre-agent-recipe'\n$zipPath = Join-Path $env:TEMP 'sre-agent-recipe.zip'\nRemove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue\nNew-Item -Path $workRoot -ItemType Directory -Force | Out-Null\n\nWrite-Output \"Downloading SRE Agent recipe package: $recipePackageUri\"\nInvoke-WithRetry -Label 'download recipe package' -Action {\n Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath\n} | Out-Null\nExpand-Archive -Path $zipPath -DestinationPath $workRoot -Force\n\n$extrasPath = Join-Path $workRoot 'extras.json'\nif (-not (Test-Path $extrasPath)) {\n throw \"Recipe package did not contain extras.json\"\n}\n\n$extras = Get-Content $extrasPath -Raw | ConvertFrom-Json -Depth 100\nWrite-Output \"Loaded recipe package from $extrasPath\"\n\nif ([string]::IsNullOrWhiteSpace($kustoConnectorUri)) {\n $extras.connectors = @(\n Get-Collection $extras.connectors | Where-Object {\n $type = Get-PropertyValue $_.properties @('dataConnectorType', 'type')\n $type -ine 'Kusto'\n }\n )\n}\nelse {\n foreach ($connector in Get-Collection $extras.connectors) {\n $type = Get-PropertyValue $connector.properties @('dataConnectorType', 'type')\n if ($type -ieq 'Kusto') {\n $connector.properties.dataSource = $kustoConnectorUri\n if (-not $connector.properties.PSObject.Properties['identity']) {\n $connector.properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n }\n }\n}\n\nfunction Invoke-ArmPutConnector([string]$Name, $Body) {\n $uri = \"$armBase/connectors/$Name`?api-version=$armApiVersion\"\n Invoke-WithRetry -Label \"ARM PUT connector $Name\" -Action {\n Invoke-JsonRest -Method PUT -Uri $uri -Token (Get-ArmAccessTokenString) -Body $Body\n } | Out-Null\n Write-Output \" ARM PUT connectors/${Name}: ok\"\n}\n\nfunction Invoke-SreApi([string]$Method, [string]$Path, $Body = $null) {\n $uri = \"$agentEndpoint$Path\"\n return Invoke-WithRetry -Label \"$Method $Path\" -MaxAttempts 21 -DelaySeconds 30 -Action {\n Invoke-JsonRest -Method $Method -Uri $uri -Token (Get-SreAccessTokenString) -Body $Body\n }\n}\n\nfunction Invoke-ExtendedPut([string]$Kind, [string]$Name, [string]$Type, $Properties) {\n $encodedName = [Uri]::EscapeDataString($Name)\n $body = @{\n name = $Name\n type = $Type\n tags = @()\n properties = $Properties\n }\n Invoke-SreApi -Method PUT -Path \"/api/v2/extendedAgent/$Kind/$encodedName\" -Body $body | Out-Null\n Write-Output \" PUT $Kind/${Name}: ok\"\n}\n\nWrite-Output 'Step 1/7: Applying connectors...'\nforeach ($connector in Get-Collection $extras.connectors) {\n $name = [string]$connector.name\n $properties = $connector.properties\n if (-not $properties.PSObject.Properties['identity']) {\n $properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n Invoke-ArmPutConnector -Name $name -Body @{ properties = $properties }\n}\n\nWrite-Output 'Step 2/7: Configuring built-in tools...'\n$overrides = Get-Collection $extras.builtInTools.overrides\nif ($overrides.Count -gt 0) {\n $body = @{\n overrides = @($overrides | ForEach-Object {\n @{\n name = $_.name\n enabled = [bool]$_.enabled\n }\n })\n }\n Invoke-SreApi -Method POST -Path '/api/v2/agent/tools/configure' -Body $body | Out-Null\n Write-Output \" built-in tools configured: $($overrides.Count) overrides\"\n}\n\nWrite-Output 'Step 3/7: Uploading knowledge sources...'\nforeach ($item in Get-Collection $extras.knowledgeItems) {\n $sourceName = Get-KnowledgeSourceName ([string]$item.name)\n $bytes = [Text.Encoding]::UTF8.GetBytes([string]$item.content)\n $body = @{\n properties = @{\n dataConnectorType = 'KnowledgeFile'\n dataSource = $sourceName\n extendedProperties = @{\n displayName = [string]$item.name\n fileName = [string]$item.name\n fileContent = [Convert]::ToBase64String($bytes)\n contentType = [string](Get-PropertyValue $item @('contentType') 'application/octet-stream')\n }\n }\n }\n Invoke-ArmPutConnector -Name $sourceName -Body $body\n Start-Sleep -Seconds 5\n}\n\nWrite-Output 'Step 4/7: Applying tools...'\nforeach ($tool in Get-Collection $extras.tools) {\n $name = [string]$tool.metadata.name\n $properties = $tool.spec\n if ($properties.type -eq 'PythonTool') {\n $properties.type = 'PythonFunctionTool'\n }\n Invoke-ExtendedPut -Kind 'tools' -Name $name -Type 'ExtendedAgentTool' -Properties $properties\n}\n\nWrite-Output 'Step 5/7: Applying skills...'\nforeach ($skill in Get-Collection $extras.skills) {\n $name = [string]$skill.metadata.name\n $tools = @()\n if ($skill.metadata.spec -and $skill.metadata.spec.tools) {\n $tools = Get-Collection $skill.metadata.spec.tools\n }\n $properties = @{\n name = $name\n description = [string](Get-PropertyValue $skill.metadata @('description'))\n tools = $tools\n skillContent = [string](Get-PropertyValue $skill @('skillContent'))\n additionalFiles = @()\n }\n Invoke-ExtendedPut -Kind 'skills' -Name $name -Type 'Skill' -Properties $properties\n}\n\nWrite-Output 'Step 6/7: Applying subagents...'\nforeach ($subagent in Get-Collection $extras.subagents) {\n $name = [string]$subagent.metadata.name\n Invoke-ExtendedPut -Kind 'agents' -Name $name -Type 'ExtendedAgent' -Properties $subagent.spec\n}\n\nWrite-Output 'Step 7/7: Applying scheduled tasks...'\n$scheduledTasks = Get-Collection $extras.scheduledTasks\nif ($scheduledTasks.Count -gt 0) {\n $existing = Invoke-SreApi -Method GET -Path '/api/v1/scheduledtasks'\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n foreach ($match in (Get-Collection $existing | Where-Object { $_.name -eq $name })) {\n if ($match.id) {\n Invoke-SreApi -Method DELETE -Path \"/api/v1/scheduledtasks/$($match.id)\" | Out-Null\n Write-Output \" deleted existing scheduledtasks/$name\"\n }\n }\n }\n\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n $spec = $task.spec\n $properties = @{\n name = [string](Get-PropertyValue $spec @('name') $name)\n description = [string](Get-PropertyValue $spec @('description'))\n cronExpression = [string](Get-PropertyValue $spec @('schedule', 'cronExpression', 'cron_expression'))\n agentPrompt = [string](Get-PropertyValue $spec @('prompt', 'agentPrompt', 'agent_prompt'))\n agentMode = [string](Get-PropertyValue $spec @('mode', 'agentMode', 'agent_mode') 'Review')\n isEnabled = [bool](Get-PropertyValue $spec @('enabled') $true)\n agent = [string](Get-PropertyValue $spec @('agent'))\n }\n Invoke-ExtendedPut -Kind 'scheduledtasks' -Name $name -Type 'ScheduledTask' -Properties $properties\n }\n}\n\nWrite-Output 'SRE Agent extras complete.'\n", + "identityName": "[format('id-sre-apply-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", + "scriptName": "[format('apply-sre-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", + "sreAgentAdminRoleId": "e79298df-d852-4c6d-84f9-5d13249d1e55" + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[variables('identityName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/agents', parameters('agentName'))]", + "name": "[guid(resourceId('Microsoft.App/agents', parameters('agentName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), variables('sreAgentAdminRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('sreAgentAdminRoleId'))]", + "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), '2023-01-31').principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]" + ] + }, + { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[variables('scriptName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "AzurePowerShell", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')))]": {} + } + }, + "properties": { + "azPowerShellVersion": "11.0", + "retentionInterval": "PT1H", + "cleanupPreference": "OnSuccess", + "timeout": "PT2H", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "scriptContent": "[variables('$fxv#0')]", + "environmentVariables": [ + { + "name": "subscriptionId", + "value": "[parameters('subscriptionId')]" + }, + { + "name": "resourceGroupName", + "value": "[resourceGroup().name]" + }, + { + "name": "agentName", + "value": "[parameters('agentName')]" + }, + { + "name": "agentEndpoint", + "value": "[parameters('agentEndpoint')]" + }, + { + "name": "recipePackageUri", + "value": "[parameters('recipePackageUri')]" + }, + { + "name": "kustoConnectorUri", + "value": "[parameters('kustoConnectorUri')]" + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]", + "[extensionResourceId(resourceId('Microsoft.App/agents', parameters('agentName')), 'Microsoft.Authorization/roleAssignments', guid(resourceId('Microsoft.App/agents', parameters('agentName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), variables('sreAgentAdminRoleId')))]" + ] + } + ], + "outputs": { + "identityName": { + "type": "string", + "value": "[variables('identityName')]" + }, + "scriptName": { + "type": "string", + "value": "[variables('scriptName')]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]", + "targetRbac" + ] + } + ], + "outputs": { + "AZURE_RESOURCE_GROUP": { + "type": "string", + "value": "[parameters('resourceGroupName')]" + }, + "AZURE_LOCATION": { + "type": "string", + "value": "[parameters('location')]" + }, + "SRE_AGENT_NAME": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentName.value]" + }, + "SRE_AGENT_ENDPOINT": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "AGENT_PORTAL_URL": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPortalUrl.value]" + }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "SYSTEM_MANAGED_IDENTITY_TENANT_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentTenantId.value]" + }, + "LOG_ANALYTICS_WORKSPACE_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.logAnalyticsWorkspaceId.value]" + }, + "APPLY_EXTRAS_SCRIPT": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'apply-extras'), '2025-04-01').outputs.scriptName.value]" + } + } +} \ No newline at end of file diff --git a/docs/deploy/sre-agent/14.0/createUiDefinition.json b/docs/deploy/sre-agent/14.0/createUiDefinition.json new file mode 100644 index 000000000..87e82bcaa --- /dev/null +++ b/docs/deploy/sre-agent/14.0/createUiDefinition.json @@ -0,0 +1,169 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#", + "handler": "Microsoft.Azure.CreateUIDef", + "version": "0.1.2-preview", + "parameters": { + "config": { + "basics": { + "description": "Deploy Azure SRE Agent with the FinOps toolkit recipe for FinOps hub analysis, capacity monitoring, scheduled tasks, and specialist agents.", + "location": { + "label": "Location", + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ] + } + } + }, + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ], + "basics": [ + { + "name": "resourceGroupName", + "type": "Microsoft.Common.TextBox", + "label": "Agent resource group", + "defaultValue": "finops-hub-sre", + "toolTip": "Resource group that will contain the Azure SRE Agent, monitoring resources, and deployment script identity.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9._()\\-]{1,90}$", + "validationMessage": "Enter a valid Azure resource group name." + }, + "visible": true + }, + { + "name": "agentName", + "type": "Microsoft.Common.TextBox", + "label": "Agent name", + "defaultValue": "finops-hub-sre", + "toolTip": "Name of the Azure SRE Agent resource.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9][a-zA-Z0-9\\-]{1,61}[a-zA-Z0-9]$", + "validationMessage": "Name must be 3-63 characters and can contain letters, numbers, and hyphens. The first and last characters must be alphanumeric." + }, + "visible": true + } + ], + "steps": [ + { + "name": "configuration", + "label": "Configuration", + "elements": [ + { + "name": "finopsHubKustoConnectorUri", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto URI", + "defaultValue": "", + "toolTip": "Optional database-qualified Azure Data Explorer URI for the FinOps hub. Example: https://cluster.region.kusto.windows.net/Hub", + "constraints": { + "required": false, + "regex": "^$|^https://.+\\.kusto\\.windows\\.net/.+", + "validationMessage": "Enter a database-qualified Kusto URI such as https://cluster.region.kusto.windows.net/Hub, or leave blank." + }, + "visible": true + }, + { + "name": "finopsHubKustoClusterResourceId", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto cluster resource ID", + "defaultValue": "", + "toolTip": "Optional Azure Data Explorer cluster resource ID. Provide this to assign the agent managed identity AllDatabasesViewer on the cluster.", + "constraints": { + "required": false, + "regex": "^$|^/subscriptions/.+/resourceGroups/.+/providers/Microsoft\\.Kusto/clusters/.+", + "validationMessage": "Enter a valid Microsoft.Kusto/clusters resource ID, or leave blank." + }, + "visible": true + }, + { + "name": "targetResourceGroups", + "type": "Microsoft.Common.TextBox", + "label": "Additional target resource groups", + "defaultValue": "", + "toolTip": "Optional comma-separated resource group names the agent can observe or act on. The agent resource group is always included.", + "constraints": { + "required": false, + "regex": "^$|^[A-Za-z0-9_.()\\-]+(\\s*,\\s*[A-Za-z0-9_.()\\-]+)*$", + "validationMessage": "Enter a comma-separated list of resource group names without blank entries or trailing commas." + }, + "visible": true + }, + { + "name": "accessLevel", + "type": "Microsoft.Common.OptionsGroup", + "label": "Access level", + "defaultValue": "High", + "toolTip": "High adds Contributor on target resource groups for autonomous remediation workflows. Low grants read-only monitoring roles.", + "constraints": { + "allowedValues": [ + { + "label": "High", + "value": "High" + }, + { + "label": "Low", + "value": "Low" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "actionMode", + "type": "Microsoft.Common.OptionsGroup", + "label": "Action mode", + "defaultValue": "autonomous", + "toolTip": "Review requires approval before write actions. Autonomous lets the agent run enabled actions within its assigned access.", + "constraints": { + "allowedValues": [ + { + "label": "Autonomous", + "value": "autonomous" + }, + { + "label": "Review", + "value": "review" + }, + { + "label": "Read only", + "value": "readOnly" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "enableSubscriptionReaderRole", + "type": "Microsoft.Common.CheckBox", + "label": "Grant subscription Reader to the agent", + "toolTip": "Recommended. Grants the agent managed identity Reader on the deployment subscription for inventory, Resource Graph, capacity, quota, and monitoring coverage workflows.", + "defaultValue": true, + "visible": true + } + ] + } + ], + "outputs": { + "resourceGroupName": "[basics('resourceGroupName')]", + "agentName": "[basics('agentName')]", + "location": "[location()]", + "targetResourceGroupNames": "[steps('configuration').targetResourceGroups]", + "finopsHubKustoConnectorUri": "[steps('configuration').finopsHubKustoConnectorUri]", + "finopsHubKustoClusterResourceId": "[steps('configuration').finopsHubKustoClusterResourceId]", + "accessLevel": "[steps('configuration').accessLevel]", + "actionMode": "[steps('configuration').actionMode]", + "enableSubscriptionReaderRole": "[steps('configuration').enableSubscriptionReaderRole]" + } + } +} diff --git a/docs/deploy/sre-agent/14.0/sre-agent-recipe.zip b/docs/deploy/sre-agent/14.0/sre-agent-recipe.zip new file mode 100644 index 0000000000000000000000000000000000000000..159ae7454137f5096b46f48672aeefb4b3f4c11f GIT binary patch literal 346636 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%0A)e)d3rs&)|sg|KHplPj~#pU_9+m5qE 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 z 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%0D6D`-ZdASrQP9OimVrY6mqmXI2owz@k-Eo#;# zn03z$MGL%}xoN4r#kD&o?ARbJOcm6l*Yyv%Pi3QoYdGurPYU_*V2V2!Z|poUCi-Gj!oZZ=xoA zsFgY8BHDsDHvzurS7>@ysuL4AUa6NxWG!2ZnF_XbtWc@;HLt2|X+s37T&?n&Bcu;T zmYRM9=qpo``5gA^QqvC+y$v;7V#|)SAJFqJ!Bh>%eoIsVxt8gPSFLxYn#D^ysIg5p zEz}k9Z`OfFUzM7Ug}O2|{Rq+<<(p+p(@og6Le%K(bxi@a1i0l5gaWmw*`#cCQzH?p zH{dX9coH4{^fuJE+%m?rzB%uF2aNUAskyPZtqvsYt5dV9k992?PYZy$rQLCZ$kDJH zDo-mTyMu47EKp$8NA3 z+kTse`@aw30fv*az`@nJbOs>`2?}gZ_cGPc7Unt#JFanQc;L>{a^VojZ4E z@m$Q#_6ae&CBtl=>ats!%l1huyCtw}AB4PH0CM0CzaC@~WPvRpU4n74aavFM@ql}P zFcW!9=}Kies$>S}>-K@I4foX*gIc!_65TC8bo=nn-9kUN5A576sB`;}&E3K^Lsw?M z%-iS2oW#=anm1ZIPUJgXJB~=dYx!GbaBfwDvj+NODrTFmhRb|er-Fe`#(7t14~F}$ za≺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 z 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 aZcs}F1^@s6009620672v0KG{C0002qu>Iu# literal 0 HcmV?d00001 diff --git a/src/scripts/Build-SreAgentTemplate.ps1 b/src/scripts/Build-SreAgentTemplate.ps1 new file mode 100644 index 000000000..8c2c2a5e2 --- /dev/null +++ b/src/scripts/Build-SreAgentTemplate.ps1 @@ -0,0 +1,47 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<# + .SYNOPSIS + Builds the SRE Agent recipe package used by the portal deployment template. + + .PARAMETER DestDir + Release directory for the copied sre-agent template. +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)][string]$DestDir +) + +$templateRoot = Resolve-Path "$PSScriptRoot/../templates/sre-agent" +$recipeDir = Join-Path $templateRoot "recipes/finops-hub" +$builder = Join-Path $templateRoot "bin/build-extras.py" +$assetsDir = Join-Path $DestDir "assets" +$workDir = Join-Path $assetsDir "sre-agent-recipe" +$extrasPath = Join-Path $workDir "extras.json" +$packagePath = Join-Path $assetsDir "sre-agent-recipe.zip" +$placeholderKustoUri = "https://placeholder.eastus2.kusto.windows.net/Hub" + +if (-not (Get-Command python3 -ErrorAction SilentlyContinue)) +{ + throw "python3 is required to build the SRE Agent recipe package." +} + +& "$PSScriptRoot/New-Directory.ps1" $assetsDir +Remove-Item $workDir -Recurse -Force -ErrorAction SilentlyContinue +& "$PSScriptRoot/New-Directory.ps1" $workDir + +Write-Host " Building SRE Agent recipe package..." +$summary = python3 $builder --recipe $recipeDir --output $extrasPath --kusto-connector-uri $placeholderKustoUri +if (-not $?) +{ + throw "Failed to build SRE Agent extras manifest." +} + +Write-Verbose " SRE Agent extras summary: $summary" +Remove-Item $packagePath -Force -ErrorAction SilentlyContinue +Compress-Archive -Path "$workDir/*" -DestinationPath $packagePath -Force +Remove-Item $workDir -Recurse -Force + +Write-Host " Created assets/sre-agent-recipe.zip" diff --git a/src/scripts/Build-Toolkit.ps1 b/src/scripts/Build-Toolkit.ps1 index cfa992eb6..dfd7e336e 100644 --- a/src/scripts/Build-Toolkit.ps1 +++ b/src/scripts/Build-Toolkit.ps1 @@ -193,17 +193,15 @@ $templates | ForEach-Object { # Create target directory $destDir = "$outdir/$templateName" Write-Verbose " Creating target directory: $destDir" - Remove-Item $destDir -Recurse -ErrorAction SilentlyContinue + Remove-Item $destDir -Recurse -Force -ErrorAction SilentlyContinue & "$PSScriptRoot/New-Directory.ps1" $destDir # Copy required files Write-Host " Copying files..." - $sourceFiles = Get-ChildItem $srcDir -Force | Where-Object { $_.Name -notin @(".build.config", ".buildignore", "scaffold.json") } + $sourceFiles = Get-ChildItem $srcDir | Where-Object { $_.Name -notin @(".build.config", ".buildignore", "scaffold.json") } Write-Verbose " Copying $($sourceFiles.Count) items from source to destination" $sourceFiles | Copy-Item -Destination $destDir -Recurse - Get-ChildItem $destDir -Force -Recurse -Filter ".DS_Store" | Remove-Item -Force - # Run custom build scripts after copying files (operates on release copy, not source) if ($buildConfig.scripts.Count -gt 0) { diff --git a/src/templates/sre-agent/.build.config b/src/templates/sre-agent/.build.config new file mode 100644 index 000000000..ac067ed9b --- /dev/null +++ b/src/templates/sre-agent/.build.config @@ -0,0 +1,9 @@ +{ + "scripts": [ + "Build-SreAgentTemplate.ps1" + ], + "ignore": [ + "bin/__pycache__", + "submodules" + ] +} diff --git a/src/templates/sre-agent/bin/apply-extras.sh b/src/templates/sre-agent/bin/apply-extras.sh new file mode 100755 index 000000000..c90365b0c --- /dev/null +++ b/src/templates/sre-agent/bin/apply-extras.sh @@ -0,0 +1,581 @@ +#!/usr/bin/env bash +# ============================================================================= +# apply-extras.sh - Apply non-Bicep SRE Agent recipe assets +# +# Follows the microsoft/sre-agent template pattern: Bicep deploys the ARM +# resource, then this script applies connectors, KnowledgeFile sources, skills, +# subagents, tools, and scheduled tasks through the supported ARM/data-plane +# surfaces. +# ============================================================================= + +set -euo pipefail + +usage() { + cat < --subscription --resource-group --name --recipe

--build-dir [options] + +Required: + --endpoint SRE Agent endpoint + --subscription Azure subscription that contains the SRE Agent + --resource-group Resource group that contains the SRE Agent + --name SRE Agent name + --recipe Recipe directory + --build-dir Working directory for generated extras and request files + +Optional: + --kusto-connector-uri Database-qualified Kusto connector URI + --dry-run Build extras and request payloads without Azure calls + -h, --help Show this help +EOF + exit "${1:-0}" +} + +fail() { + echo "$1" >&2 + exit "${2:-1}" +} + +require_value() { + local flag="$1" + local value="${2:-}" + if [[ -z "$value" || "$value" == -* ]]; then + fail "Error: flag ${flag} requires a value" 2 + fi +} + +safe_name() { + printf '%s' "$1" | tr '/:' '__' | tr -cd 'A-Za-z0-9._-' +} + +urlencode() { + printf '%s' "$1" | jq -sRr @uri +} + +knowledge_source_name() { + basename "$1" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9-]+/-/g; s/-+/-/g; s/^-//; s/-$//' +} + +get_sre_token() { + az account get-access-token --resource https://azuresre.dev --query accessToken -o tsv 2>/dev/null +} + +ENDPOINT="" +SUBSCRIPTION_ID="" +RESOURCE_GROUP="" +AGENT_NAME="" +RECIPE_DIR="" +BUILD_DIR="" +KUSTO_CONNECTOR_URI="" +DRY_RUN="" +ARM_API_VERSION="2025-05-01-preview" +REQUEST_DELAY_SECONDS="${SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS:-15}" +RETRY_DELAY_SECONDS="${SRE_AGENT_APPLY_RETRY_DELAY_SECONDS:-15}" + +while [[ $# -gt 0 ]]; do + case "$1" in + --endpoint) + require_value "--endpoint" "${2:-}" + ENDPOINT="$2" + shift 2 + ;; + --subscription) + require_value "--subscription" "${2:-}" + SUBSCRIPTION_ID="$2" + shift 2 + ;; + --resource-group) + require_value "--resource-group" "${2:-}" + RESOURCE_GROUP="$2" + shift 2 + ;; + --name) + require_value "--name" "${2:-}" + AGENT_NAME="$2" + shift 2 + ;; + --recipe) + require_value "--recipe" "${2:-}" + RECIPE_DIR="$2" + shift 2 + ;; + --build-dir) + require_value "--build-dir" "${2:-}" + BUILD_DIR="$2" + shift 2 + ;; + --kusto-connector-uri) + require_value "--kusto-connector-uri" "${2:-}" + KUSTO_CONNECTOR_URI="$2" + shift 2 + ;; + --dry-run) + DRY_RUN="true" + shift + ;; + -h|--help) + usage 0 + ;; + *) + fail "Error: unknown argument '$1'" 2 + ;; + esac +done + +[[ -n "$ENDPOINT" ]] || fail "Error: --endpoint is required" 2 +[[ -n "$SUBSCRIPTION_ID" ]] || fail "Error: --subscription is required" 2 +[[ -n "$RESOURCE_GROUP" ]] || fail "Error: --resource-group is required" 2 +[[ -n "$AGENT_NAME" ]] || fail "Error: --name is required" 2 +[[ -n "$RECIPE_DIR" ]] || fail "Error: --recipe is required" 2 +[[ -n "$BUILD_DIR" ]] || fail "Error: --build-dir is required" 2 +[[ -d "$RECIPE_DIR" ]] || fail "Error: recipe directory not found: $RECIPE_DIR" 1 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +RECIPE_DIR="$(cd "$RECIPE_DIR" && pwd)" +mkdir -p "$BUILD_DIR" +BUILD_DIR="$(cd "$BUILD_DIR" && pwd)" +EXTRAS_FILE="${BUILD_DIR}/extras.json" +REQUEST_DIR="${BUILD_DIR}/requests" +RESPONSE_DIR="${BUILD_DIR}/responses" +ARM_BASE="https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.App/agents/${AGENT_NAME}" + +command -v jq >/dev/null || fail "jq is required" 1 +command -v base64 >/dev/null || fail "base64 is required" 1 + +PYTHON_CMD="" +if command -v python3 >/dev/null; then + PYTHON_CMD="python3" +elif command -v python >/dev/null && python --version 2>&1 | grep -q "Python 3"; then + PYTHON_CMD="python" +else + fail "Python 3 is required" 1 +fi + +"$PYTHON_CMD" -c "import yaml" 2>/dev/null || fail "PyYAML is required to build extras. Install with: pip install pyyaml" 1 + +mkdir -p "$REQUEST_DIR" "$RESPONSE_DIR" + +echo "" +echo "=============================================" +echo " SRE Agent - Apply Extras" +echo "=============================================" +echo "" +echo "Agent endpoint: $ENDPOINT" +echo "Recipe: $RECIPE_DIR" +echo "Build dir: $BUILD_DIR" +echo "" + +echo "Step 1/8: Building extras manifest..." +SUMMARY_JSON="$("$PYTHON_CMD" "${SCRIPT_DIR}/build-extras.py" \ + --recipe "$RECIPE_DIR" \ + --output "$EXTRAS_FILE" \ + --kusto-connector-uri "$KUSTO_CONNECTOR_URI")" +echo " extras: $EXTRAS_FILE" +echo " summary: $SUMMARY_JSON" +echo "" + +if [[ -z "$DRY_RUN" ]]; then + command -v az >/dev/null || fail "az is required to apply extras" 1 + command -v curl >/dev/null || fail "curl is required to apply extras" 1 + az account set --subscription "$SUBSCRIPTION_ID" >/dev/null + DP_TOKEN="$(get_sre_token)" + [[ -n "$DP_TOKEN" ]] || fail "Error: failed to get Azure SRE Agent bearer token. Run: az login --scope https://azuresre.dev/.default" 1 +else + DP_TOKEN="dry-run" + echo "Dry run enabled. Azure control-plane and data-plane calls will be skipped." + echo "" +fi + +arm_put_connector() { + local name="$1" + local body_json="$2" + local safe + local body_file + local response_file + local result + + safe="$(safe_name "$name")" + body_file="${REQUEST_DIR}/arm-connectors/${safe}.json" + response_file="${RESPONSE_DIR}/arm-connectors/${safe}.json" + mkdir -p "$(dirname "$body_file")" "$(dirname "$response_file")" + printf '%s\n' "$body_json" > "$body_file" + + if [[ -n "$DRY_RUN" ]]; then + echo " dry-run ARM PUT connectors/${name} -> $body_file" + return 0 + fi + + for attempt in 1 2 3 4 5; do + if result="$(az rest -m PUT \ + --url "${ARM_BASE}/connectors/${name}?api-version=${ARM_API_VERSION}" \ + --body "@${body_file}" \ + --headers "Content-Type=application/json" \ + -o json 2>&1)"; then + printf '%s\n' "$result" > "$response_file" + echo " ARM PUT connectors/${name}: ok" + return 0 + fi + + printf '%s\n' "$result" > "$response_file" + echo " ARM PUT connectors/${name}: attempt ${attempt}/5 failed" + [[ "$attempt" != "5" ]] && sleep "$RETRY_DELAY_SECONDS" + done + + sed -n '1,120p' "$response_file" >&2 || true + fail "Failed to apply connector ${name}" 1 +} + +dataplane_put_extended() { + local kind="$1" + local name="$2" + local type="$3" + local tags_json="$4" + local props_json="$5" + local safe + local body_file + local response_file + local body + local http_code + local encoded_name + + safe="$(safe_name "$name")" + body_file="${REQUEST_DIR}/dataplane-${kind}/${safe}.json" + response_file="${RESPONSE_DIR}/dataplane-${kind}/${safe}.json" + mkdir -p "$(dirname "$body_file")" "$(dirname "$response_file")" + body="$(jq -nc --arg name "$name" --arg type "$type" --argjson tags "$tags_json" --argjson properties "$props_json" \ + '{name: $name, type: $type, tags: $tags, properties: $properties}')" + printf '%s\n' "$body" > "$body_file" + + if [[ -n "$DRY_RUN" ]]; then + echo " dry-run PUT ${kind}/${name} -> $body_file" + return 0 + fi + + encoded_name="$(urlencode "$name")" + for attempt in 1 2 3 4 5; do + if http_code="$(curl -sS -o "$response_file" -w "%{http_code}" \ + -X PUT "${ENDPOINT}/api/v2/extendedAgent/${kind}/${encoded_name}" \ + -H "Authorization: Bearer ${DP_TOKEN}" \ + -H "Content-Type: application/json" \ + --data-binary "@${body_file}")"; then + : + else + http_code="000" + fi + + case "$http_code" in + 200|201|202|204) + echo " PUT ${kind}/${name}: ok" + return 0 + ;; + esac + + echo " PUT ${kind}/${name}: attempt ${attempt}/5 returned HTTP ${http_code}" + [[ "$attempt" != "5" ]] && sleep "$RETRY_DELAY_SECONDS" + done + + sed -n '1,120p' "$response_file" >&2 || true + fail "Failed to apply ${kind}/${name}" 1 +} + +apply_built_in_tools_config() { + local config_json + local override_count + local body_file="${REQUEST_DIR}/built-in-tools/configure.json" + local response_file="${RESPONSE_DIR}/built-in-tools/configure.json" + local http_code + + config_json="$(jq -c '.builtInTools // {"overrides":[]}' "$EXTRAS_FILE")" + override_count="$(jq -r '.overrides | length' <<< "$config_json")" + [[ "$override_count" != "0" ]] || { + echo " built-in tools: no overrides" + return 0 + } + + mkdir -p "$(dirname "$body_file")" "$(dirname "$response_file")" + jq '{overrides: [.overrides[] | {name, enabled}]}' <<< "$config_json" > "$body_file" + + if [[ -n "$DRY_RUN" ]]; then + echo " dry-run POST agent/tools/configure -> $body_file" + return 0 + fi + + for attempt in 1 2 3 4 5; do + if http_code="$(curl -sS -o "$response_file" -w "%{http_code}" \ + -X POST "${ENDPOINT}/api/v2/agent/tools/configure" \ + -H "Authorization: Bearer ${DP_TOKEN}" \ + -H "Content-Type: application/json" \ + --data-binary "@${body_file}")"; then + : + else + http_code="000" + fi + + case "$http_code" in + 200|201|202|204) + echo " built-in tools configured: ${override_count} overrides" + return 0 + ;; + esac + + echo " built-in tools: attempt ${attempt}/5 returned HTTP ${http_code}" + [[ "$attempt" != "5" ]] && sleep "$RETRY_DELAY_SECONDS" + done + + sed -n '1,120p' "$response_file" >&2 || true + fail "Failed to configure built-in tools" 1 +} + +delete_existing_scheduled_tasks() { + local count + local response_file="${RESPONSE_DIR}/scheduledtasks.existing.json" + local name + local ids + local id + local http_code + local deleted=0 + + count="$(jq '.scheduledTasks // [] | length' "$EXTRAS_FILE")" + [[ "$count" -gt 0 ]] || return 0 + + if [[ -n "$DRY_RUN" ]]; then + echo " dry-run scheduled-task cleanup: ${count} task name(s)" + return 0 + fi + + if http_code="$(curl -sS -o "$response_file" -w "%{http_code}" \ + "${ENDPOINT}/api/v1/scheduledtasks" \ + -H "Authorization: Bearer ${DP_TOKEN}")"; then + : + else + http_code="000" + fi + [[ "$http_code" == "200" ]] || fail "Failed to list existing scheduled tasks before apply (HTTP ${http_code})" 1 + + for i in $(seq 0 $((count - 1))); do + name="$(jq -r --argjson index "$i" '.scheduledTasks[$index].metadata.name' "$EXTRAS_FILE")" + ids="$(jq -r --arg name "$name" '.[]? | select(.name == $name) | .id // empty' "$response_file" 2>/dev/null || true)" + while IFS= read -r id; do + [[ -n "$id" ]] || continue + if curl -sS -o /dev/null -X DELETE "${ENDPOINT}/api/v1/scheduledtasks/${id}" -H "Authorization: Bearer ${DP_TOKEN}"; then + echo " deleted existing scheduled-task ${name} (${id})" + deleted=$((deleted + 1)) + else + fail "Failed to delete existing scheduled-task ${name} (${id})" 1 + fi + done <<< "$ids" + done + + [[ "$deleted" -eq 0 ]] || echo " scheduled-task cleanup: ${deleted} existing deleted" +} + +verify_knowledge_docs() { + local expected_docs=("$@") + local response_file="${RESPONSE_DIR}/knowledge-sources/list.json" + local detail_file + local doc + local source_name + local entry + local indexed + local reason + local missing + local unindexed + local http_code + + [[ "${#expected_docs[@]}" -gt 0 ]] || return 0 + [[ -z "$DRY_RUN" ]] || { + echo " dry-run knowledge verification skipped" + return 0 + } + + mkdir -p "$(dirname "$response_file")" + echo " waiting for knowledge sources to index..." + for attempt in $(seq 1 20); do + if http_code="$(curl -sS -o "$response_file" -w "%{http_code}" \ + "${ENDPOINT}/api/v2/extendedAgent/connectors" \ + -H "Authorization: Bearer ${DP_TOKEN}")"; then + : + else + http_code="000" + fi + + missing=0 + unindexed=0 + if [[ "$http_code" == "200" ]]; then + for doc in "${expected_docs[@]}"; do + source_name="$(knowledge_source_name "$doc")" + entry="$(jq -c --arg name "$source_name" '[.value[]? | select(.name == $name and .properties.dataConnectorType == "KnowledgeFile")][0] // empty' "$response_file" 2>/dev/null || true)" + if [[ -z "$entry" ]]; then + missing=$((missing + 1)) + continue + fi + + detail_file="${RESPONSE_DIR}/knowledge-sources/${source_name}.json" + if http_code="$(curl -sS -o "$detail_file" -w "%{http_code}" \ + "${ENDPOINT}/api/v2/extendedAgent/connectors/${source_name}" \ + -H "Authorization: Bearer ${DP_TOKEN}")"; then + : + else + http_code="000" + fi + + indexed="$(jq -r '.properties.extendedProperties.createdAt // empty' "$detail_file" 2>/dev/null || true)" + [[ -n "$indexed" ]] || unindexed=$((unindexed + 1)) + done + + if [[ "$missing" -eq 0 && "$unindexed" -eq 0 ]]; then + echo " knowledge sources indexed: ${#expected_docs[@]} docs" + return 0 + fi + + echo " knowledge indexing attempt ${attempt}/20: ${missing} missing, ${unindexed} not indexed" + else + echo " knowledge indexing attempt ${attempt}/20: connectors returned HTTP ${http_code}" + fi + + [[ "$attempt" -lt 20 ]] && sleep "$RETRY_DELAY_SECONDS" + done + + echo " knowledge source status:" >&2 + for doc in "${expected_docs[@]}"; do + source_name="$(knowledge_source_name "$doc")" + detail_file="${RESPONSE_DIR}/knowledge-sources/${source_name}.json" + entry="$(jq -c --arg name "$source_name" '[.value[]? | select(.name == $name and .properties.dataConnectorType == "KnowledgeFile")][0] // empty' "$response_file" 2>/dev/null || true)" + if [[ -z "$entry" ]]; then + echo " ${doc}: missing" >&2 + else + indexed="$(jq -r '.properties.extendedProperties.createdAt // empty' "$detail_file" 2>/dev/null || true)" + reason="$(jq -r '.properties.extendedProperties.errorReason // ""' "$detail_file" 2>/dev/null || true)" + echo " ${doc}: indexed=${indexed}${reason:+ reason=${reason}}" >&2 + fi + done + fail "Knowledge sources failed to index" 1 +} + +echo "Step 2/8: Applying connectors..." +CONNECTOR_COUNT="$(jq '.connectors // [] | length' "$EXTRAS_FILE")" +if [[ "$CONNECTOR_COUNT" -gt 0 ]]; then + for i in $(seq 0 $((CONNECTOR_COUNT - 1))); do + name="$(jq -r --argjson index "$i" '.connectors[$index].name' "$EXTRAS_FILE")" + connector_type="$(jq -r --argjson index "$i" '.connectors[$index].properties.dataConnectorType // .connectors[$index].properties.type // ""' "$EXTRAS_FILE")" + connector_type_lower="$(printf '%s' "$connector_type" | tr '[:upper:]' '[:lower:]')" + if [[ "$connector_type_lower" == "mcp" ]]; then + jq -e --argjson index "$i" '.connectors[$index].properties.extendedProperties.type == "http" and (.connectors[$index].properties.extendedProperties.endpoint // "") != ""' "$EXTRAS_FILE" >/dev/null \ + || fail "Error: MCP connector ${name} must use properties.extendedProperties.type and endpoint" 1 + jq -e --argjson index "$i" '(.connectors[$index].properties.extendedProperties.headers? | type) != "object"' "$EXTRAS_FILE" >/dev/null \ + || fail "Error: MCP connector ${name} must flatten custom headers into properties.extendedProperties" 1 + fi + body="$(jq -c --argjson index "$i" '{properties: (.connectors[$index].properties | if (.identity // "") == "" then . + {identity: "system"} else . end)}' "$EXTRAS_FILE")" + arm_put_connector "$name" "$body" + done +else + echo " connectors: none" +fi +echo "" + +echo "Step 3/8: Configuring built-in tools..." +apply_built_in_tools_config +echo "" + +echo "Step 4/8: Uploading knowledge sources..." +KNOWLEDGE_COUNT="$(jq '.knowledgeItems // [] | length' "$EXTRAS_FILE")" +KNOWLEDGE_DOC_NAMES=() +if [[ "$KNOWLEDGE_COUNT" -gt 0 ]]; then + for i in $(seq 0 $((KNOWLEDGE_COUNT - 1))); do + fname="$(jq -r --argjson index "$i" '.knowledgeItems[$index].name' "$EXTRAS_FILE")" + content_type="$(jq -r --argjson index "$i" '.knowledgeItems[$index].contentType // "application/octet-stream"' "$EXTRAS_FILE")" + source_name="$(knowledge_source_name "$fname")" + content_b64="$(jq -rj --argjson index "$i" '.knowledgeItems[$index].content' "$EXTRAS_FILE" | base64 | tr -d '\n')" + KNOWLEDGE_DOC_NAMES+=("$fname") + body="$(jq -nc \ + --arg dataSource "$source_name" \ + --arg displayName "$fname" \ + --arg fileName "$fname" \ + --arg fileContent "$content_b64" \ + --arg contentType "$content_type" \ + '{properties:{dataConnectorType:"KnowledgeFile",dataSource:$dataSource,extendedProperties:{displayName:$displayName,fileName:$fileName,fileContent:$fileContent,contentType:$contentType}}}')" + arm_put_connector "$source_name" "$body" + [[ -z "$DRY_RUN" && "$i" -lt $((KNOWLEDGE_COUNT - 1)) ]] && sleep "$REQUEST_DELAY_SECONDS" + done + verify_knowledge_docs "${KNOWLEDGE_DOC_NAMES[@]}" +else + echo " knowledge sources: none" +fi +echo "" + +echo "Step 5/8: Applying tools..." +TOOL_COUNT="$(jq '.tools // [] | length' "$EXTRAS_FILE")" +if [[ "$TOOL_COUNT" -gt 0 ]]; then + for i in $(seq 0 $((TOOL_COUNT - 1))); do + name="$(jq -r --argjson index "$i" '.tools[$index].metadata.name' "$EXTRAS_FILE")" + props="$(jq -c --argjson index "$i" ' + .tools[$index].spec + | if (.type // "") == "PythonTool" then .type = "PythonFunctionTool" else . end + ' "$EXTRAS_FILE")" + dataplane_put_extended "tools" "$name" "ExtendedAgentTool" "[]" "$props" + done +else + echo " tools: none" +fi +echo "" + +echo "Step 6/8: Applying skills..." +SKILL_COUNT="$(jq '.skills // [] | length' "$EXTRAS_FILE")" +if [[ "$SKILL_COUNT" -gt 0 ]]; then + for i in $(seq 0 $((SKILL_COUNT - 1))); do + name="$(jq -r --argjson index "$i" '.skills[$index].metadata.name' "$EXTRAS_FILE")" + props="$(jq -c --argjson index "$i" ' + { + name: .skills[$index].metadata.name, + description: (.skills[$index].metadata.description // ""), + tools: (.skills[$index].metadata.spec.tools // []), + skillContent: (.skills[$index].skillContent // ""), + additionalFiles: [] + }' "$EXTRAS_FILE")" + dataplane_put_extended "skills" "$name" "Skill" "[]" "$props" + done +else + echo " skills: none" +fi +echo "" + +echo "Step 7/8: Applying subagents..." +SUBAGENT_COUNT="$(jq '.subagents // [] | length' "$EXTRAS_FILE")" +if [[ "$SUBAGENT_COUNT" -gt 0 ]]; then + for i in $(seq 0 $((SUBAGENT_COUNT - 1))); do + name="$(jq -r --argjson index "$i" '.subagents[$index].metadata.name' "$EXTRAS_FILE")" + props="$(jq -c --argjson index "$i" '.subagents[$index].spec' "$EXTRAS_FILE")" + dataplane_put_extended "agents" "$name" "ExtendedAgent" "[]" "$props" + done +else + echo " subagents: none" +fi +echo "" + +echo "Step 8/8: Applying scheduled tasks..." +TASK_COUNT="$(jq '.scheduledTasks // [] | length' "$EXTRAS_FILE")" +if [[ "$TASK_COUNT" -gt 0 ]]; then + delete_existing_scheduled_tasks + for i in $(seq 0 $((TASK_COUNT - 1))); do + name="$(jq -r --argjson index "$i" '.scheduledTasks[$index].metadata.name' "$EXTRAS_FILE")" + props="$(jq -c --argjson index "$i" ' + .scheduledTasks[$index].spec as $spec | + { + name: ($spec.name // .scheduledTasks[$index].metadata.name // ""), + description: ($spec.description // ""), + cronExpression: ($spec.schedule // $spec.cronExpression // $spec.cron_expression // ""), + agentPrompt: ($spec.prompt // $spec.agentPrompt // $spec.agent_prompt // ""), + agentMode: ($spec.mode // $spec.agentMode // $spec.agent_mode // "Review"), + isEnabled: ($spec.enabled // true), + agent: ($spec.agent // "") + }' "$EXTRAS_FILE")" + dataplane_put_extended "scheduledtasks" "$name" "ScheduledTask" "[]" "$props" + done +else + echo " scheduled tasks: none" +fi +echo "" + +echo "=============================================" +echo " SRE Agent extras complete" +echo "=============================================" +echo "" diff --git a/src/templates/sre-agent/bin/check-prerequisites.sh b/src/templates/sre-agent/bin/check-prerequisites.sh new file mode 100755 index 000000000..2dd6b2566 --- /dev/null +++ b/src/templates/sre-agent/bin/check-prerequisites.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# check-prerequisites.sh — verify required tools are installed + +usage() { + cat <] + +Options: + --subscription Subscription to scope Azure CLI checks + -h, --help Show this help +EOF + exit "${1:-0}" +} + +check_prerequisites() { + local missing=0 + + for cmd in az curl git jq; do + if ! command -v "$cmd" &>/dev/null; then + echo " ❌ Missing: $cmd" >&2 + missing=$((missing + 1)) + fi + done + + if ! command -v python3 &>/dev/null && ! command -v python &>/dev/null; then + echo " ❌ Missing: python3 (needed for YAML processing)" >&2 + missing=$((missing + 1)) + else + local py=$(command -v python3 || command -v python) + if ! "$py" -c "import yaml" 2>/dev/null; then + echo " ❌ Missing: PyYAML — install: pip install pyyaml" >&2 + missing=$((missing + 1)) + fi + fi + + if [[ $missing -gt 0 ]]; then + echo " $missing prerequisite(s) missing. See README for install guide." >&2 + return 1 + fi + return 0 +} + +if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + SUBSCRIPTION_ID="" + while [[ $# -gt 0 ]]; do + case "$1" in + --subscription) + [[ -n "${2:-}" && "${2:-}" != -* ]] || { echo "Error: flag --subscription requires a value" >&2; exit 2; } + SUBSCRIPTION_ID="$2" + shift 2 + ;; + -h|--help) + usage 0 + ;; + *) + echo "Error: unexpected argument '$1'" >&2 + usage 2 + ;; + esac + done + + if [[ -n "$SUBSCRIPTION_ID" ]]; then + export AZURE_SUBSCRIPTION_ID="$SUBSCRIPTION_ID" + fi + + check_prerequisites +fi diff --git a/src/templates/sre-agent/bin/deploy.sh b/src/templates/sre-agent/bin/deploy.sh new file mode 100755 index 000000000..3b9a5f53c --- /dev/null +++ b/src/templates/sre-agent/bin/deploy.sh @@ -0,0 +1,558 @@ +#!/usr/bin/env bash +# ============================================================================= +# deploy.sh - FinOps Toolkit SRE Agent setup +# +# Copied from microsoft/sre-agent labs/starter-lab/scripts/setup.sh and updated +# for this template: +# - uses Azure CLI + Bicep directly, not azd +# - deploys the FinOps SRE Agent infrastructure only, not the Grubify lab app +# - applies non-Bicep recipe assets with apply-extras after ARM succeeds +# ============================================================================= + +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +INFRA_DIR="${PROJECT_DIR}/infra" + +usage() { + cat < [options] + +Required: + --recipe Recipe directory + --subscription Azure subscription + -g, --resource-group Resource group for the agent + -n, --name Agent name + -l, --location Azure region + +Optional: + --target-resource-group Repeatable target resource group. The agent resource group is always included. + --cluster-uri Kusto connector URI, including database name. + Example: https://..kusto.windows.net/Hub + --cluster-resource-id Optional Kusto cluster ARM resource ID. Real deployments resolve this from --cluster-uri when possible; dry-run requires it. + --no-subscription-reader Do not assign Reader at subscription scope. Default: assign Reader. + --deploy-name Deployment name override. Defaults to a deterministic name. + --dry-run Validate inputs and write parameters without Azure calls. + --force Accepted for compatibility. + --no-telemetry Accepted for compatibility. + -h, --help Show this help. +EOF + exit "${1:-0}" +} + +fail() { + echo -e "${RED}$1${NC}" >&2 + exit "${2:-1}" +} + +require_value() { + local flag="$1" + local value="${2:-}" + if [[ -z "$value" || "$value" == -* ]]; then + fail "Error: flag ${flag} requires a value" 2 + fi +} + +recipe_value() { + local file="$1" + local path="$2" + jq -r "$path // empty | if . == null or . == \"null\" then \"\" else . end" "$file" +} + +deterministic_deploy_name() { + "$PYTHON_CMD" - "$SUBSCRIPTION_ID" "$RESOURCE_GROUP" "$AGENT_NAME" <<'PY' +import hashlib +import re +import sys + +subscription_id, resource_group, agent_name = sys.argv[1:4] +resource_group_id = f"/subscriptions/{subscription_id}/resourceGroups/{resource_group}" +seed = f"{subscription_id}|{resource_group_id}|{agent_name}".lower() +slug = re.sub(r"[^a-z0-9-]+", "-", agent_name.lower()).strip("-") or "agent" +digest = hashlib.sha256(seed.encode("utf-8")).hexdigest()[:12] +name = f"sre-agent-{slug}-{digest}" +print(name[:64].rstrip("-")) +PY +} + +deployment_output_value() { + local file="$1" + local key="$2" + local default="${3:-}" + jq -r \ + --arg key "$key" \ + --arg default "$default" \ + '(.properties.outputs // {}) + | to_entries + | map(select((.key | ascii_upcase) == ($key | ascii_upcase)) | .value.value) + | first // $default' \ + "$file" +} + +normalize_action_mode() { + case "$1" in + Autonomous|autonomous|Automatic|automatic) printf 'autonomous' ;; + Review|review) printf 'review' ;; + ReadOnly|readOnly|readonly) printf 'readOnly' ;; + *) fail "Error: unsupported action mode '$1'" 2 ;; + esac +} + +validate_kusto_uri() { + local uri="$1" + [[ -z "$uri" ]] && return 0 + if [[ "$uri" != https://*.kusto.windows.net/* ]]; then + fail "Error: --cluster-uri must be a database-qualified Kusto URI. Example: https://..kusto.windows.net/Hub" 2 + fi + local path="${uri#https://}" + if [[ "$path" != */* || -z "${path#*/}" ]]; then + fail "Error: --cluster-uri must include the Kusto database name. Example: https://..kusto.windows.net/Hub" 2 + fi +} + +parse_kusto_cluster_name() { + local uri="$1" + local host + host="${uri#https://}" + host="${host%%/*}" + printf '%s\n' "${host%%.*}" +} + +parse_kusto_database_name() { + local uri="$1" + local path + path="${uri#https://}" + path="${path#*/}" + path="${path%%\?*}" + path="${path%%#*}" + printf '%s\n' "${path%%/*}" +} + +to_lower() { + printf '%s\n' "$1" | tr '[:upper:]' '[:lower:]' +} + +append_target_rg() { + local rg="$1" + local existing + [[ -n "$rg" ]] || return 0 + if [[ "${#TARGET_RGS[@]}" -gt 0 ]]; then + for existing in "${TARGET_RGS[@]}"; do + if [[ "$(to_lower "$existing")" == "$(to_lower "$rg")" ]]; then + return 0 + fi + done + fi + TARGET_RGS+=("$rg") +} + +resource_id_subscription() { + local resource_id="$1" + printf '%s\n' "$resource_id" | awk -F/ '{print $3}' +} + +resource_id_resource_group() { + local resource_id="$1" + printf '%s\n' "$resource_id" | awk -F/ '{print $5}' +} + +resolve_kusto_cluster_resource_id() { + local uri="$1" + local cluster_name + local cluster_uri + local resource_id + local graph_result_count + + cluster_name="$(parse_kusto_cluster_name "$uri")" + [[ -n "$cluster_name" ]] || fail "Error: could not parse Kusto cluster name from --cluster-uri" 2 + cluster_uri="${uri%/*}" + + resource_id="$(az resource list \ + --subscription "$SUBSCRIPTION_ID" \ + --resource-type Microsoft.Kusto/clusters \ + --query "[?name=='${cluster_name}'].id | [0]" \ + -o tsv 2>/dev/null || true)" + + if [[ -n "$resource_id" && "$resource_id" != "null" ]]; then + printf '%s\n' "$resource_id" + return 0 + fi + + resource_id="$(az graph query \ + -q "Resources | where type =~ 'microsoft.kusto/clusters' | where name =~ '${cluster_name}' or tostring(properties.uri) =~ '${cluster_uri}' | project id | limit 2" \ + -o json 2>/dev/null | jq -r '.data[].id' 2>/dev/null || true)" + graph_result_count="$(printf '%s\n' "$resource_id" | sed '/^$/d' | wc -l | tr -d ' ')" + + if [[ "$graph_result_count" == "1" ]]; then + printf '%s\n' "$resource_id" + return 0 + fi + + if [[ -z "$resource_id" || "$resource_id" == "null" ]]; then + fail "Error: could not resolve Kusto cluster '${cluster_name}'. Pass --cluster-resource-id so deployment can assign AllDatabasesViewer before creating the connector." 2 + fi + + fail "Error: Kusto cluster '${cluster_name}' resolved to multiple resources. Pass --cluster-resource-id explicitly so deployment assigns AllDatabasesViewer to the intended cluster." 2 +} + +warn_kusto_private_query_limitation() { + local cluster_id="$1" + local cluster_json + local public_network_access + local private_endpoint_count + local cluster_uri + local docs_url="https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations" + + [[ -n "$cluster_id" ]] || return 0 + + cluster_json="$(az resource show --ids "$cluster_id" --api-version 2023-08-15 -o json 2>/dev/null || true)" + if [[ -z "$cluster_json" ]]; then + echo -e "${YELLOW}Warning: Could not inspect Kusto cluster network access. Deployment will continue.${NC}" + echo " Cluster: $cluster_id" + echo " Review SRE Agent private endpoint limitations: $docs_url" + echo "" + return 0 + fi + + public_network_access="$(echo "$cluster_json" | jq -r '.properties.publicNetworkAccess // .publicNetworkAccess // ""' 2>/dev/null || true)" + private_endpoint_count="$(echo "$cluster_json" | jq -r '((.properties.privateEndpointConnections // .privateEndpointConnections // []) | length)' 2>/dev/null || echo 0)" + cluster_uri="$(echo "$cluster_json" | jq -r '.properties.uri // .uri // empty' 2>/dev/null || true)" + + if [[ "$public_network_access" == "Disabled" ]]; then + echo -e "${YELLOW}Warning: The Kusto cluster denies public query access.${NC}" + echo " Cluster: ${cluster_uri:-$cluster_id}" + echo " publicNetworkAccess: ${public_network_access}" + echo " private endpoint connections: ${private_endpoint_count}" + echo " SRE Agent will still be deployed and the finops-hub-kusto connector will still be created." + echo " Per the SRE Agent known limitations, private endpoint ADX blocks direct KQL queries." + echo " The customer can enable public query access if they want the Kusto connector to become healthy:" + echo " $docs_url" + echo "" + fi +} + +RECIPE_DIR="" +SUBSCRIPTION_ID="" +RESOURCE_GROUP="" +AGENT_NAME="" +LOCATION="" +CLUSTER_URI="" +CLUSTER_RESOURCE_ID="" +DEPLOY_NAME="" +DRY_RUN="" +ENABLE_SUBSCRIPTION_READER="true" +TARGET_RGS=() + +while [[ $# -gt 0 ]]; do + case "$1" in + --recipe) + require_value "--recipe" "${2:-}" + RECIPE_DIR="$2" + shift 2 + ;; + --subscription) + require_value "--subscription" "${2:-}" + SUBSCRIPTION_ID="$2" + shift 2 + ;; + -g|--resource-group) + require_value "--resource-group / -g" "${2:-}" + RESOURCE_GROUP="$2" + shift 2 + ;; + -n|--name) + require_value "--name / -n" "${2:-}" + AGENT_NAME="$2" + shift 2 + ;; + -l|--location) + require_value "--location / -l" "${2:-}" + LOCATION="$2" + shift 2 + ;; + --target-resource-group) + require_value "--target-resource-group" "${2:-}" + TARGET_RGS+=("$2") + shift 2 + ;; + --cluster-uri) + require_value "--cluster-uri" "${2:-}" + CLUSTER_URI="$2" + shift 2 + ;; + --cluster-resource-id) + require_value "--cluster-resource-id" "${2:-}" + CLUSTER_RESOURCE_ID="$2" + shift 2 + ;; + --subscription-reader) + ENABLE_SUBSCRIPTION_READER="true" + shift + ;; + --no-subscription-reader) + ENABLE_SUBSCRIPTION_READER="false" + shift + ;; + --deploy-name) + require_value "--deploy-name" "${2:-}" + DEPLOY_NAME="$2" + shift 2 + ;; + --dry-run) + DRY_RUN="true" + shift + ;; + --force|--no-telemetry) + shift + ;; + -h|--help) + usage 0 + ;; + -*) + fail "Error: unknown flag '$1'" 2 + ;; + *) + fail "Error: unknown argument '$1'" 2 + ;; + esac +done + +[[ -n "$RECIPE_DIR" ]] || fail "Error: --recipe is required" 2 +[[ -d "$RECIPE_DIR" ]] || fail "Error: recipe directory not found: $RECIPE_DIR" 1 +[[ -f "${RECIPE_DIR}/agent.json" ]] || fail "Error: recipe agent.json not found: ${RECIPE_DIR}/agent.json" 1 +[[ -n "$SUBSCRIPTION_ID" ]] || fail "Error: --subscription is required" 2 +[[ -n "$RESOURCE_GROUP" ]] || fail "Error: --resource-group is required" 2 +[[ -n "$AGENT_NAME" ]] || fail "Error: --name is required" 2 +[[ -n "$LOCATION" ]] || fail "Error: --location is required" 2 +validate_kusto_uri "$CLUSTER_URI" +if [[ -n "$CLUSTER_URI" ]]; then + [[ -n "$(parse_kusto_database_name "$CLUSTER_URI")" ]] || fail "Error: could not parse Kusto database name from --cluster-uri" 2 +fi + +append_target_rg "$RESOURCE_GROUP" + +command -v az >/dev/null || fail "Azure CLI (az) is required" 1 +command -v jq >/dev/null || fail "jq is required" 1 +command -v git >/dev/null || fail "git is required" 1 + +PYTHON_CMD="" +if command -v python3 >/dev/null; then + PYTHON_CMD="python3" +elif command -v python >/dev/null && python --version 2>&1 | grep -q "Python 3"; then + PYTHON_CMD="python" +else + fail "Python 3 is required" 1 +fi + +if [[ -n "$CLUSTER_URI" && -z "$CLUSTER_RESOURCE_ID" ]]; then + if [[ -n "$DRY_RUN" ]]; then + fail "Error: --cluster-resource-id is required with --cluster-uri for --dry-run because dry-run makes no Azure calls. Real deployments can resolve it from the Kusto URI." 2 + fi + + echo "Resolving Kusto cluster resource ID from --cluster-uri..." + az account show --subscription "$SUBSCRIPTION_ID" >/dev/null + az account set --subscription "$SUBSCRIPTION_ID" + CLUSTER_RESOURCE_ID="$(resolve_kusto_cluster_resource_id "$CLUSTER_URI")" + echo " Kusto cluster: $CLUSTER_RESOURCE_ID" +fi + +if [[ -n "$CLUSTER_RESOURCE_ID" && -z "$DRY_RUN" ]]; then + warn_kusto_private_query_limitation "$CLUSTER_RESOURCE_ID" +fi + +if [[ -n "$CLUSTER_RESOURCE_ID" ]]; then + CLUSTER_SUBSCRIPTION_ID="$(resource_id_subscription "$CLUSTER_RESOURCE_ID")" + CLUSTER_RESOURCE_GROUP="$(resource_id_resource_group "$CLUSTER_RESOURCE_ID")" + if [[ "$(to_lower "$CLUSTER_SUBSCRIPTION_ID")" == "$(to_lower "$SUBSCRIPTION_ID")" ]]; then + append_target_rg "$CLUSTER_RESOURCE_GROUP" + else + echo -e "${YELLOW}Warning: FinOps Hub cluster is in subscription ${CLUSTER_SUBSCRIPTION_ID}; add agent managed-resource scope and resource-group RBAC for ${CLUSTER_RESOURCE_GROUP} separately.${NC}" >&2 + fi +fi + +ACCESS_LEVEL="$(recipe_value "${RECIPE_DIR}/agent.json" '.access.accessLevel')" +[[ -n "$ACCESS_LEVEL" ]] || ACCESS_LEVEL="Low" +ACTION_MODE_RAW="$(recipe_value "${RECIPE_DIR}/agent.json" '.access.actionMode')" +[[ -n "$ACTION_MODE_RAW" ]] || ACTION_MODE_RAW="Review" +ACTION_MODE="$(normalize_action_mode "$ACTION_MODE_RAW")" +UPGRADE_CHANNEL="$(recipe_value "${RECIPE_DIR}/agent.json" '.upgradeChannel')" +[[ -n "$UPGRADE_CHANNEL" ]] || UPGRADE_CHANNEL="Preview" +DEFAULT_MODEL_PROVIDER="$(recipe_value "${RECIPE_DIR}/agent.json" '.defaultModelProvider')" +[[ -n "$DEFAULT_MODEL_PROVIDER" ]] || DEFAULT_MODEL_PROVIDER="MicrosoftFoundry" +DEFAULT_MODEL_NAME="$(recipe_value "${RECIPE_DIR}/agent.json" '.defaultModelName')" +[[ -n "$DEFAULT_MODEL_NAME" ]] || DEFAULT_MODEL_NAME="Automatic" +MONTHLY_AGENT_UNIT_LIMIT="$(recipe_value "${RECIPE_DIR}/agent.json" '.monthlyAgentUnitLimit')" +[[ -n "$MONTHLY_AGENT_UNIT_LIMIT" ]] || MONTHLY_AGENT_UNIT_LIMIT="10000" +EXPERIMENTAL_SETTINGS="$(jq -c '.experimentalSettings // {"EnableSandboxGroup": true, "EnableWorkspaceTools": true}' "${RECIPE_DIR}/agent.json")" +TAGS="$(jq -c '.tags // {"finops-toolkit":"sre-agent","source":"microsoft-finops-toolkit"}' "${RECIPE_DIR}/agent.json")" +TARGET_RGS_JSON="$(printf '%s\n' "${TARGET_RGS[@]}" | jq -R . | jq -sc '.')" + +[[ -n "$DEPLOY_NAME" ]] || DEPLOY_NAME="$(deterministic_deploy_name)" +BUILD_ROOT="${SRE_AGENT_DEPLOY_DIR:-${HOME}/.cache/finops-toolkit/sre-agent}" +BUILD_DIR="${BUILD_ROOT}/${AGENT_NAME}-${DEPLOY_NAME}" +mkdir -p "$BUILD_DIR" + +PARAMETERS_FILE="${BUILD_DIR}/deploy.parameters.json" +RESULT_FILE="${BUILD_DIR}/deployment-result.json" + +jq -n \ + --arg resourceGroupName "$RESOURCE_GROUP" \ + --arg agentName "$AGENT_NAME" \ + --arg location "$LOCATION" \ + --arg accessLevel "$ACCESS_LEVEL" \ + --arg actionMode "$ACTION_MODE" \ + --arg upgradeChannel "$UPGRADE_CHANNEL" \ + --arg defaultModelProvider "$DEFAULT_MODEL_PROVIDER" \ + --arg defaultModelName "$DEFAULT_MODEL_NAME" \ + --argjson monthlyAgentUnitLimit "$MONTHLY_AGENT_UNIT_LIMIT" \ + --arg kustoClusterId "$CLUSTER_RESOURCE_ID" \ + --argjson enableSubscriptionReaderRole "$ENABLE_SUBSCRIPTION_READER" \ + --argjson targetResourceGroups "$TARGET_RGS_JSON" \ + --argjson experimentalSettings "$EXPERIMENTAL_SETTINGS" \ + --argjson tags "$TAGS" \ + '{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceGroupName": { "value": $resourceGroupName }, + "agentName": { "value": $agentName }, + "location": { "value": $location }, + "targetResourceGroups": { "value": $targetResourceGroups }, + "accessLevel": { "value": $accessLevel }, + "actionMode": { "value": $actionMode }, + "upgradeChannel": { "value": $upgradeChannel }, + "defaultModelProvider": { "value": $defaultModelProvider }, + "defaultModelName": { "value": $defaultModelName }, + "monthlyAgentUnitLimit": { "value": $monthlyAgentUnitLimit }, + "experimentalSettings": { "value": $experimentalSettings }, + "tags": { "value": $tags }, + "finopsHubKustoClusterResourceId": { "value": $kustoClusterId }, + "enableSubscriptionReaderRole": { "value": $enableSubscriptionReaderRole } + } + }' > "$PARAMETERS_FILE" + +echo "" +echo -e "${BLUE}============================================================${NC}" +echo -e "${BLUE} Azure SRE Agent - FinOps Toolkit Setup${NC}" +echo -e "${BLUE}============================================================${NC}" +echo "" +echo -e "${YELLOW}[1/4] Checking prerequisites...${NC}" +echo " az: $(az version --query '\"azure-cli\"' -o tsv 2>/dev/null || echo found)" +echo " jq: $(jq --version)" +echo " python: $($PYTHON_CMD --version 2>&1)" +echo " azd: not used" +echo "" + +if [[ -n "$DRY_RUN" ]]; then + echo -e "${YELLOW}[2/4] Planned deployment...${NC}" + echo " Subscription: $SUBSCRIPTION_ID" + echo " Resource group: $RESOURCE_GROUP" + echo " Agent: $AGENT_NAME" + echo " Region: $LOCATION" + echo " Target resource groups: ${TARGET_RGS[*]}" + echo " Subscription Reader: $ENABLE_SUBSCRIPTION_READER" + echo " Parameters: $PARAMETERS_FILE" + echo "" + echo "Dry run complete. No Azure calls were made." + exit 0 +fi + +echo -e "${YELLOW}[2/4] Checking Azure account...${NC}" +az account show --subscription "$SUBSCRIPTION_ID" --query "{subscription:name, id:id}" -o table >/dev/null +az account set --subscription "$SUBSCRIPTION_ID" +echo " Subscription: $SUBSCRIPTION_ID" +echo " Resource group: $RESOURCE_GROUP" +echo " Agent: $AGENT_NAME" +echo " Region: $LOCATION" +echo " Target resource groups: ${TARGET_RGS[*]}" +echo " Subscription Reader: $ENABLE_SUBSCRIPTION_READER" +echo " Parameters: $PARAMETERS_FILE" +echo "" + +echo -e "${YELLOW}[3/4] Deploying infrastructure with Azure CLI + Bicep...${NC}" +echo " Registering Microsoft.App provider..." +az provider register -n Microsoft.App --wait --output none + +echo " Starting deployment: $DEPLOY_NAME" +az deployment sub create \ + --subscription "$SUBSCRIPTION_ID" \ + --location "$LOCATION" \ + --name "$DEPLOY_NAME" \ + --template-file "${INFRA_DIR}/main.bicep" \ + --parameters "@${PARAMETERS_FILE}" \ + --no-wait \ + --output none + +echo " Waiting for deployment to complete..." +DEPLOYMENT_START="$(date +%s)" +DEPLOYMENT_JSON="{}" +STATE="" +while true; do + DEPLOYMENT_JSON="$(az deployment sub show \ + --subscription "$SUBSCRIPTION_ID" \ + --name "$DEPLOY_NAME" \ + --output json 2>/dev/null || echo "{}")" + STATE="$(echo "$DEPLOYMENT_JSON" | jq -r '.properties.provisioningState // "Accepted"' 2>/dev/null)" + + case "$STATE" in + Succeeded|Failed|Canceled) + break + ;; + *) + NOW="$(date +%s)" + echo " Deployment state: ${STATE} ($((NOW - DEPLOYMENT_START))s elapsed)" + sleep 10 + ;; + esac +done + +printf '%s\n' "$DEPLOYMENT_JSON" > "$RESULT_FILE" + +STATE="$(jq -r '.properties.provisioningState // "Failed"' "$RESULT_FILE")" +if [[ "$STATE" != "Succeeded" ]]; then + echo "" + echo "Deployment failed. Diagnostic command:" + echo " az deployment operation sub list --subscription ${SUBSCRIPTION_ID} -n ${DEPLOY_NAME} -o table" + exit 1 +fi + +AGENT_ENDPOINT="$(deployment_output_value "$RESULT_FILE" "SRE_AGENT_ENDPOINT")" +SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID="$(deployment_output_value "$RESULT_FILE" "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID")" +AGENT_PORTAL_URL="$(deployment_output_value "$RESULT_FILE" "AGENT_PORTAL_URL" "https://sre.azure.com")" + +[[ -n "$AGENT_ENDPOINT" ]] || fail "Deployment succeeded but did not return SRE_AGENT_ENDPOINT" 1 +[[ -n "$SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID" ]] || fail "Deployment succeeded but did not return SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID" 1 + +echo "" +echo -e "${YELLOW}[4/4] Applying SRE Agent extras...${NC}" +APPLY_EXTRAS_ARGS=( + --endpoint "$AGENT_ENDPOINT" + --subscription "$SUBSCRIPTION_ID" + --resource-group "$RESOURCE_GROUP" + --name "$AGENT_NAME" + --recipe "$RECIPE_DIR" + --build-dir "${BUILD_DIR}/extras" +) + +if [[ -n "$CLUSTER_URI" ]]; then + APPLY_EXTRAS_ARGS+=(--kusto-connector-uri "$CLUSTER_URI") +fi + +bash "${SCRIPT_DIR}/apply-extras.sh" \ + "${APPLY_EXTRAS_ARGS[@]}" + +echo "" +echo -e "${BLUE}============================================================${NC}" +echo -e "${GREEN} SRE Agent ready${NC}" +echo -e "${BLUE}============================================================${NC}" +echo " Agent portal: $AGENT_PORTAL_URL" +echo " Endpoint: $AGENT_ENDPOINT" +echo " Build dir: $BUILD_DIR" +echo "" diff --git a/src/templates/sre-agent/bin/post-provision.sh b/src/templates/sre-agent/bin/post-provision.sh new file mode 100755 index 000000000..4bf44af9f --- /dev/null +++ b/src/templates/sre-agent/bin/post-provision.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# Compatibility wrapper. The SRE Agent recipe now follows the upstream +# Bicep + apply-extras pattern for post-provisioning. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +echo "bin/post-provision.sh is deprecated; forwarding to bin/apply-extras.sh" >&2 +exec bash "${SCRIPT_DIR}/apply-extras.sh" "$@" diff --git a/src/templates/sre-agent/bin/telemetry.sh b/src/templates/sre-agent/bin/telemetry.sh new file mode 100755 index 000000000..97aa3a02a --- /dev/null +++ b/src/templates/sre-agent/bin/telemetry.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# telemetry.sh — anonymous usage tracking for recipe popularity. +# +# Sends a single custom event to App Insights. Non-blocking, best-effort. +# No PII is collected — only recipe name, action, region, OS, and coarse booleans. +# +# Usage (sourced by other scripts): +# source "$(dirname "$0")/telemetry.sh" +# send_telemetry "deploy" "finops-hub" "westus3" "true" "false" "true" "false" "deploy" + +_TELEMETRY_IKEY="f10eff7f-b995-4c41-8347-90f0f55d5969" +_TELEMETRY_ENDPOINT="https://eastus2-3.in.applicationinsights.azure.com/v2/track" + +send_telemetry() { + [[ "${_NO_TELEMETRY:-}" == "true" ]] && return 0 + + local action="${1:-unknown}" + local recipe="${2:-unknown}" + local region="${3:-unknown}" + local used_recipe_flag="${4:-false}" + local used_legacy_positional="${5:-false}" + local has_cluster_uri="${6:-false}" + local has_cluster_resource_id="${7:-false}" + local mode="${8:-deploy}" + local os_type + os_type="$(uname -s 2>/dev/null || echo unknown)" + + # Fire and forget — never block or fail the main script + (curl -s -o /dev/null -m 5 -X POST "$_TELEMETRY_ENDPOINT" \ + -H "Content-Type: application/json" \ + -d "[{ + \"name\": \"Microsoft.ApplicationInsights.Event\", + \"time\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\", + \"iKey\": \"${_TELEMETRY_IKEY}\", + \"data\": { + \"baseType\": \"EventData\", + \"baseData\": { + \"name\": \"recipe-usage\", + \"properties\": { + \"action\": \"${action}\", + \"recipe\": \"${recipe}\", + \"region\": \"${region}\", + \"os\": \"${os_type}\", + \"used_recipe_flag\": \"${used_recipe_flag}\", + \"used_legacy_positional\": \"${used_legacy_positional}\", + \"has_cluster_uri\": \"${has_cluster_uri}\", + \"has_cluster_resource_id\": \"${has_cluster_resource_id}\", + \"mode\": \"${mode}\" + } + } + } + }]" 2>/dev/null &) 2>/dev/null +} diff --git a/src/templates/sre-agent/createUiDefinition.json b/src/templates/sre-agent/createUiDefinition.json new file mode 100644 index 000000000..87e82bcaa --- /dev/null +++ b/src/templates/sre-agent/createUiDefinition.json @@ -0,0 +1,169 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#", + "handler": "Microsoft.Azure.CreateUIDef", + "version": "0.1.2-preview", + "parameters": { + "config": { + "basics": { + "description": "Deploy Azure SRE Agent with the FinOps toolkit recipe for FinOps hub analysis, capacity monitoring, scheduled tasks, and specialist agents.", + "location": { + "label": "Location", + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ] + } + } + }, + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ], + "basics": [ + { + "name": "resourceGroupName", + "type": "Microsoft.Common.TextBox", + "label": "Agent resource group", + "defaultValue": "finops-hub-sre", + "toolTip": "Resource group that will contain the Azure SRE Agent, monitoring resources, and deployment script identity.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9._()\\-]{1,90}$", + "validationMessage": "Enter a valid Azure resource group name." + }, + "visible": true + }, + { + "name": "agentName", + "type": "Microsoft.Common.TextBox", + "label": "Agent name", + "defaultValue": "finops-hub-sre", + "toolTip": "Name of the Azure SRE Agent resource.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9][a-zA-Z0-9\\-]{1,61}[a-zA-Z0-9]$", + "validationMessage": "Name must be 3-63 characters and can contain letters, numbers, and hyphens. The first and last characters must be alphanumeric." + }, + "visible": true + } + ], + "steps": [ + { + "name": "configuration", + "label": "Configuration", + "elements": [ + { + "name": "finopsHubKustoConnectorUri", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto URI", + "defaultValue": "", + "toolTip": "Optional database-qualified Azure Data Explorer URI for the FinOps hub. Example: https://cluster.region.kusto.windows.net/Hub", + "constraints": { + "required": false, + "regex": "^$|^https://.+\\.kusto\\.windows\\.net/.+", + "validationMessage": "Enter a database-qualified Kusto URI such as https://cluster.region.kusto.windows.net/Hub, or leave blank." + }, + "visible": true + }, + { + "name": "finopsHubKustoClusterResourceId", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto cluster resource ID", + "defaultValue": "", + "toolTip": "Optional Azure Data Explorer cluster resource ID. Provide this to assign the agent managed identity AllDatabasesViewer on the cluster.", + "constraints": { + "required": false, + "regex": "^$|^/subscriptions/.+/resourceGroups/.+/providers/Microsoft\\.Kusto/clusters/.+", + "validationMessage": "Enter a valid Microsoft.Kusto/clusters resource ID, or leave blank." + }, + "visible": true + }, + { + "name": "targetResourceGroups", + "type": "Microsoft.Common.TextBox", + "label": "Additional target resource groups", + "defaultValue": "", + "toolTip": "Optional comma-separated resource group names the agent can observe or act on. The agent resource group is always included.", + "constraints": { + "required": false, + "regex": "^$|^[A-Za-z0-9_.()\\-]+(\\s*,\\s*[A-Za-z0-9_.()\\-]+)*$", + "validationMessage": "Enter a comma-separated list of resource group names without blank entries or trailing commas." + }, + "visible": true + }, + { + "name": "accessLevel", + "type": "Microsoft.Common.OptionsGroup", + "label": "Access level", + "defaultValue": "High", + "toolTip": "High adds Contributor on target resource groups for autonomous remediation workflows. Low grants read-only monitoring roles.", + "constraints": { + "allowedValues": [ + { + "label": "High", + "value": "High" + }, + { + "label": "Low", + "value": "Low" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "actionMode", + "type": "Microsoft.Common.OptionsGroup", + "label": "Action mode", + "defaultValue": "autonomous", + "toolTip": "Review requires approval before write actions. Autonomous lets the agent run enabled actions within its assigned access.", + "constraints": { + "allowedValues": [ + { + "label": "Autonomous", + "value": "autonomous" + }, + { + "label": "Review", + "value": "review" + }, + { + "label": "Read only", + "value": "readOnly" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "enableSubscriptionReaderRole", + "type": "Microsoft.Common.CheckBox", + "label": "Grant subscription Reader to the agent", + "toolTip": "Recommended. Grants the agent managed identity Reader on the deployment subscription for inventory, Resource Graph, capacity, quota, and monitoring coverage workflows.", + "defaultValue": true, + "visible": true + } + ] + } + ], + "outputs": { + "resourceGroupName": "[basics('resourceGroupName')]", + "agentName": "[basics('agentName')]", + "location": "[location()]", + "targetResourceGroupNames": "[steps('configuration').targetResourceGroups]", + "finopsHubKustoConnectorUri": "[steps('configuration').finopsHubKustoConnectorUri]", + "finopsHubKustoClusterResourceId": "[steps('configuration').finopsHubKustoClusterResourceId]", + "accessLevel": "[steps('configuration').accessLevel]", + "actionMode": "[steps('configuration').actionMode]", + "enableSubscriptionReaderRole": "[steps('configuration').enableSubscriptionReaderRole]" + } + } +} diff --git a/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml b/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml new file mode 100644 index 000000000..afa74e4e7 --- /dev/null +++ b/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml @@ -0,0 +1,32 @@ +name: Deploy FinOps SRE Agent + +on: + workflow_dispatch: + +permissions: + id-token: write + contents: read + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + - name: Deploy FinOps SRE Agent + working-directory: src/templates/sre-agent + env: + CLUSTER_URI: ${{ secrets.SRE_AGENT_CLUSTER_URI }} + run: > + bash bin/deploy.sh + --recipe recipes/finops-hub + --resource-group ${{ vars.SRE_AGENT_RESOURCE_GROUP }} + --name ${{ vars.SRE_AGENT_NAME }} + --location ${{ vars.SRE_AGENT_LOCATION }} + --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} + --cluster-uri "$CLUSTER_URI" + --force diff --git a/src/templates/sre-agent/infra/main.bicep b/src/templates/sre-agent/infra/main.bicep new file mode 100644 index 000000000..ff49374b9 --- /dev/null +++ b/src/templates/sre-agent/infra/main.bicep @@ -0,0 +1,132 @@ +// Copied from microsoft/sre-agent labs/starter-lab/infra/main.bicep and +// updated for the FinOps Toolkit SRE Agent template: +// - no azd environment dependency +// - no Grubify sample application +// - resource-group scoped target access + +targetScope = 'subscription' + +@description('Resource group that holds the SRE Agent resources.') +param resourceGroupName string + +@description('SRE Agent name.') +param agentName string + +@description('Primary location for all resources.') +@allowed(['australiaeast', 'canadacentral', 'eastus2', 'francecentral', 'koreacentral', 'swedencentral', 'uksouth']) +param location string = 'eastus2' + +@description('Resource groups the agent can observe or act on.') +param targetResourceGroups array = [] + +@description('Agent access level.') +@allowed(['Low', 'High']) +param accessLevel string = 'Low' + +@description('Agent action mode.') +@allowed(['review', 'autonomous', 'readOnly']) +param actionMode string = 'review' + +@description('Agent upgrade channel.') +@allowed(['Stable', 'Preview']) +param upgradeChannel string = 'Preview' + +@description('Default SRE Agent model provider. MicrosoftFoundry maps to the Azure OpenAI provider in the SRE Agent portal.') +@allowed(['MicrosoftFoundry', 'Anthropic']) +param defaultModelProvider string = 'MicrosoftFoundry' + +@description('Default SRE Agent model name. Automatic lets SRE Agent route to the appropriate model within the selected provider.') +param defaultModelName string = 'Automatic' + +@description('Monthly agent unit limit.') +@minValue(1) +param monthlyAgentUnitLimit int = 10000 + +@description('Agent experimental settings.') +param experimentalSettings object = { + EnableSandboxGroup: true + EnableWorkspaceTools: true +} + +@description('Azure resource tags.') +param tags object = {} + +@description('Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment.') +param finopsHubKustoClusterResourceId string = '' + +@description('Assign Reader on the deployment subscription to the agent managed identity.') +param enableSubscriptionReaderRole bool = true + +var targetRgs = empty(targetResourceGroups) ? [resourceGroupName] : targetResourceGroups +var agentResourceGroupId = subscriptionResourceId('Microsoft.Resources/resourceGroups', resourceGroupName) +var targetRgIds = [for rgName in targetRgs: subscriptionResourceId('Microsoft.Resources/resourceGroups', rgName)] +var namingSeed = toLower('${subscription().subscriptionId}|${agentResourceGroupId}|${agentName}') +var readerRoleId = 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + +resource rg 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: location + tags: tags +} + +module resources 'resources.bicep' = { + name: 'resources-deployment' + scope: rg + params: { + agentName: agentName + location: location + namingSeed: namingSeed + targetResourceGroupIds: targetRgIds + accessLevel: accessLevel + actionMode: actionMode + upgradeChannel: upgradeChannel + defaultModelProvider: defaultModelProvider + defaultModelName: defaultModelName + monthlyAgentUnitLimit: monthlyAgentUnitLimit + experimentalSettings: experimentalSettings + tags: tags + } +} + +module targetRbac 'modules/resource-group-rbac.bicep' = [for rgName in targetRgs: { + name: 'target-rbac-${uniqueString(toLower(subscriptionResourceId('Microsoft.Resources/resourceGroups', rgName)), namingSeed)}' + scope: resourceGroup(rgName) + params: { + principalId: resources.outputs.agentPrincipalId + accessLevel: accessLevel + } +}] + +resource subscriptionReaderRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableSubscriptionReaderRole) { + name: guid(subscription().id, namingSeed, readerRoleId) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', readerRoleId) + principalId: resources.outputs.agentPrincipalId + principalType: 'ServicePrincipal' + } +} + +var hasKustoCluster = !empty(finopsHubKustoClusterResourceId) +var kustoClusterSubscriptionId = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[2] : '' +var kustoClusterResourceGroupName = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[4] : '' +var kustoClusterName = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[8] : '' + +module finopsHubKustoAllDatabasesViewerRbac 'modules/kusto-all-databases-viewer-rbac.bicep' = if (hasKustoCluster) { + name: 'kusto-rbac-${uniqueString(finopsHubKustoClusterResourceId, namingSeed)}' + scope: resourceGroup(kustoClusterSubscriptionId, kustoClusterResourceGroupName) + params: { + clusterName: kustoClusterName + principalApplicationId: resources.outputs.agentPrincipalId + principalTenantId: tenant().tenantId + principalAssignmentName: 'sre-agent-${uniqueString(finopsHubKustoClusterResourceId, namingSeed, 'all-db-viewer')}' + } +} + +output AZURE_RESOURCE_GROUP string = rg.name +output AZURE_LOCATION string = location +output SRE_AGENT_NAME string = resources.outputs.agentName +output SRE_AGENT_ENDPOINT string = resources.outputs.agentEndpoint +output AGENT_PORTAL_URL string = resources.outputs.agentPortalUrl +output SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID string = resources.outputs.agentPrincipalId +output SYSTEM_MANAGED_IDENTITY_TENANT_ID string = resources.outputs.agentTenantId +output LOG_ANALYTICS_WORKSPACE_ID string = resources.outputs.logAnalyticsWorkspaceId diff --git a/src/templates/sre-agent/infra/modules/apply-extras.bicep b/src/templates/sre-agent/infra/modules/apply-extras.bicep new file mode 100644 index 000000000..4adbe17a8 --- /dev/null +++ b/src/templates/sre-agent/infra/modules/apply-extras.bicep @@ -0,0 +1,103 @@ +targetScope = 'resourceGroup' + +@description('Location for the deployment script resources.') +param location string + +@description('SRE Agent name.') +param agentName string + +@description('SRE Agent data-plane endpoint.') +param agentEndpoint string + +@description('Subscription that contains the SRE Agent.') +param subscriptionId string + +@description('Public URI for the generated SRE Agent recipe package.') +param recipePackageUri string + +@description('Optional database-qualified Kusto connector URI.') +param kustoConnectorUri string = '' + +@description('Forces the deployment script to run when the template is redeployed.') +param forceUpdateTag string + +@description('Azure resource tags.') +param tags object = {} + +var identityName = 'id-sre-apply-${uniqueString(resourceGroup().id, agentName)}' +var scriptName = 'apply-sre-${uniqueString(resourceGroup().id, agentName)}' +var sreAgentAdminRoleId = 'e79298df-d852-4c6d-84f9-5d13249d1e55' + +#disable-next-line BCP081 +resource sreAgent 'Microsoft.App/agents@2026-01-01' existing = { + name: agentName +} + +resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: identityName + location: location + tags: tags +} + +resource sreAgentAdminRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(sreAgent.id, identity.id, sreAgentAdminRoleId) + scope: sreAgent + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', sreAgentAdminRoleId) + principalId: identity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +resource applyExtras 'Microsoft.Resources/deploymentScripts@2023-08-01' = { + name: scriptName + location: location + tags: tags + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${identity.id}': {} + } + } + properties: { + azPowerShellVersion: '11.0' + retentionInterval: 'PT1H' + cleanupPreference: 'OnSuccess' + timeout: 'PT2H' + forceUpdateTag: forceUpdateTag + scriptContent: loadTextContent('../scripts/Apply-SreAgentExtras.ps1') + environmentVariables: [ + { + name: 'subscriptionId' + value: subscriptionId + } + { + name: 'resourceGroupName' + value: resourceGroup().name + } + { + name: 'agentName' + value: agentName + } + { + name: 'agentEndpoint' + value: agentEndpoint + } + { + name: 'recipePackageUri' + value: recipePackageUri + } + { + name: 'kustoConnectorUri' + value: kustoConnectorUri + } + ] + } + dependsOn: [ + sreAgentAdminRoleAssignment + ] +} + +output identityName string = identity.name +output scriptName string = applyExtras.name diff --git a/src/templates/sre-agent/infra/modules/kusto-all-databases-viewer-rbac.bicep b/src/templates/sre-agent/infra/modules/kusto-all-databases-viewer-rbac.bicep new file mode 100644 index 000000000..61baa4c44 --- /dev/null +++ b/src/templates/sre-agent/infra/modules/kusto-all-databases-viewer-rbac.bicep @@ -0,0 +1,26 @@ +@description('Kusto cluster name.') +param clusterName string + +@description('Microsoft Entra application/client ID to assign to the Kusto cluster.') +param principalApplicationId string + +@description('Principal tenant ID.') +param principalTenantId string + +@description('Stable principal assignment name.') +param principalAssignmentName string + +resource cluster 'Microsoft.Kusto/clusters@2024-04-13' existing = { + name: clusterName +} + +resource allDatabasesViewer 'Microsoft.Kusto/clusters/principalAssignments@2024-04-13' = { + parent: cluster + name: principalAssignmentName + properties: { + principalId: principalApplicationId + principalType: 'App' + role: 'AllDatabasesViewer' + tenantId: principalTenantId + } +} diff --git a/src/templates/sre-agent/infra/modules/monitoring.bicep b/src/templates/sre-agent/infra/modules/monitoring.bicep new file mode 100644 index 000000000..6a0102df1 --- /dev/null +++ b/src/templates/sre-agent/infra/modules/monitoring.bicep @@ -0,0 +1,39 @@ +@description('Location for resources') +param location string + +@description('Log Analytics Workspace name') +param logAnalyticsName string + +@description('Application Insights name') +param appInsightsName string + +// Log Analytics Workspace +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsName + location: location + properties: { + sku: { + name: 'PerGB2018' + } + retentionInDays: 30 + } +} + +// Application Insights (linked to Log Analytics) +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { + name: appInsightsName + location: location + kind: 'web' + properties: { + Application_Type: 'web' + Request_Source: 'IbizaAIExtension' + WorkspaceResourceId: logAnalyticsWorkspace.id + } +} + +// Outputs +output logAnalyticsWorkspaceId string = logAnalyticsWorkspace.id +output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name +output appInsightsId string = applicationInsights.id +output appInsightsAppId string = applicationInsights.properties.AppId +output appInsightsConnectionString string = applicationInsights.properties.ConnectionString diff --git a/src/templates/sre-agent/infra/modules/resource-group-rbac.bicep b/src/templates/sre-agent/infra/modules/resource-group-rbac.bicep new file mode 100644 index 000000000..15ede6c34 --- /dev/null +++ b/src/templates/sre-agent/infra/modules/resource-group-rbac.bicep @@ -0,0 +1,33 @@ +@description('Principal ID of the managed identity to assign roles to.') +param principalId string + +@description('Agent access level.') +@allowed(['Low', 'High']) +param accessLevel string + +var readerRoleId = 'acdd72a7-3385-48ef-bd42-f606fba81ae7' +var monitoringReaderRoleId = '43d0d8ad-25c7-4714-9337-8ba259a9fe05' +var logAnalyticsReaderRoleId = '73c42c96-874c-492b-b04d-ab87d138a893' +var contributorRoleId = 'b24988ac-6180-42a0-ab88-20f7382dd24c' + +var roleIds = accessLevel == 'High' + ? [ + readerRoleId + monitoringReaderRoleId + logAnalyticsReaderRoleId + contributorRoleId + ] + : [ + readerRoleId + monitoringReaderRoleId + logAnalyticsReaderRoleId + ] + +resource roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for roleId in roleIds: { + name: guid(resourceGroup().id, principalId, roleId) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleId) + principalId: principalId + principalType: 'ServicePrincipal' + } +}] diff --git a/src/templates/sre-agent/infra/modules/sre-agent.bicep b/src/templates/sre-agent/infra/modules/sre-agent.bicep new file mode 100644 index 000000000..4eb264822 --- /dev/null +++ b/src/templates/sre-agent/infra/modules/sre-agent.bicep @@ -0,0 +1,103 @@ +// Copied from microsoft/sre-agent labs/starter-lab/infra/modules/sre-agent.bicep +// and updated for the FinOps Toolkit SRE Agent template. + +@description('Location for resources.') +param location string + +@description('SRE Agent name.') +param agentName string + +@description('Application Insights App ID.') +param appInsightsAppId string + +@description('Application Insights connection string.') +@secure() +param appInsightsConnectionString string + +@description('Application Insights resource ID.') +param appInsightsId string + +@description('Resource group IDs to add as managed resources.') +param managedResourceGroupIds array + +@description('Agent access level.') +param accessLevel string + +@description('Agent action mode.') +param actionMode string + +@description('Agent upgrade channel.') +param upgradeChannel string + +@description('Default SRE Agent model provider.') +param defaultModelProvider string + +@description('Default SRE Agent model name.') +param defaultModelName string + +@description('Monthly agent unit limit.') +param monthlyAgentUnitLimit int + +@description('Agent experimental settings.') +param experimentalSettings object + +@description('Azure resource tags.') +param tags object = {} + +var sreAgentAdminRoleId = 'e79298df-d852-4c6d-84f9-5d13249d1e55' + +#disable-next-line BCP081 +resource sreAgent 'Microsoft.App/agents@2026-01-01' = { + name: agentName + location: location + tags: union(tags, { + 'hidden-link: /app-insights-resource-id': appInsightsId + source: 'microsoft-sre-agent-starter-lab' + 'finops-toolkit': 'sre-agent' + }) + identity: { + type: 'SystemAssigned' + } + properties: { + knowledgeGraphConfiguration: { + managedResources: managedResourceGroupIds + identity: 'system' + } + actionConfiguration: { + mode: actionMode + identity: 'system' + accessLevel: accessLevel + } + upgradeChannel: upgradeChannel + defaultModel: { + provider: defaultModelProvider + name: defaultModelName + } + monthlyAgentUnitLimit: monthlyAgentUnitLimit + experimentalSettings: experimentalSettings + mcpServers: [] + logConfiguration: { + applicationInsightsConfiguration: { + appId: appInsightsAppId + connectionString: appInsightsConnectionString + } + } + } +} + +resource sreAgentAdminRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(sreAgent.id, deployer().objectId, sreAgentAdminRoleId) + scope: sreAgent + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', sreAgentAdminRoleId) + principalId: deployer().objectId + principalType: 'User' + } +} + +output agentName string = sreAgent.name +output agentId string = sreAgent.id +output agentEndpoint string = sreAgent.properties.agentEndpoint +output agentPortalUrl string = 'https://sre.azure.com/#/agent/${subscription().subscriptionId}/${resourceGroup().name}/${sreAgent.name}' +output agentPrincipalId string = sreAgent.identity.principalId +output agentTenantId string = sreAgent.identity.tenantId diff --git a/src/templates/sre-agent/infra/resources.bicep b/src/templates/sre-agent/infra/resources.bicep new file mode 100644 index 000000000..1fd023349 --- /dev/null +++ b/src/templates/sre-agent/infra/resources.bicep @@ -0,0 +1,78 @@ +// Copied from microsoft/sre-agent labs/starter-lab/infra/resources.bicep and +// updated for the FinOps Toolkit SRE Agent template. + +@description('SRE Agent name.') +param agentName string + +@description('Location for all resources.') +param location string + +@description('Deterministic naming seed built from subscription ID, agent resource group ID, and agent name.') +param namingSeed string + +@description('Resource group IDs shown as managed resources in the SRE Agent.') +param targetResourceGroupIds array + +@description('Agent access level.') +param accessLevel string + +@description('Agent action mode.') +param actionMode string + +@description('Agent upgrade channel.') +param upgradeChannel string + +@description('Default SRE Agent model provider.') +param defaultModelProvider string + +@description('Default SRE Agent model name.') +param defaultModelName string + +@description('Monthly agent unit limit.') +param monthlyAgentUnitLimit int + +@description('Agent experimental settings.') +param experimentalSettings object + +@description('Azure resource tags.') +param tags object = {} + +var uniqueSuffix = uniqueString(namingSeed) +var logAnalyticsName = 'law-${uniqueSuffix}' +var appInsightsName = 'appi-${uniqueSuffix}' + +module monitoring 'modules/monitoring.bicep' = { + name: 'monitoring' + params: { + location: location + logAnalyticsName: logAnalyticsName + appInsightsName: appInsightsName + } +} + +module sreAgent 'modules/sre-agent.bicep' = { + name: 'sre-agent' + params: { + location: location + agentName: agentName + appInsightsAppId: monitoring.outputs.appInsightsAppId + appInsightsConnectionString: monitoring.outputs.appInsightsConnectionString + appInsightsId: monitoring.outputs.appInsightsId + managedResourceGroupIds: targetResourceGroupIds + accessLevel: accessLevel + actionMode: actionMode + upgradeChannel: upgradeChannel + defaultModelProvider: defaultModelProvider + defaultModelName: defaultModelName + monthlyAgentUnitLimit: monthlyAgentUnitLimit + experimentalSettings: experimentalSettings + tags: tags + } +} + +output agentName string = sreAgent.outputs.agentName +output agentEndpoint string = sreAgent.outputs.agentEndpoint +output agentPortalUrl string = sreAgent.outputs.agentPortalUrl +output agentPrincipalId string = sreAgent.outputs.agentPrincipalId +output agentTenantId string = sreAgent.outputs.agentTenantId +output logAnalyticsWorkspaceId string = monitoring.outputs.logAnalyticsWorkspaceId diff --git a/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 b/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 new file mode 100644 index 000000000..7a8db80ef --- /dev/null +++ b/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 @@ -0,0 +1,306 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +$ErrorActionPreference = 'Stop' + +function Get-RequiredEnv($Name) { + $value = [Environment]::GetEnvironmentVariable($Name) + if ([string]::IsNullOrWhiteSpace($value)) { + throw "Missing required environment variable: $Name" + } + return $value +} + +function Get-OptionalEnv($Name) { + return [Environment]::GetEnvironmentVariable($Name) +} + +function Get-TempRoot() { + $tempRoot = [System.IO.Path]::GetTempPath() + if ([string]::IsNullOrWhiteSpace($tempRoot)) { + $tempRoot = Get-OptionalEnv 'AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY' + } + if ([string]::IsNullOrWhiteSpace($tempRoot)) { + $tempRoot = (Get-Location).Path + } + return $tempRoot.TrimEnd([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar) +} + +function ConvertTo-BodyJson($Value) { + return ($Value | ConvertTo-Json -Depth 100 -Compress) +} + +function Get-PropertyValue($Object, [string[]]$Names, $Default = '') { + foreach ($name in $Names) { + if ($null -ne $Object -and $Object.PSObject.Properties[$name] -and $null -ne $Object.$name) { + return $Object.$name + } + } + return $Default +} + +function Get-HttpStatusCode($Exception) { + if ($Exception.Response -and $Exception.Response.StatusCode) { + return [int]$Exception.Response.StatusCode + } + return $null +} + +function Invoke-WithRetry([scriptblock]$Action, [string]$Label, [int]$MaxAttempts = 5, [int]$DelaySeconds = 15) { + for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) { + try { + return & $Action + } + catch { + $statusCode = Get-HttpStatusCode $_.Exception + if ($statusCode -and $statusCode -notin @(401, 403, 408, 429, 500, 502, 503, 504)) { + throw + } + if ($attempt -eq $MaxAttempts) { + throw + } + Write-Output "$Label attempt $attempt/$MaxAttempts failed: $($_.Exception.Message)" + Start-Sleep -Seconds $DelaySeconds + } + } +} + +function Invoke-JsonRest([string]$Method, [string]$Uri, [string]$Token, $Body = $null) { + $headers = @{ + Authorization = "Bearer $Token" + 'Content-Type' = 'application/json' + } + $parameters = @{ + Method = $Method + Uri = $Uri + Headers = $headers + } + if ($null -ne $Body) { + $parameters.Body = ConvertTo-BodyJson $Body + } + return Invoke-RestMethod @parameters +} + +function Get-KnowledgeSourceName([string]$FileName) { + $name = [IO.Path]::GetFileName($FileName).ToLowerInvariant() -replace '[^a-z0-9-]+', '-' + $name = $name -replace '-+', '-' + return $name.Trim('-') +} + +function Get-Collection($Value) { + if ($null -eq $Value) { + return @() + } + return @($Value) +} + +function Convert-TokenToString($Token) { + if ($Token -is [Security.SecureString]) { + $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token) + try { + return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) + } + finally { + [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) + } + } + return [string]$Token +} + +function Get-ArmAccessTokenString() { + return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://management.azure.com/').Token +} + +function Get-SreAccessTokenString() { + return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://azuresre.dev').Token +} + +$subscriptionId = Get-RequiredEnv 'subscriptionId' +$resourceGroupName = Get-RequiredEnv 'resourceGroupName' +$agentName = Get-RequiredEnv 'agentName' +$agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/') +$recipePackageUri = Get-RequiredEnv 'recipePackageUri' +$kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri' +$armApiVersion = '2025-05-01-preview' +$armBase = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName" + +Write-Output 'Connecting with deployment script managed identity...' +Connect-AzAccount -Identity | Out-Null +Set-AzContext -Subscription $subscriptionId | Out-Null + +$tempRoot = Get-TempRoot +$workRoot = Join-Path $tempRoot 'sre-agent-recipe' +$zipPath = Join-Path $tempRoot 'sre-agent-recipe.zip' +Remove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue +New-Item -Path $workRoot -ItemType Directory -Force | Out-Null + +Write-Output "Downloading SRE Agent recipe package: $recipePackageUri" +Invoke-WithRetry -Label 'download recipe package' -Action { + Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath +} | Out-Null +Expand-Archive -Path $zipPath -DestinationPath $workRoot -Force + +$extrasPath = Join-Path $workRoot 'extras.json' +if (-not (Test-Path $extrasPath)) { + throw "Recipe package did not contain extras.json" +} + +$extras = Get-Content $extrasPath -Raw | ConvertFrom-Json -Depth 100 +Write-Output "Loaded recipe package from $extrasPath" + +if ([string]::IsNullOrWhiteSpace($kustoConnectorUri)) { + $extras.connectors = @( + Get-Collection $extras.connectors | Where-Object { + $type = Get-PropertyValue $_.properties @('dataConnectorType', 'type') + $type -ine 'Kusto' + } + ) +} +else { + foreach ($connector in Get-Collection $extras.connectors) { + $type = Get-PropertyValue $connector.properties @('dataConnectorType', 'type') + if ($type -ieq 'Kusto') { + $connector.properties.dataSource = $kustoConnectorUri + if (-not $connector.properties.PSObject.Properties['identity']) { + $connector.properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system' + } + } + } +} + +function Invoke-ArmPutConnector([string]$Name, $Body) { + $uri = "$armBase/connectors/$Name`?api-version=$armApiVersion" + Invoke-WithRetry -Label "ARM PUT connector $Name" -Action { + Invoke-JsonRest -Method PUT -Uri $uri -Token (Get-ArmAccessTokenString) -Body $Body + } | Out-Null + Write-Output " ARM PUT connectors/${Name}: ok" +} + +function Invoke-SreApi([string]$Method, [string]$Path, $Body = $null) { + $uri = "$agentEndpoint$Path" + return Invoke-WithRetry -Label "$Method $Path" -MaxAttempts 21 -DelaySeconds 30 -Action { + Invoke-JsonRest -Method $Method -Uri $uri -Token (Get-SreAccessTokenString) -Body $Body + } +} + +function Invoke-ExtendedPut([string]$Kind, [string]$Name, [string]$Type, $Properties) { + $encodedName = [Uri]::EscapeDataString($Name) + $body = @{ + name = $Name + type = $Type + tags = @() + properties = $Properties + } + Invoke-SreApi -Method PUT -Path "/api/v2/extendedAgent/$Kind/$encodedName" -Body $body | Out-Null + Write-Output " PUT $Kind/${Name}: ok" +} + +Write-Output 'Step 1/7: Applying connectors...' +foreach ($connector in Get-Collection $extras.connectors) { + $name = [string]$connector.name + $properties = $connector.properties + if (-not $properties.PSObject.Properties['identity']) { + $properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system' + } + Invoke-ArmPutConnector -Name $name -Body @{ properties = $properties } +} + +Write-Output 'Step 2/7: Configuring built-in tools...' +$overrides = Get-Collection $extras.builtInTools.overrides +if ($overrides.Count -gt 0) { + $body = @{ + overrides = @($overrides | ForEach-Object { + @{ + name = $_.name + enabled = [bool]$_.enabled + } + }) + } + Invoke-SreApi -Method POST -Path '/api/v2/agent/tools/configure' -Body $body | Out-Null + Write-Output " built-in tools configured: $($overrides.Count) overrides" +} + +Write-Output 'Step 3/7: Uploading knowledge sources...' +foreach ($item in Get-Collection $extras.knowledgeItems) { + $sourceName = Get-KnowledgeSourceName ([string]$item.name) + $bytes = [Text.Encoding]::UTF8.GetBytes([string]$item.content) + $body = @{ + properties = @{ + dataConnectorType = 'KnowledgeFile' + dataSource = $sourceName + extendedProperties = @{ + displayName = [string]$item.name + fileName = [string]$item.name + fileContent = [Convert]::ToBase64String($bytes) + contentType = [string](Get-PropertyValue $item @('contentType') 'application/octet-stream') + } + } + } + Invoke-ArmPutConnector -Name $sourceName -Body $body + Start-Sleep -Seconds 5 +} + +Write-Output 'Step 4/7: Applying tools...' +foreach ($tool in Get-Collection $extras.tools) { + $name = [string]$tool.metadata.name + $properties = $tool.spec + if ($properties.type -eq 'PythonTool') { + $properties.type = 'PythonFunctionTool' + } + Invoke-ExtendedPut -Kind 'tools' -Name $name -Type 'ExtendedAgentTool' -Properties $properties +} + +Write-Output 'Step 5/7: Applying skills...' +foreach ($skill in Get-Collection $extras.skills) { + $name = [string]$skill.metadata.name + $tools = @() + if ($skill.metadata.spec -and $skill.metadata.spec.tools) { + $tools = Get-Collection $skill.metadata.spec.tools + } + $properties = @{ + name = $name + description = [string](Get-PropertyValue $skill.metadata @('description')) + tools = $tools + skillContent = [string](Get-PropertyValue $skill @('skillContent')) + additionalFiles = @() + } + Invoke-ExtendedPut -Kind 'skills' -Name $name -Type 'Skill' -Properties $properties +} + +Write-Output 'Step 6/7: Applying subagents...' +foreach ($subagent in Get-Collection $extras.subagents) { + $name = [string]$subagent.metadata.name + Invoke-ExtendedPut -Kind 'agents' -Name $name -Type 'ExtendedAgent' -Properties $subagent.spec +} + +Write-Output 'Step 7/7: Applying scheduled tasks...' +$scheduledTasks = Get-Collection $extras.scheduledTasks +if ($scheduledTasks.Count -gt 0) { + $existing = Invoke-SreApi -Method GET -Path '/api/v1/scheduledtasks' + foreach ($task in $scheduledTasks) { + $name = [string]$task.metadata.name + foreach ($match in (Get-Collection $existing | Where-Object { $_.name -eq $name })) { + if ($match.id) { + Invoke-SreApi -Method DELETE -Path "/api/v1/scheduledtasks/$($match.id)" | Out-Null + Write-Output " deleted existing scheduledtasks/$name" + } + } + } + + foreach ($task in $scheduledTasks) { + $name = [string]$task.metadata.name + $spec = $task.spec + $properties = @{ + name = [string](Get-PropertyValue $spec @('name') $name) + description = [string](Get-PropertyValue $spec @('description')) + cronExpression = [string](Get-PropertyValue $spec @('schedule', 'cronExpression', 'cron_expression')) + agentPrompt = [string](Get-PropertyValue $spec @('prompt', 'agentPrompt', 'agent_prompt')) + agentMode = [string](Get-PropertyValue $spec @('mode', 'agentMode', 'agent_mode') 'Review') + isEnabled = [bool](Get-PropertyValue $spec @('enabled') $true) + agent = [string](Get-PropertyValue $spec @('agent')) + } + Invoke-ExtendedPut -Kind 'scheduledtasks' -Name $name -Type 'ScheduledTask' -Properties $properties + } +} + +Write-Output 'SRE Agent extras complete.' diff --git a/src/templates/sre-agent/main.bicep b/src/templates/sre-agent/main.bicep new file mode 100644 index 000000000..fd4632140 --- /dev/null +++ b/src/templates/sre-agent/main.bicep @@ -0,0 +1,164 @@ +// One-click portal entry point for the FinOps Toolkit SRE Agent. +// The CLI path keeps using infra/main.bicep directly. + +targetScope = 'subscription' + +@description('Resource group that holds the SRE Agent resources.') +param resourceGroupName string + +@description('SRE Agent name.') +param agentName string + +@description('Primary location for all resources.') +@allowed(['australiaeast', 'canadacentral', 'eastus2', 'francecentral', 'koreacentral', 'swedencentral', 'uksouth']) +param location string = 'eastus2' + +@description('Resource groups the agent can observe or act on. The agent resource group is always included.') +param targetResourceGroups array = [] + +@description('Comma-separated resource groups the agent can observe or act on. Used by the Azure portal form.') +param targetResourceGroupNames string = '' + +@description('Optional database-qualified FinOps Hub Kusto connector URI. Example: https://..kusto.windows.net/Hub') +param finopsHubKustoConnectorUri string = '' + +@description('Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment.') +param finopsHubKustoClusterResourceId string = '' + +@description('Agent access level.') +@allowed(['Low', 'High']) +param accessLevel string = 'High' + +@description('Agent action mode.') +@allowed(['review', 'autonomous', 'readOnly']) +param actionMode string = 'autonomous' + +@description('Agent upgrade channel.') +@allowed(['Stable', 'Preview']) +param upgradeChannel string = 'Preview' + +@description('Default SRE Agent model provider. MicrosoftFoundry maps to the Azure OpenAI provider in the SRE Agent portal.') +@allowed(['MicrosoftFoundry', 'Anthropic']) +param defaultModelProvider string = 'MicrosoftFoundry' + +@description('Default SRE Agent model name. Automatic lets SRE Agent route to the appropriate model within the selected provider.') +param defaultModelName string = 'Automatic' + +@description('Monthly agent unit limit.') +@minValue(1) +param monthlyAgentUnitLimit int = 10000 + +@description('Agent experimental settings.') +param experimentalSettings object = { + EnableSandboxGroup: true + EnableWorkspaceTools: true +} + +@description('Assign Reader on the deployment subscription to the agent managed identity.') +param enableSubscriptionReaderRole bool = true + +@description('Public URI for the generated SRE Agent recipe package. Deploy-to-Azure links derive this from the template URI.') +param recipePackageUri string = uri(any(deployment()).properties.templateLink.uri, 'sre-agent-recipe.zip') + +@description('Forces the recipe deployment script to run when the template is redeployed.') +param forceUpdateTag string = utcNow() + +@description('Azure resource tags.') +param tags object = { + 'finops-toolkit': 'sre-agent' + source: 'microsoft-finops-toolkit' +} + +var rawTargetResourceGroups = split(replace(targetResourceGroupNames, ' ', ''), ',') +var parsedTargetResourceGroups = filter(rawTargetResourceGroups, rgName => !empty(rgName)) +var targetRgs = union([resourceGroupName], targetResourceGroups, parsedTargetResourceGroups) +var agentResourceGroupId = subscriptionResourceId('Microsoft.Resources/resourceGroups', resourceGroupName) +var targetRgIds = [for rgName in targetRgs: subscriptionResourceId('Microsoft.Resources/resourceGroups', rgName)] +var namingSeed = toLower('${subscription().subscriptionId}|${agentResourceGroupId}|${agentName}') +var readerRoleId = 'acdd72a7-3385-48ef-bd42-f606fba81ae7' +var hasKustoCluster = !empty(finopsHubKustoClusterResourceId) +var kustoClusterSubscriptionId = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[2] : '' +var kustoClusterResourceGroupName = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[4] : '' +var kustoClusterName = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[8] : '' + +resource rg 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: location + tags: tags +} + +module resources 'infra/resources.bicep' = { + name: 'resources-deployment' + scope: rg + params: { + agentName: agentName + location: location + namingSeed: namingSeed + targetResourceGroupIds: targetRgIds + accessLevel: accessLevel + actionMode: actionMode + upgradeChannel: upgradeChannel + defaultModelProvider: defaultModelProvider + defaultModelName: defaultModelName + monthlyAgentUnitLimit: monthlyAgentUnitLimit + experimentalSettings: experimentalSettings + tags: tags + } +} + +module targetRbac 'infra/modules/resource-group-rbac.bicep' = [for rgName in targetRgs: { + name: 'target-rbac-${uniqueString(toLower(subscriptionResourceId('Microsoft.Resources/resourceGroups', rgName)), namingSeed)}' + scope: resourceGroup(rgName) + params: { + principalId: resources.outputs.agentPrincipalId + accessLevel: accessLevel + } +}] + +resource subscriptionReaderRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableSubscriptionReaderRole) { + name: guid(subscription().id, namingSeed, readerRoleId) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', readerRoleId) + principalId: resources.outputs.agentPrincipalId + principalType: 'ServicePrincipal' + } +} + +module finopsHubKustoAllDatabasesViewerRbac 'infra/modules/kusto-all-databases-viewer-rbac.bicep' = if (hasKustoCluster) { + name: 'kusto-rbac-${uniqueString(finopsHubKustoClusterResourceId, namingSeed)}' + scope: resourceGroup(kustoClusterSubscriptionId, kustoClusterResourceGroupName) + params: { + clusterName: kustoClusterName + principalApplicationId: resources.outputs.agentPrincipalId + principalTenantId: tenant().tenantId + principalAssignmentName: 'sre-agent-${uniqueString(finopsHubKustoClusterResourceId, namingSeed, 'all-db-viewer')}' + } +} + +module applyExtras 'infra/modules/apply-extras.bicep' = { + name: 'apply-extras' + scope: rg + params: { + location: location + agentName: agentName + agentEndpoint: resources.outputs.agentEndpoint + subscriptionId: subscription().subscriptionId + recipePackageUri: recipePackageUri + kustoConnectorUri: finopsHubKustoConnectorUri + forceUpdateTag: forceUpdateTag + tags: tags + } + dependsOn: [ + targetRbac + ] +} + +output AZURE_RESOURCE_GROUP string = rg.name +output AZURE_LOCATION string = location +output SRE_AGENT_NAME string = resources.outputs.agentName +output SRE_AGENT_ENDPOINT string = resources.outputs.agentEndpoint +output AGENT_PORTAL_URL string = resources.outputs.agentPortalUrl +output SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID string = resources.outputs.agentPrincipalId +output SYSTEM_MANAGED_IDENTITY_TENANT_ID string = resources.outputs.agentTenantId +output LOG_ANALYTICS_WORKSPACE_ID string = resources.outputs.logAnalyticsWorkspaceId +output APPLY_EXTRAS_SCRIPT string = applyExtras.outputs.scriptName diff --git a/src/templates/sre-agent/package-manifest.json b/src/templates/sre-agent/package-manifest.json new file mode 100644 index 000000000..b3bde6c79 --- /dev/null +++ b/src/templates/sre-agent/package-manifest.json @@ -0,0 +1,21 @@ +{ + "deployment": { + "Files": [ + { + "sourceFolder": ".", + "source": "azuredeploy.json", + "destination": "azuredeploy.json" + }, + { + "sourceFolder": ".", + "source": "createUiDefinition.json", + "destination": "createUiDefinition.json" + }, + { + "sourceFolder": "assets", + "source": "sre-agent-recipe.zip", + "destination": "sre-agent-recipe.zip" + } + ] + } +} From 05601e681f02c8832f939208dc61c31ce32a8739 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 09:35:27 -0700 Subject: [PATCH 02/10] fix(sre-agent): keep deploy checks in deploy slice --- docs-mslearn/toolkit/changelog.md | 2 +- docs-mslearn/toolkit/hubs/configure-sre.md | 2 +- docs-mslearn/toolkit/sre-agent/agents.md | 2 +- docs-mslearn/toolkit/sre-agent/deploy.md | 2 +- docs-mslearn/toolkit/sre-agent/get-started.md | 2 +- docs-mslearn/toolkit/sre-agent/knowledge.md | 2 +- docs-mslearn/toolkit/sre-agent/kusto-tools.md | 2 +- docs-mslearn/toolkit/sre-agent/overview.md | 2 +- .../toolkit/sre-agent/python-tools.md | 2 +- .../toolkit/sre-agent/scheduled-tasks.md | 2 +- docs-mslearn/toolkit/sre-agent/security.md | 2 +- docs-mslearn/toolkit/sre-agent/template.md | 2 +- docs-mslearn/toolkit/sre-agent/tools.md | 2 +- .../toolkit/sre-agent/troubleshooting.md | 2 +- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 1043 +++++++++++++++++ 15 files changed, 1057 insertions(+), 14 deletions(-) create mode 100644 src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 diff --git a/docs-mslearn/toolkit/changelog.md b/docs-mslearn/toolkit/changelog.md index 6c538b1f8..c46cd6c5d 100644 --- a/docs-mslearn/toolkit/changelog.md +++ b/docs-mslearn/toolkit/changelog.md @@ -3,7 +3,7 @@ title: FinOps toolkit changelog description: Review the latest features and enhancements in the FinOps toolkit, including updates to FinOps hubs, Power BI reports, and more. author: MSBrett ms.author: brettwil -ms.date: 06/01/2026 +ms.date: 06/03/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/hubs/configure-sre.md b/docs-mslearn/toolkit/hubs/configure-sre.md index cf9800933..37f888dcd 100644 --- a/docs-mslearn/toolkit/hubs/configure-sre.md +++ b/docs-mslearn/toolkit/hubs/configure-sre.md @@ -3,7 +3,7 @@ title: Configure an SRE agent for FinOps hubs description: Learn how to configure an Azure SRE agent to connect to your FinOps hub for scheduled cost analysis, capacity monitoring, and reporting. author: msbrett ms.author: brettwil -ms.date: 06/02/2026 +ms.date: 06/03/2026 ms.topic: how-to ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/agents.md b/docs-mslearn/toolkit/sre-agent/agents.md index 1257c7b15..5411f4bb6 100644 --- a/docs-mslearn/toolkit/sre-agent/agents.md +++ b/docs-mslearn/toolkit/sre-agent/agents.md @@ -3,7 +3,7 @@ title: Specialist agents and skills (Azure SRE Agent in the FinOps toolkit) description: Understand how the FinOps toolkit configures Azure SRE Agent with specialist agents, tools, skills, and knowledge to automate FinOps and capacity management work. author: msbrett ms.author: brettwil -ms.date: 06/01/2026 +ms.date: 06/03/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/deploy.md b/docs-mslearn/toolkit/sre-agent/deploy.md index 3e135a6fe..88e0c3dcc 100644 --- a/docs-mslearn/toolkit/sre-agent/deploy.md +++ b/docs-mslearn/toolkit/sre-agent/deploy.md @@ -3,7 +3,7 @@ title: Deploy Azure SRE Agent with the FinOps toolkit description: Deploy the FinOps toolkit Azure SRE Agent template from the Azure portal or CLI, connect it to a FinOps hub Data Explorer cluster, and validate the deployment. author: msbrett ms.author: brettwil -ms.date: 06/02/2026 +ms.date: 06/03/2026 ms.topic: tutorial ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/get-started.md b/docs-mslearn/toolkit/sre-agent/get-started.md index 7aba04595..5b2981737 100644 --- a/docs-mslearn/toolkit/sre-agent/get-started.md +++ b/docs-mslearn/toolkit/sre-agent/get-started.md @@ -3,7 +3,7 @@ title: Get started with the FinOps toolkit on Azure SRE Agent description: Learn what to do after deploying Azure SRE Agent with the FinOps toolkit — first queries, scheduled tasks, and specialized subagents. author: flanakin ms.author: micflan -ms.date: 05/25/2026 +ms.date: 06/03/2026 ms.topic: quickstart ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/knowledge.md b/docs-mslearn/toolkit/sre-agent/knowledge.md index 7578736c3..9a94d8dda 100644 --- a/docs-mslearn/toolkit/sre-agent/knowledge.md +++ b/docs-mslearn/toolkit/sre-agent/knowledge.md @@ -3,7 +3,7 @@ title: Manage knowledge and memory (Azure SRE Agent in the FinOps toolkit) description: Learn how knowledge grounds the FinOps toolkit's Azure SRE Agent in your team's context and how memory keeps operational learnings available across sessions and redeployments. author: msbrett ms.author: brettwil -ms.date: 05/25/2026 +ms.date: 06/03/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/kusto-tools.md b/docs-mslearn/toolkit/sre-agent/kusto-tools.md index 7c2ca749b..19dfe39da 100644 --- a/docs-mslearn/toolkit/sre-agent/kusto-tools.md +++ b/docs-mslearn/toolkit/sre-agent/kusto-tools.md @@ -3,7 +3,7 @@ title: Kusto tools description: Review the FinOps hub Kusto tools the FinOps toolkit ships for Azure SRE Agent and learn when to use each tool for cost, commitment discount, anomaly, forecast, AI, and price analysis. author: msbrett ms.author: brettwil -ms.date: 06/01/2026 +ms.date: 06/03/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/overview.md b/docs-mslearn/toolkit/sre-agent/overview.md index 97a739e9e..c7240abbf 100644 --- a/docs-mslearn/toolkit/sre-agent/overview.md +++ b/docs-mslearn/toolkit/sre-agent/overview.md @@ -3,7 +3,7 @@ title: Azure SRE Agent in the FinOps toolkit description: Learn how the FinOps toolkit deploys Azure SRE Agent with FinOps and capacity management automation on top of FinOps hubs. author: msbrett ms.author: brettwil -ms.date: 06/02/2026 +ms.date: 06/03/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/python-tools.md b/docs-mslearn/toolkit/sre-agent/python-tools.md index 7def2af39..1de0cce9f 100644 --- a/docs-mslearn/toolkit/sre-agent/python-tools.md +++ b/docs-mslearn/toolkit/sre-agent/python-tools.md @@ -3,7 +3,7 @@ title: Python tools description: Review the Python tools the FinOps toolkit ships for Azure SRE Agent for Azure quota, capacity, budgets, anomaly alerts, Resource Graph, FinOps hub health, and Advisor suppressions. author: msbrett ms.author: brettwil -ms.date: 05/25/2026 +ms.date: 06/03/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md index 7862eaa6c..f98f3e14a 100644 --- a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md +++ b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md @@ -3,7 +3,7 @@ title: Scheduled tasks (Azure SRE Agent in the FinOps toolkit) description: Learn how the FinOps toolkit's scheduled tasks automate daily, weekly, monthly, and quarterly FinOps operating rhythms on Azure SRE Agent. author: msbrett ms.author: brettwil -ms.date: 05/25/2026 +ms.date: 06/03/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/security.md b/docs-mslearn/toolkit/sre-agent/security.md index 3aa3109bb..f4b7e0f6b 100644 --- a/docs-mslearn/toolkit/sre-agent/security.md +++ b/docs-mslearn/toolkit/sre-agent/security.md @@ -3,7 +3,7 @@ title: Security and permissions for Azure SRE Agent in the FinOps toolkit description: Review the permissions, identities, run modes, and data flows the FinOps toolkit configures on Azure SRE Agent before you deploy it in your environment. author: msbrett ms.author: brettwil -ms.date: 06/01/2026 +ms.date: 06/03/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/template.md b/docs-mslearn/toolkit/sre-agent/template.md index 79e4c00a7..25c7474c6 100644 --- a/docs-mslearn/toolkit/sre-agent/template.md +++ b/docs-mslearn/toolkit/sre-agent/template.md @@ -3,7 +3,7 @@ title: Azure SRE Agent template reference (FinOps toolkit) description: Review the FinOps toolkit's Azure SRE Agent deployment template, parameters, outputs, script flags, and Bicep module structure. author: msbrett ms.author: brettwil -ms.date: 06/02/2026 +ms.date: 06/03/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/tools.md b/docs-mslearn/toolkit/sre-agent/tools.md index 429a08d50..a8447b62f 100644 --- a/docs-mslearn/toolkit/sre-agent/tools.md +++ b/docs-mslearn/toolkit/sre-agent/tools.md @@ -3,7 +3,7 @@ title: Tools shipped for Azure SRE Agent in the FinOps toolkit description: Review the Kusto and Python tools the FinOps toolkit ships for Azure SRE Agent for cost analysis, anomaly detection, rate optimization, capacity management, and operations. author: msbrett ms.author: brettwil -ms.date: 06/01/2026 +ms.date: 06/03/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/troubleshooting.md b/docs-mslearn/toolkit/sre-agent/troubleshooting.md index 4f029c16a..53a5af68c 100644 --- a/docs-mslearn/toolkit/sre-agent/troubleshooting.md +++ b/docs-mslearn/toolkit/sre-agent/troubleshooting.md @@ -3,7 +3,7 @@ title: Troubleshoot Azure SRE Agent deployments from the FinOps toolkit description: Resolve common deployment, tenant, connector, data, and query issues for Azure SRE Agent deployments from the FinOps toolkit. author: msbrett ms.author: brettwil -ms.date: 06/02/2026 +ms.date: 06/03/2026 ms.topic: how-to ms.service: finops ms.subservice: finops-toolkit diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 new file mode 100644 index 000000000..b1042a83f --- /dev/null +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -0,0 +1,1043 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe 'SRE Agent deploy template' { + BeforeAll { + $script:RepoRoot = (Get-Item -Path $PSScriptRoot).Parent.Parent.Parent.Parent.FullName + $script:DeployScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/deploy.sh' + $script:ApplyExtrasScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/apply-extras.sh' + $script:PostProvisionScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/post-provision.sh' + $script:VerifyScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh' + $script:RecipeDir = Join-Path $script:RepoRoot 'src/templates/sre-agent/recipes/finops-hub' + $script:ScheduledTaskDir = Join-Path $script:RecipeDir 'automations/scheduled-tasks' + $script:OutputStylePath = Join-Path $script:RepoRoot 'src/templates/claude-plugin/output-styles/ftk-output-style.md' + $script:ReadmePath = Join-Path $script:RepoRoot 'src/templates/sre-agent/README.md' + $script:DocsPath = Join-Path $script:RepoRoot 'docs-mslearn/toolkit/sre-agent/deploy.md' + $script:AgentJsonPath = Join-Path $script:RecipeDir 'agent.json' + $script:SkipBash = -not (Get-Command bash -ErrorAction SilentlyContinue) + + function Invoke-BashCommand { + param( + [Parameter(Mandatory)] + [string] $Command + ) + + Push-Location $script:RepoRoot + try { + $output = & bash -lc $Command 2>&1 + [pscustomobject]@{ + ExitCode = $LASTEXITCODE + Output = ($output -join "`n") + } + } + finally { + Pop-Location + } + } + + function Invoke-BashCommandWithPath { + param( + [Parameter(Mandatory)] + [string] $Command, + + [Parameter(Mandatory)] + [string] $PathPrefix + ) + + Push-Location $script:RepoRoot + try { + $originalPath = $env:PATH + $env:PATH = "${PathPrefix}:$originalPath" + $output = & bash -c $Command 2>&1 + [pscustomobject]@{ + ExitCode = $LASTEXITCODE + Output = ($output -join "`n") + } + } + finally { + $env:PATH = $originalPath + Pop-Location + } + } + + function Set-BashStub { + param( + [Parameter(Mandatory)] + [string] $Path, + + [Parameter(Mandatory)] + [string] $Content + ) + + $utf8NoBom = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllText($Path, ($Content -replace "`r`n", "`n"), $utf8NoBom) + & chmod +x $Path + } + } + + Context 'bash availability' { + It 'has bash available for hermetic tests' { + if ($script:SkipBash) { + Set-ItResult -Skipped -Because 'bash is unavailable' + } + $true | Should -BeTrue + } + } + + Context 'help and parsing' { + It 'prints help with portal labels and required flags' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --help" + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'Resource group' + $result.Output | Should -Match 'Agent name' + $result.Output | Should -Match 'Region' + $result.Output | Should -Match 'Subscription' + $result.Output | Should -Match '--cluster-uri' + } + + It 'documents the same help lines in README and docs' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $help = Invoke-BashCommand "bash '$script:DeployScript' --help" + $help.ExitCode | Should -Be 0 + $readme = Get-Content -Path $script:ReadmePath -Raw + $docs = Get-Content -Path $script:DocsPath -Raw + + @( + '--recipe ', + '--resource-group ', + '--name ', + '--location ', + '--subscription ', + '--cluster-uri ', + '--cluster-resource-id ', + '--deploy-name ' + ) | ForEach-Object { + $escaped = [regex]::Escape($_) + $help.Output | Should -Match $escaped + $readme | Should -Match $escaped + $docs | Should -Match $escaped + } + } + + It 'errors for each missing required recipe flag' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $cases = @( + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --dry-run" + Match = 'subscription' + } + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 --dry-run" + Match = 'resource-group' + } + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-x --dry-run" + Match = 'name' + } + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-x -n a --dry-run" + Match = 'location' + } + ) + + foreach ($case in $cases) { + $result = Invoke-BashCommand $case.Command + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match $case.Match + } + } + + It 'errors on unknown flags' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipes '$script:RecipeDir' --dry-run" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'unknown flag' + } + + It 'errors when a value-taking flag is missing its value' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' -g -n foo --dry-run" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'requires a value' + } + + It 'errors when verify-agent expected config is missing its value' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:VerifyScript' 00000000-0000-0000-0000-000000000000 rg-test test-agent --expected" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'flag --expected requires a value' + $result.Output | Should -Not -Match 'unbound variable' + } + + It 'rejects unknown verify-agent arguments before Azure calls' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:VerifyScript' 00000000-0000-0000-0000-000000000000 rg-test test-agent --bogus" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match "unknown argument '--bogus'" + $result.Output | Should -Not -Match 'Could not resolve agent endpoint' + } + + It 'rejects the positional footgun' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --dry-run rg-test" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'unknown argument' + } + + It 'shows customer values and not maintainer defaults on happy-path dry-run' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --cluster-resource-id /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Kusto/clusters/fake --dry-run" + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'rg-test-customer' + $result.Output | Should -Match 'customer-sre-agent' + $result.Output | Should -Match 'westus3' + $result.Output | Should -Not -Match 'rg-finops-sre-agent|finops-sre-agent|eastus2' + } + + It 'uses a deterministic default deployment name across dry-runs' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $deployRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-deploy-name-" + [guid]::NewGuid().ToString('N')) + try { + $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --cluster-resource-id /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Kusto/clusters/fake --dry-run" + $first = Invoke-BashCommand $command + $second = Invoke-BashCommand $command + + $first.ExitCode | Should -Be 0 + $second.ExitCode | Should -Be 0 + $firstPath = [regex]::Match($first.Output, 'Parameters:\s+(.+)').Groups[1].Value.Trim() + $secondPath = [regex]::Match($second.Output, 'Parameters:\s+(.+)').Groups[1].Value.Trim() + + $firstPath | Should -Be $secondPath + $firstPath | Should -Match 'sre-agent-customer-sre-agent-[a-f0-9]{12}' + + $parameters = Get-Content -Path $firstPath -Raw | ConvertFrom-Json + $parameters.parameters.upgradeChannel.value | Should -Be 'Preview' + $parameters.parameters.experimentalSettings.value.EnableSandboxGroup | Should -BeTrue + $parameters.parameters.experimentalSettings.value.EnableWorkspaceTools | Should -BeTrue + $parameters.parameters.monthlyAgentUnitLimit.value | Should -Be 10000 + } + finally { + Remove-Item -Path $deployRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'requires cluster resource ID for dry-run when a Kusto URI is provided' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --dry-run" + + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match '--cluster-resource-id is required with --cluster-uri for --dry-run' + } + + It 'auto-resolves the Kusto cluster resource ID before deployment' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-kusto-resolve-" + [guid]::NewGuid().ToString('N')) + $binDir = Join-Path $tempRoot 'bin' + $deployRoot = Join-Path $tempRoot 'deploy' + New-Item -ItemType Directory -Force -Path $binDir, $deployRoot | Out-Null + + $fakeAz = Join-Path $binDir 'az' + Set-BashStub -Path $fakeAz -Content @' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "$*" == *"account get-access-token"* ]]; then + echo "fake-token" + exit 0 +fi + +if [[ "${1:-}" == "rest" ]]; then + echo "{}" + exit 0 +fi + +if [[ "$*" == *"resource list"* ]]; then + exit 0 +fi + +if [[ "$*" == *"graph query"* ]]; then + cat <<'JSON' +{ + "data": [ + { + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/example" + } + ] +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub show"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub create"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +case "$*" in + *"account show"*|*"account set"*|*"provider register"*|*"version"*) + exit 0 + ;; +esac + +exit 0 +'@ + + $fakeCurl = Join-Path $binDir 'curl' + Set-BashStub -Path $fakeCurl -Content @' +#!/usr/bin/env bash +set -euo pipefail + +out="" +url="" +method="GET" +while [[ $# -gt 0 ]]; do + case "$1" in + -o) + out="$2" + shift 2 + ;; + -w) + shift 2 + ;; + -X) + method="$2" + shift 2 + ;; + -H|--data-binary) + shift 2 + ;; + http*) + url="$1" + shift + ;; + *) + shift + ;; + esac +done + +if [[ "$url" == */api/v2/extendedAgent/connectors/finops-hub-kusto ]]; then + cat > "$out" <<'JSON' +{"name":"finops-hub-kusto","properties":{"dataConnectorType":"Kusto"}} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then + cat > "$out" <<'JSON' +{ + "value": [ + { "name": "chart-artifact-verification-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "document-index-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "ftk-output-style-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "known-issues-and-workarounds-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "onboarding-recommendations-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "teams-notification-guide-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } + ] +} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "dataConnectorType": "KnowledgeFile", + "extendedProperties": { + "createdAt": "2026-05-25T19:57:31Z", + "lastModifiedAt": "2026-05-25T19:57:31Z" + } + } +} +JSON + if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi + exit 0 +fi + +if [[ "$url" == */api/v2/agent/tools/configure ]]; then + cat > "$out" <<'JSON' +{} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v1/scheduledtasks ]]; then + cat > "$out" <<'JSON' +[] +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/agents/* ]]; then + [[ -n "${AGENT_APPLY_LOG:-}" ]] && basename "$url" >> "$AGENT_APPLY_LOG" + cat > "$out" <<'JSON' +{ + "type": "ExtendedAgent", + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +cat > "$out" <<'JSON' +{ + "files": [ + { "name": "chart-artifact-verification-md", "isIndexed": true, "errorReason": null }, + { "name": "document-index-md", "isIndexed": true, "errorReason": null }, + { "name": "ftk-output-style-md", "isIndexed": true, "errorReason": null }, + { "name": "known-issues-and-workarounds-md", "isIndexed": true, "errorReason": null }, + { "name": "onboarding-recommendations-md", "isIndexed": true, "errorReason": null }, + { "name": "teams-notification-guide-md", "isIndexed": true, "errorReason": null } + ], + "continuationToken": "" +} +JSON +printf "200" +'@ + + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' +#!/usr/bin/env bash +exit 0 +'@ + + try { + $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://example.westus3.kusto.windows.net/Hub" + $result = Invoke-BashCommandWithPath $command $binDir + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'Resolving Kusto cluster resource ID from --cluster-uri' + $result.Output | Should -Match '/providers/Microsoft\.Kusto/clusters/example' + + $parametersFile = (Get-ChildItem -Path $deployRoot -Recurse -Filter 'deploy.parameters.json' | Select-Object -First 1).FullName + $parametersFile | Should -Not -BeNullOrEmpty + $parameters = Get-Content -Path $parametersFile -Raw | ConvertFrom-Json + $parameters.parameters.finopsHubKustoClusterResourceId.value | Should -Be '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/example' + } + finally { + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'warns but continues when the Kusto cluster denies public query access' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-kusto-private-" + [guid]::NewGuid().ToString('N')) + $binDir = Join-Path $tempRoot 'bin' + $deployRoot = Join-Path $tempRoot 'deploy' + New-Item -ItemType Directory -Force -Path $binDir, $deployRoot | Out-Null + + $fakeAz = Join-Path $binDir 'az' + Set-BashStub -Path $fakeAz -Content @' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "$*" == *"account get-access-token"* ]]; then + echo "fake-token" + exit 0 +fi + +if [[ "${1:-}" == "rest" ]]; then + echo "{}" + exit 0 +fi + +if [[ "$*" == *"resource show"* ]]; then + cat <<'JSON' +{ + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/privateadx", + "properties": { + "uri": "https://privateadx.westus.kusto.windows.net", + "publicNetworkAccess": "Disabled", + "privateEndpointConnections": [ + { + "name": "privateadx-ep", + "properties": { + "privateLinkServiceConnectionState": { + "status": "Approved" + } + } + } + ] + } +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub show"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub create"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +case "$*" in + *"account show"*|*"account set"*|*"provider register"*|*"version"*) + exit 0 + ;; +esac + +exit 0 +'@ + + $fakeCurl = Join-Path $binDir 'curl' + Set-BashStub -Path $fakeCurl -Content @' +#!/usr/bin/env bash +set -euo pipefail + +out="" +url="" +method="GET" +while [[ $# -gt 0 ]]; do + case "$1" in + -o) + out="$2" + shift 2 + ;; + -w) + shift 2 + ;; + -X) + method="$2" + shift 2 + ;; + -H|--data-binary) + shift 2 + ;; + http*) + url="$1" + shift + ;; + *) + shift + ;; + esac +done + +if [[ "$url" == */api/v2/extendedAgent/connectors/finops-hub-kusto ]]; then + cat > "$out" <<'JSON' +{"name":"finops-hub-kusto","properties":{"dataConnectorType":"Kusto"}} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then + cat > "$out" <<'JSON' +{ + "value": [ + { "name": "chart-artifact-verification-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "document-index-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "ftk-output-style-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "known-issues-and-workarounds-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "onboarding-recommendations-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "teams-notification-guide-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } + ] +} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "dataConnectorType": "KnowledgeFile", + "extendedProperties": { + "createdAt": "2026-05-25T19:57:31Z", + "lastModifiedAt": "2026-05-25T19:57:31Z" + } + } +} +JSON + if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi + exit 0 +fi + +if [[ "$url" == */api/v1/scheduledtasks ]]; then + cat > "$out" <<'JSON' +[] +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/agent/tools/configure ]]; then + cat > "$out" <<'JSON' +{} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/agents/* || "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +cat > "$out" <<'JSON' +{} +JSON +printf "200" +'@ + + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' +#!/usr/bin/env bash +exit 0 +'@ + + try { + $clusterId = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/privateadx' + $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://privateadx.westus.kusto.windows.net/Hub --cluster-resource-id $clusterId" + $result = Invoke-BashCommandWithPath $command $binDir + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'Warning: The Kusto cluster denies public query access' + $result.Output | Should -Match 'private endpoint ADX blocks direct KQL queries' + $result.Output | Should -Match 'https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations' + $result.Output | Should -Match 'SRE Agent ready' + } + finally { + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'routes deploy through the copied starter-lab infra and apply-extras path' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $deployContent = Get-Content -Path $script:DeployScript -Raw + $deployContent | Should -Match 'INFRA_DIR=.*infra' + $deployContent | Should -Match '\$\{INFRA_DIR\}/main\.bicep' + $deployContent | Should -Match 'apply-extras\.sh' + $deployContent | Should -Not -Match 'bicep/assemble-agent|hydrate-extensions' + + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') | Should -BeTrue + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/apply-extras.sh') | Should -BeTrue + } + } + + Context 'repo invariants' { + It 'removes shipped recipe identity defaults' { + $agentJson = Get-Content -Path $script:AgentJsonPath -Raw + $agentJson | Should -Not -Match '"identity"' + } + + It 'uses the current SRE Agent API, model provider, and sandbox configuration' { + $agentJson = Get-Content -Path $script:AgentJsonPath -Raw | ConvertFrom-Json + $mainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw + $sreAgentBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/modules/sre-agent.bicep') -Raw + $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw + + $agentJson.upgradeChannel | Should -Be 'Preview' + $agentJson.defaultModelProvider | Should -Be 'MicrosoftFoundry' + $agentJson.defaultModelName | Should -Be 'Automatic' + $agentJson.experimentalSettings.EnableSandboxGroup | Should -BeTrue + $agentJson.experimentalSettings.EnableWorkspaceTools | Should -BeTrue + $sreAgentBicep | Should -Match 'Microsoft\.App/agents@2026-01-01' + $sreAgentBicep | Should -Not -Match 'Microsoft\.App/agents@2025-05-01-preview' + $sreAgentBicep | Should -Match 'defaultModel:' + $sreAgentBicep | Should -Match 'provider: defaultModelProvider' + $sreAgentBicep | Should -Match 'name: defaultModelName' + $sreAgentBicep | Should -Match 'upgradeChannel: upgradeChannel' + $mainBicep | Should -Match 'defaultModelProvider' + $mainBicep | Should -Match 'defaultModelName' + $mainBicep | Should -Match 'EnableSandboxGroup' + $mainBicep | Should -Match 'EnableWorkspaceTools' + $verifyScript | Should -Match 'API_VERSION="2026-01-01"' + } + + It 'limits legacy config env-var references to the allowlist' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "git grep -nE 'FINOPS_HUB_CLUSTER_URI|FINOPS_HUB_CLUSTER_RESOURCE_ID|SRE_AGENT_NO_TELEMETRY' -- docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent" + $result.ExitCode | Should -Be 0 + + $paths = $result.Output -split "`n" | + Where-Object { $_ } | + ForEach-Object { ($_ -split ':', 2)[0] } | + Sort-Object -Unique + + $paths | Should -Be @( + 'docs-mslearn/toolkit/sre-agent/deploy.md', + 'src/templates/sre-agent/bin/build-extras.py', + 'src/templates/sre-agent/README.md', + 'src/templates/sre-agent/recipes/finops-hub/connectors.json' + ) + } + + It 'keeps connectors.secrets.env out of scripts' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "git grep -nE 'connectors\.secrets\.env' -- src/templates/sre-agent/bin src/templates/sre-agent/infra" + $result.ExitCode | Should -Be 1 + } + + It 'removes the legacy custom bicep deployment surface' { + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bicep') | Should -BeFalse + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/hydrate-extensions.sh') | Should -BeFalse + } + + It 'uses deterministic subscription and resource group identity for support resource names' { + $mainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw + $resourcesBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/resources.bicep') -Raw + + $mainBicep | Should -Match "agentResourceGroupId = subscriptionResourceId\('Microsoft\.Resources/resourceGroups', resourceGroupName\)" + $mainBicep | Should -Match 'namingSeed = toLower' + $mainBicep | Should -Match 'subscription\(\)\.subscriptionId' + $mainBicep | Should -Match 'agentResourceGroupId' + $mainBicep | Should -Match 'agentName' + + $resourcesBicep | Should -Match 'param namingSeed string' + $resourcesBicep | Should -Match 'uniqueSuffix = uniqueString\(namingSeed\)' + $resourcesBicep | Should -Not -Match 'resourceGroup\(\)\.id|deployment\(\)\.name' + } + + It 'applies subagents after their local handoff targets' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-post-provision-" + [guid]::NewGuid().ToString('N')) + $binDir = Join-Path $tempRoot 'bin' + $buildDir = Join-Path $tempRoot 'build' + $logPath = Join-Path $tempRoot 'agent-apply.log' + New-Item -ItemType Directory -Force -Path $binDir, $buildDir | Out-Null + + $fakeAz = Join-Path $binDir 'az' + Set-BashStub -Path $fakeAz -Content @' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "$*" == *"account get-access-token"* ]]; then + echo "fake-token" + exit 0 +fi + +if [[ "${1:-}" == "rest" ]]; then + echo "{}" + exit 0 +fi + +case "$*" in + *"account show"*|*"account set"*|*"version"*) + exit 0 + ;; +esac + +exit 1 +'@ + + $fakeCurl = Join-Path $binDir 'curl' + Set-BashStub -Path $fakeCurl -Content @' +#!/usr/bin/env bash +set -euo pipefail + +out="" +url="" +method="GET" +while [[ $# -gt 0 ]]; do + case "$1" in + -o) + out="$2" + shift 2 + ;; + -w) + shift 2 + ;; + -X) + method="$2" + shift 2 + ;; + -H|--data-binary) + shift 2 + ;; + http*) + url="$1" + shift + ;; + *) + shift + ;; + esac +done + +if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then + cat > "$out" <<'JSON' +{ + "value": [ + { "name": "chart-artifact-verification-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "document-index-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "ftk-output-style-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "known-issues-and-workarounds-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "onboarding-recommendations-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "teams-notification-guide-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } + ] +} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then + cat > "$out" <<'JSON' +{ + "type": "KnowledgeItem", + "properties": { + "dataConnectorType": "KnowledgeFile", + "extendedProperties": { + "createdAt": "2026-05-25T19:57:31Z", + "lastModifiedAt": "2026-05-25T19:57:31Z" + } + } +} +JSON + if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/agents/* ]]; then + [[ -n "${AGENT_APPLY_LOG:-}" ]] && basename "$url" >> "$AGENT_APPLY_LOG" + cat > "$out" <<'JSON' +{ + "type": "ExtendedAgent", + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/agent/tools/configure ]]; then + cat > "$out" <<'JSON' +{} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v1/scheduledtasks ]]; then + cat > "$out" <<'JSON' +[] +JSON + printf "200" + exit 0 +fi + +cat > "$out" <<'JSON' +{ + "files": [ + { "name": "chart-artifact-verification-md", "isIndexed": true, "errorReason": null }, + { "name": "document-index-md", "isIndexed": true, "errorReason": null }, + { "name": "ftk-output-style-md", "isIndexed": true, "errorReason": null }, + { "name": "known-issues-and-workarounds-md", "isIndexed": true, "errorReason": null }, + { "name": "onboarding-recommendations-md", "isIndexed": true, "errorReason": null }, + { "name": "teams-notification-guide-md", "isIndexed": true, "errorReason": null } + ], + "continuationToken": "" +} +JSON +printf "200" +'@ + + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' +#!/usr/bin/env bash +exit 0 +'@ + + try { + $command = "AGENT_APPLY_LOG='$logPath' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:PostProvisionScript' --endpoint https://example.azuresre.ai --subscription 00000000-0000-0000-0000-000000000000 --resource-group rg-test-customer --name customer-sre-agent --recipe '$script:RecipeDir' --build-dir '$buildDir'" + $result = Invoke-BashCommandWithPath $command $binDir + $result.ExitCode | Should -Be 0 + + $order = @(Get-Content -Path $logPath) + [array]::IndexOf($order, 'chief-financial-officer') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) + [array]::IndexOf($order, 'ftk-database-query') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) + [array]::IndexOf($order, 'ftk-hubs-agent') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) + } + finally { + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'derives expected recipe connectors for verification' { + $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw + + $verifyScript | Should -Match 'connectors\.json' + $verifyScript | Should -Match 'EXPECTED_CONNECTORS' + $verifyScript | Should -Match 'EXP_CONN_CT=.*EXPECTED_CONNECTORS' + $verifyScript | Should -Match 'EXP_CONN_NAMES=.*EXPECTED_CONNECTORS' + } + + It 'uploads the shared FinOps output style as a portal knowledge source' { + $applyExtrasScript = Get-Content -Path $script:ApplyExtrasScript -Raw + $buildExtrasScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/build-extras.py') -Raw + + Test-Path $script:OutputStylePath | Should -BeTrue + $buildExtrasScript | Should -Match 'claude-plugin/output-styles/ftk-output-style\.md' + $buildExtrasScript | Should -Match 'Output style knowledge document not found' + $applyExtrasScript | Should -Match 'knowledgeItems' + $applyExtrasScript | Should -Match '/api/v2/extendedAgent/connectors' + $applyExtrasScript | Should -Match 'Knowledge sources failed to index' + $applyExtrasScript | Should -Match 'KnowledgeFile' + $applyExtrasScript | Should -Not -Match ('sr' + 'ectl') + $applyExtrasScript | Should -Not -Match '/api/v1/agentmemory/files' + } + + It 'requires expected knowledge sources and verifies indexing' { + $expectedConfig = Get-Content -Path (Join-Path $script:RecipeDir 'expected-config.json') -Raw | ConvertFrom-Json + $verifyScript = Get-Content -Path $script:VerifyScript -Raw + + $expectedConfig.knowledgeSources.Count | Should -Be 6 + $expectedConfig.knowledgeSources | Should -Contain 'ftk-output-style.md' + $expectedConfig.PSObject.Properties.Name | Should -Not -Contain 'knowledgeDocs' + $verifyScript | Should -Match '/api/v2/extendedAgent/connectors' + $verifyScript | Should -Match '\$expected\[\] \| \. as \$name \| select\(\$actual \| index\(\$name\)\)' + $verifyScript | Should -Match 'Knowledge sources expected' + $verifyScript | Should -Match 'Knowledge sources indexed' + $verifyScript | Should -Match 'Unindexed knowledge sources' + $verifyScript | Should -Not -Match '/api/v1/agentmemory' + $verifyScript | Should -Not -Match '"knowledge_" \+' + $verifyScript | Should -Not -Match 'Knowledge connector rows' + } + + It 'does not duplicate response plan verification with dead incident-filter scan state' { + $verifyScript = Get-Content -Path $script:VerifyScript -Raw + + ([regex]::Matches($verifyScript, 'check "Filter names"')).Count | Should -Be 1 + $verifyScript | Should -Not -Match 'EXP_FILTERS' + $verifyScript | Should -Not -Match 'automations/incident-filters' + } + + It 'requires every scheduled task to apply the shared output style' { + $taskFiles = @(Get-ChildItem -Path $script:ScheduledTaskDir -Filter '*.yaml') + $taskFiles.Count | Should -Be 19 + + $expectedInstruction = [regex]::Escape('Output style: Apply `ftk-output-style.md`') + foreach ($file in $taskFiles) { + $content = Get-Content -Path $file.FullName -Raw + $content | Should -Match $expectedInstruction + } + } + + It 'deletes existing scheduled tasks before applying manifests' { + $applyExtrasScript = Get-Content -Path $script:ApplyExtrasScript -Raw + $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw + + $applyExtrasScript | Should -Match 'delete_existing_scheduled_tasks' + $applyExtrasScript | Should -Match '/api/v1/scheduledtasks' + $applyExtrasScript | Should -Match 'dataplane_put_extended "scheduledtasks"' + $verifyScript | Should -Match 'Scheduled task duplicates' + $verifyScript | Should -Match '0 duplicates' + } + + } + + Context 'copy-and-update deployment contract' { + It 'rejects what-if because the copied starter-lab flow deploys directly' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test -n test-agent -l westus3 --what-if" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'unknown flag' + } + + It 'documents that azd is not used' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "git grep -nF 'azd' -- src/templates/sre-agent/bin src/templates/sre-agent/infra docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent/README.md" + $result.Output | Should -Match 'azd' + $result.Output | Should -Match 'not used|doesn''t use' + } + } +} From b332089fff46b2ae69bf567473f500d4940ca9d1 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 09:45:43 -0700 Subject: [PATCH 03/10] fix(sre-agent): address deploy CI failures --- docs-mslearn/toolkit/hubs/configure-sre.md | 26 +++++++++---------- docs-mslearn/toolkit/sre-agent/agents.md | 6 ++--- docs-mslearn/toolkit/sre-agent/get-started.md | 2 +- docs-mslearn/toolkit/sre-agent/knowledge.md | 6 ++--- docs-mslearn/toolkit/sre-agent/kusto-tools.md | 4 +-- docs-mslearn/toolkit/sre-agent/overview.md | 6 ++--- .../toolkit/sre-agent/python-tools.md | 2 +- .../toolkit/sre-agent/scheduled-tasks.md | 4 +-- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 2 +- 9 files changed, 29 insertions(+), 29 deletions(-) diff --git a/docs-mslearn/toolkit/hubs/configure-sre.md b/docs-mslearn/toolkit/hubs/configure-sre.md index 37f888dcd..0dd1deacf 100644 --- a/docs-mslearn/toolkit/hubs/configure-sre.md +++ b/docs-mslearn/toolkit/hubs/configure-sre.md @@ -13,7 +13,7 @@ ms.reviewer: micflan # Configure an SRE agent for FinOps hubs -[Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) supports agent-based operational workflows. This article shows how to connect Azure SRE Agent to a [FinOps hub](finops-hubs-overview.md), configure scheduled cost analysis and capacity checks from the [SRE agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent), and send results to Teams with the [Teams notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). +[Azure SRE Agent](/azure/sre-agent/overview) supports agent-based operational workflows. This article shows how to connect Azure SRE Agent to a [FinOps hub](finops-hubs-overview.md), configure scheduled cost analysis and capacity checks from the [SRE agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent), and send results to Teams with the [Teams notification connector](/azure/sre-agent/send-notifications).
@@ -22,8 +22,8 @@ ms.reviewer: micflan - [Deployed a FinOps hub instance](finops-hubs-overview.md#create-a-new-hub) with Data Explorer. - [Configured scopes](configure-scopes.md) and ingested data successfully. - Permissions to create deployed resources, such as **Contributor** on the subscription when the template creates the agent resource group. You also need permissions to assign roles at subscription, target resource group, and agent scopes, such as **Role Based Access Control Administrator**, **User Access Administrator**, or **Owner** on those scopes. [Learn more](/azure/role-based-access-control/built-in-roles). -- The `Microsoft.App` resource provider [registered](https://learn.microsoft.com/azure/azure-resource-manager/management/resource-providers-and-types#register-resource-provider) on the subscription. -- For local CLI deployments only: [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) 2.60 or later, `curl`, `jq`, `python3`, and `bash` available locally for the [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent). +- The `Microsoft.App` resource provider [registered](/azure/azure-resource-manager/management/resource-providers-and-types#register-resource-provider) on the subscription. +- For local CLI deployments only: [Azure CLI](/cli/azure/install-azure-cli) 2.60 or later, `curl`, `jq`, `python3`, and `bash` available locally for the [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent).
@@ -33,7 +33,7 @@ The [SRE agent template](https://github.com/microsoft/finops-toolkit/tree/main/s | Component | Count | Description | |-----------|-------|-------------| -| SRE agent | 1 | Stable [`Microsoft.App/agents`](https://learn.microsoft.com/azure/sre-agent/overview) resource in [autonomous mode](https://learn.microsoft.com/azure/sre-agent/run-modes) | +| SRE agent | 1 | Stable [`Microsoft.App/agents`](/azure/sre-agent/overview) resource in [autonomous mode](/azure/sre-agent/run-modes) | | Managed identities | 1-2 | System-assigned managed identity for the agent; portal deployments also create a user-assigned identity for the deployment script | | Log Analytics | 1 | Workspace for agent telemetry | | Application Insights | 1 | Linked to Log Analytics for monitoring | @@ -132,7 +132,7 @@ After `bin/deploy.sh` completes, use the template's [post-deployment verificatio ## Configure Teams notifications -Scheduled tasks can send reports to a Teams channel through the [Teams notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). The connector requires interactive OAuth setup in the portal. +Scheduled tasks can send reports to a Teams channel through the [Teams notification connector](/azure/sre-agent/send-notifications). The connector requires interactive OAuth setup in the portal. 1. Open [sre.azure.com](https://sre.azure.com), open your agent, then go to **Builder** > **Connectors**. 2. Select **Add connector** > **Send notification (Microsoft Teams)**. @@ -142,7 +142,7 @@ Scheduled tasks can send reports to a Teams channel through the [Teams notificat Use the built-in `PostTeamsMessage` tool from the [Teams notification guidance](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/recipes/finops-hub/knowledge/teams-notification-guide.md). Don't call the Microsoft Graph API or the connection's `dynamicInvoke` endpoint directly because that path returns a 403 error for this connector configuration. -For Outlook notifications, follow the same pattern with the **Outlook Tools (Office 365 Outlook)** connector. See [Send notifications](https://learn.microsoft.com/azure/sre-agent/send-notifications) for details. +For Outlook notifications, follow the same pattern with the **Outlook Tools (Office 365 Outlook)** connector. See [Send notifications](/azure/sre-agent/send-notifications) for details.
@@ -172,7 +172,7 @@ The template deploys 19 scheduled tasks from the [`recipes/finops-hub/automation | Semiannual | finops-practitioner | January 5 and July 5 at 9:00 AM | Semiannual year-over-year finance analysis with forecast and CFO consultation | | CapacityQuarterlyStrategy | finops-practitioner | Quarterly 9:00 AM | FinOps capability maturity, commitment alignment, and architecture review | -Each scheduled task reads the uploaded knowledge documents before it starts and applies `ftk-output-style.md` for evidence, formatting, FinOps capability mapping, confidence, and caveat conventions. Send financial results to Teams through the configured [notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). Save only operational notes, such as tool errors, workarounds, and patterns, to agent [memory](https://learn.microsoft.com/azure/sre-agent/memory) with `#remember`; don't save financial data. +Each scheduled task reads the uploaded knowledge documents before it starts and applies `ftk-output-style.md` for evidence, formatting, FinOps capability mapping, confidence, and caveat conventions. Send financial results to Teams through the configured [notification connector](/azure/sre-agent/send-notifications). Save only operational notes, such as tool errors, workarounds, and patterns, to agent [memory](/azure/sre-agent/memory) with `#remember`; don't save financial data.
@@ -194,10 +194,10 @@ Browser success with CLI failure indicates that the CLI token was issued for the Azure SRE Agent includes platform capabilities that are on by default in this template: -- **Workspace tools**: Azure SRE Agent can run file, terminal, and Python operations in a sandboxed environment for data analysis, chart generation, and report formatting. The [Bicep template](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/infra/modules/sre-agent.bicep) deploys the stable agent API and sets `experimentalSettings.EnableSandboxGroup` and `experimentalSettings.EnableWorkspaceTools`. See [Deep context](https://learn.microsoft.com/azure/sre-agent/workspace-tools). -- **DocsGuide**: DocsGuide provides Azure documentation grounding for agent responses. See [Use DocsGuide](https://learn.microsoft.com/azure/sre-agent/use-docsguide). -- **Visualization**: Built-in chart and table rendering for investigation results. See [Tools](https://learn.microsoft.com/azure/sre-agent/tools). -- **Memory**: Memory stores operational knowledge across sessions. See [Memory and knowledge](https://learn.microsoft.com/azure/sre-agent/memory). +- **Workspace tools**: Azure SRE Agent can run file, terminal, and Python operations in a sandboxed environment for data analysis, chart generation, and report formatting. The [Bicep template](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/infra/modules/sre-agent.bicep) deploys the stable agent API and sets `experimentalSettings.EnableSandboxGroup` and `experimentalSettings.EnableWorkspaceTools`. See [Deep context](/azure/sre-agent/workspace-tools). +- **DocsGuide**: DocsGuide provides Azure documentation grounding for agent responses. See [Use DocsGuide](/azure/sre-agent/use-docsguide). +- **Visualization**: Built-in chart and table rendering for investigation results. See [Tools](/azure/sre-agent/tools). +- **Memory**: Memory stores operational knowledge across sessions. See [Memory and knowledge](/azure/sre-agent/memory). The analytical subagents include `execute_python` where they need calculations, charts, tables, and downloadable artifacts. `finops-practitioner` orchestrates scheduled analysis, `ftk-database-query` owns Kusto evidence, `azure-capacity-manager` owns Azure capacity evidence, and `chief-financial-officer` provides finance and leadership consultation. @@ -237,8 +237,8 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) Related solutions: diff --git a/docs-mslearn/toolkit/sre-agent/agents.md b/docs-mslearn/toolkit/sre-agent/agents.md index 5411f4bb6..f074791d2 100644 --- a/docs-mslearn/toolkit/sre-agent/agents.md +++ b/docs-mslearn/toolkit/sre-agent/agents.md @@ -13,7 +13,7 @@ ms.reviewer: brettwil # Specialist agents and skills (Azure SRE Agent in the FinOps toolkit) -The FinOps toolkit configures [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) with a multi-agent architecture aligned to the canonical FinOps Framework. One orchestrator receives prompts and scheduled tasks, then delegates work to specialist subagents with focused FinOps, finance, capacity, database, and hub operations expertise. +The FinOps toolkit configures [Azure SRE Agent](/azure/sre-agent/overview) with a multi-agent architecture aligned to the canonical FinOps Framework. One orchestrator receives prompts and scheduled tasks, then delegates work to specialist subagents with focused FinOps, finance, capacity, database, and hub operations expertise. The template configures 5 subagents, 3 skills, 50 tools (37 generated Kusto tools and 13 Python tools), and a FinOps hub connector. The orchestrator keeps the experience simple. The specialist agents keep answers grounded in the right domain. @@ -349,8 +349,8 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) - [Azure Monitor](/azure/azure-monitor/) Related solutions: diff --git a/docs-mslearn/toolkit/sre-agent/get-started.md b/docs-mslearn/toolkit/sre-agent/get-started.md index 5b2981737..daa869ae7 100644 --- a/docs-mslearn/toolkit/sre-agent/get-started.md +++ b/docs-mslearn/toolkit/sre-agent/get-started.md @@ -120,7 +120,7 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure SRE Agent](/azure/sre-agent/overview) - [Azure Data Explorer](/azure/data-explorer/) - [Microsoft Cost Management](/azure/cost-management-billing/costs/) diff --git a/docs-mslearn/toolkit/sre-agent/knowledge.md b/docs-mslearn/toolkit/sre-agent/knowledge.md index 9a94d8dda..30ee26c5a 100644 --- a/docs-mslearn/toolkit/sre-agent/knowledge.md +++ b/docs-mslearn/toolkit/sre-agent/knowledge.md @@ -159,9 +159,9 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) -- [Microsoft Teams](https://learn.microsoft.com/microsoftteams/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) +- [Microsoft Teams](/microsoftteams/) Related solutions: diff --git a/docs-mslearn/toolkit/sre-agent/kusto-tools.md b/docs-mslearn/toolkit/sre-agent/kusto-tools.md index 19dfe39da..fbf33361c 100644 --- a/docs-mslearn/toolkit/sre-agent/kusto-tools.md +++ b/docs-mslearn/toolkit/sre-agent/kusto-tools.md @@ -484,8 +484,8 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) - [Microsoft Cost Management](/azure/cost-management-billing/costs/) Related solutions: diff --git a/docs-mslearn/toolkit/sre-agent/overview.md b/docs-mslearn/toolkit/sre-agent/overview.md index c7240abbf..e0f62bdb9 100644 --- a/docs-mslearn/toolkit/sre-agent/overview.md +++ b/docs-mslearn/toolkit/sre-agent/overview.md @@ -13,7 +13,7 @@ ms.reviewer: brettwil # Azure SRE Agent in the FinOps toolkit -The FinOps toolkit ships a Deploy to Azure template and a local Azure CLI + Bicep wrapper that deploy [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) and configure it for FinOps and capacity management workflows on top of [FinOps hubs](../hubs/finops-hubs-overview.md). The deployment includes specialist subagents, FOCUS-aligned Kusto and Python tools, scheduled tasks, and grounded knowledge so the agent can investigate cost changes, monitor quota and capacity signals, prepare executive summaries, and deliver scheduled updates. The deployment focuses on three core design principles: +The FinOps toolkit ships a Deploy to Azure template and a local Azure CLI + Bicep wrapper that deploy [Azure SRE Agent](/azure/sre-agent/overview) and configure it for FinOps and capacity management workflows on top of [FinOps hubs](../hubs/finops-hubs-overview.md). The deployment includes specialist subagents, FOCUS-aligned Kusto and Python tools, scheduled tasks, and grounded knowledge so the agent can investigate cost changes, monitor quota and capacity signals, prepare executive summaries, and deliver scheduled updates. The deployment focuses on three core design principles: - **Automate the rhythm**
_Run daily, weekly, monthly, and quarterly FinOps workflows without waiting for manual report requests._ - **Ground every answer**
_Use FinOps hub data, FOCUS-aligned Kusto tools, and Azure platform context to keep recommendations tied to evidence._ @@ -138,8 +138,8 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) - [Azure Monitor](/azure/azure-monitor/) Related solutions: diff --git a/docs-mslearn/toolkit/sre-agent/python-tools.md b/docs-mslearn/toolkit/sre-agent/python-tools.md index 1de0cce9f..31831392c 100644 --- a/docs-mslearn/toolkit/sre-agent/python-tools.md +++ b/docs-mslearn/toolkit/sre-agent/python-tools.md @@ -500,7 +500,7 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure SRE Agent](/azure/sre-agent/overview) - [Azure Resource Graph](/azure/governance/resource-graph/) - [Microsoft Cost Management](/azure/cost-management-billing/costs/) - [Azure Advisor](/azure/advisor/) diff --git a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md index f98f3e14a..608e277ca 100644 --- a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md +++ b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md @@ -264,8 +264,8 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) - [Azure Monitor](/azure/azure-monitor/) Related solutions: diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index b1042a83f..946e61225 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -47,7 +47,7 @@ Describe 'SRE Agent deploy template' { Push-Location $script:RepoRoot try { $originalPath = $env:PATH - $env:PATH = "${PathPrefix}:$originalPath" + $env:PATH = "${PathPrefix}$([System.IO.Path]::PathSeparator)$originalPath" $output = & bash -c $Command 2>&1 [pscustomobject]@{ ExitCode = $LASTEXITCODE From 3e8308180ce9dfb7eb67bdd14de12a93be69574f Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 09:53:24 -0700 Subject: [PATCH 04/10] test(sre-agent): normalize bash stub path on Windows --- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index 946e61225..bd9e2ab07 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -47,8 +47,9 @@ Describe 'SRE Agent deploy template' { Push-Location $script:RepoRoot try { $originalPath = $env:PATH - $env:PATH = "${PathPrefix}$([System.IO.Path]::PathSeparator)$originalPath" - $output = & bash -c $Command 2>&1 + $bashPathPrefix = ConvertTo-BashPath $PathPrefix + $quotedPathPrefix = ConvertTo-BashSingleQuoted $bashPathPrefix + $output = & bash -c "PATH=${quotedPathPrefix}:`$PATH $Command" 2>&1 [pscustomobject]@{ ExitCode = $LASTEXITCODE Output = ($output -join "`n") @@ -60,6 +61,30 @@ Describe 'SRE Agent deploy template' { } } + function ConvertTo-BashPath { + param( + [Parameter(Mandatory)] + [string] $Path + ) + + $quotedPath = ConvertTo-BashSingleQuoted $Path + $converted = & bash -lc "command -v cygpath >/dev/null 2>&1 && cygpath -u $quotedPath" 2>$null + if ($LASTEXITCODE -eq 0 -and $converted) { + return ($converted -join '') + } + + return $Path + } + + function ConvertTo-BashSingleQuoted { + param( + [Parameter(Mandatory)] + [string] $Value + ) + + return "'" + ($Value -replace "'", "'\''") + "'" + } + function Set-BashStub { param( [Parameter(Mandatory)] From 60d7857ca2407ee4d70eb5e9b5d1c1088f8bb25a Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 10:00:10 -0700 Subject: [PATCH 05/10] test(sre-agent): harden bash stub permissions --- .../Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index bd9e2ab07..4ee5c6ef3 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -96,7 +96,12 @@ Describe 'SRE Agent deploy template' { $utf8NoBom = [System.Text.UTF8Encoding]::new($false) [System.IO.File]::WriteAllText($Path, ($Content -replace "`r`n", "`n"), $utf8NoBom) - & chmod +x $Path + $bashPath = ConvertTo-BashPath $Path + $quotedPath = ConvertTo-BashSingleQuoted $bashPath + & bash -c "chmod +x $quotedPath" + if ($LASTEXITCODE -ne 0) { + throw "Failed to mark bash stub executable: $Path" + } } } @@ -480,7 +485,7 @@ exit 0 try { $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://example.westus3.kusto.windows.net/Hub" $result = Invoke-BashCommandWithPath $command $binDir - $result.ExitCode | Should -Be 0 + $result.ExitCode | Should -Be 0 -Because $result.Output $result.Output | Should -Match 'Resolving Kusto cluster resource ID from --cluster-uri' $result.Output | Should -Match '/providers/Microsoft\.Kusto/clusters/example' @@ -699,7 +704,7 @@ exit 0 $clusterId = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/privateadx' $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://privateadx.westus.kusto.windows.net/Hub --cluster-resource-id $clusterId" $result = Invoke-BashCommandWithPath $command $binDir - $result.ExitCode | Should -Be 0 + $result.ExitCode | Should -Be 0 -Because $result.Output $result.Output | Should -Match 'Warning: The Kusto cluster denies public query access' $result.Output | Should -Match 'private endpoint ADX blocks direct KQL queries' $result.Output | Should -Match 'https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations' @@ -965,7 +970,7 @@ exit 0 try { $command = "AGENT_APPLY_LOG='$logPath' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:PostProvisionScript' --endpoint https://example.azuresre.ai --subscription 00000000-0000-0000-0000-000000000000 --resource-group rg-test-customer --name customer-sre-agent --recipe '$script:RecipeDir' --build-dir '$buildDir'" $result = Invoke-BashCommandWithPath $command $binDir - $result.ExitCode | Should -Be 0 + $result.ExitCode | Should -Be 0 -Because $result.Output $order = @(Get-Content -Path $logPath) [array]::IndexOf($order, 'chief-financial-officer') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) From e46aa39106a4212403b1c89fd1038eedfbf85b04 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 10:06:58 -0700 Subject: [PATCH 06/10] test(sre-agent): stub extras builder in deploy tests --- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index 4ee5c6ef3..ff328ebc8 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -103,6 +103,67 @@ Describe 'SRE Agent deploy template' { throw "Failed to mark bash stub executable: $Path" } } + + function Set-PythonExtrasStub { + param( + [Parameter(Mandatory)] + [string] $BinDir + ) + + $realPython = (Get-Command python3 -ErrorAction SilentlyContinue).Source + if (-not $realPython) { + $realPython = (Get-Command python -ErrorAction Stop).Source + } + $realPython = ConvertTo-BashPath $realPython + + Set-BashStub -Path (Join-Path $BinDir 'python3') -Content @" +#!/usr/bin/env bash +set -euo pipefail +real_python='$realPython' + +if [[ "`$\{1:-\}" == "-c" && "`$\{2:-\}" == "import yaml" ]]; then + exit 0 +fi + +if [[ "`$\{1:-\}" == */build-extras.py ]]; then + output="" + while [[ "`$#" -gt 0 ]]; do + case "`$1" in + --output) + output="`$2" + shift 2 + ;; + *) + shift + ;; + esac + done + + [[ -n "`$output" ]] || exit 2 + mkdir -p "`$(dirname "`$output")" + cat > "`$output" <<'JSON' +{ + "connectors": [], + "builtInTools": { "overrides": [] }, + "knowledgeItems": [], + "tools": [], + "skills": [], + "subagents": [ + { "metadata": { "name": "chief-financial-officer" }, "spec": { "description": "test" } }, + { "metadata": { "name": "ftk-database-query" }, "spec": { "description": "test" } }, + { "metadata": { "name": "ftk-hubs-agent" }, "spec": { "description": "test" } }, + { "metadata": { "name": "finops-practitioner" }, "spec": { "description": "test" } } + ], + "scheduledTasks": [] +} +JSON + printf '{"connectors":0,"knowledgeItems":0,"tools":0,"skills":0,"subagents":4,"scheduledTasks":0}\n' + exit 0 +fi + +exec "`$real_python" "`$@" +"@ + } } Context 'bash availability' { @@ -477,6 +538,8 @@ JSON printf "200" '@ + Set-PythonExtrasStub -BinDir $binDir + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' #!/usr/bin/env bash exit 0 @@ -695,6 +758,8 @@ JSON printf "200" '@ + Set-PythonExtrasStub -BinDir $binDir + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' #!/usr/bin/env bash exit 0 @@ -962,6 +1027,8 @@ JSON printf "200" '@ + Set-PythonExtrasStub -BinDir $binDir + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' #!/usr/bin/env bash exit 0 From de97720371de5f424b3f1f462eea102510dedfba Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 10:14:36 -0700 Subject: [PATCH 07/10] test(sre-agent): fix Windows Python extras stub --- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index ff328ebc8..f16c0be30 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -115,22 +115,23 @@ Describe 'SRE Agent deploy template' { $realPython = (Get-Command python -ErrorAction Stop).Source } $realPython = ConvertTo-BashPath $realPython + $realPythonLiteral = ConvertTo-BashSingleQuoted $realPython - Set-BashStub -Path (Join-Path $BinDir 'python3') -Content @" + $stubContent = @' #!/usr/bin/env bash set -euo pipefail -real_python='$realPython' +real_python=__REAL_PYTHON__ -if [[ "`$\{1:-\}" == "-c" && "`$\{2:-\}" == "import yaml" ]]; then +if [[ "${1:-}" == "-c" && "${2:-}" == "import yaml" ]]; then exit 0 fi -if [[ "`$\{1:-\}" == */build-extras.py ]]; then +if [[ "${1:-}" == */build-extras.py ]]; then output="" - while [[ "`$#" -gt 0 ]]; do - case "`$1" in + while [[ "$#" -gt 0 ]]; do + case "$1" in --output) - output="`$2" + output="$2" shift 2 ;; *) @@ -139,9 +140,9 @@ if [[ "`$\{1:-\}" == */build-extras.py ]]; then esac done - [[ -n "`$output" ]] || exit 2 - mkdir -p "`$(dirname "`$output")" - cat > "`$output" <<'JSON' + [[ -n "$output" ]] || exit 2 + mkdir -p "$(dirname "$output")" + cat > "$output" <<'JSON' { "connectors": [], "builtInTools": { "overrides": [] }, @@ -161,8 +162,12 @@ JSON exit 0 fi -exec "`$real_python" "`$@" -"@ +exec "$real_python" "$@" +'@ + $stubContent = $stubContent.Replace('__REAL_PYTHON__', $realPythonLiteral) + + Set-BashStub -Path (Join-Path $BinDir 'python3') -Content $stubContent + Set-BashStub -Path (Join-Path $BinDir 'python') -Content $stubContent } } From 4ed9fb94d3126ecd81b29229e22cc643e7b2f34a Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 10:21:03 -0700 Subject: [PATCH 08/10] test(sre-agent): preserve Azure resource IDs on Windows --- src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index f16c0be30..83b7e3ad7 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -24,7 +24,7 @@ Describe 'SRE Agent deploy template' { Push-Location $script:RepoRoot try { - $output = & bash -lc $Command 2>&1 + $output = & bash -lc "MSYS2_ARG_CONV_EXCL='/subscriptions;/providers' $Command" 2>&1 [pscustomobject]@{ ExitCode = $LASTEXITCODE Output = ($output -join "`n") @@ -49,7 +49,7 @@ Describe 'SRE Agent deploy template' { $originalPath = $env:PATH $bashPathPrefix = ConvertTo-BashPath $PathPrefix $quotedPathPrefix = ConvertTo-BashSingleQuoted $bashPathPrefix - $output = & bash -c "PATH=${quotedPathPrefix}:`$PATH $Command" 2>&1 + $output = & bash -c "MSYS2_ARG_CONV_EXCL='/subscriptions;/providers' PATH=${quotedPathPrefix}:`$PATH $Command" 2>&1 [pscustomobject]@{ ExitCode = $LASTEXITCODE Output = ($output -join "`n") From fcd0beb9054b4d94f1b4bf66a1767225e37fed96 Mon Sep 17 00:00:00 2001 From: msbrett Date: Thu, 4 Jun 2026 06:19:53 -0700 Subject: [PATCH 09/10] fix(sre-agent): address PR review feedback - infra/main.bicep: union agent RG with targetResourceGroups so the agent RG is never omitted from targetRgIds (matches the portal entry point). - Build-Toolkit.ps1: restore Get-ChildItem -Force so dotfiles such as .upstream-pin, .gitignore, and .gitattributes are copied into the release output; restore the .DS_Store cleanup pass. - scheduled-tasks.md: change agent owner column to finops-practitioner for all 11 tasks that delegate to specialists in the prompt, matching the shipped YAML manifests; add a clarifying note about delegation. - tools.md, kusto-tools.md: replace ../../../src/... relative links with https://github.com/microsoft/finops-toolkit/tree/main/src/... so the links resolve on learn.microsoft.com. - docs-mslearn (14 files): bump ms.date to 06/04/2026 per AGENTS.md guidance for the update-mslearn-dates CI workflow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs-mslearn/toolkit/changelog.md | 2 +- docs-mslearn/toolkit/hubs/configure-sre.md | 2 +- docs-mslearn/toolkit/sre-agent/agents.md | 2 +- docs-mslearn/toolkit/sre-agent/deploy.md | 2 +- docs-mslearn/toolkit/sre-agent/get-started.md | 2 +- docs-mslearn/toolkit/sre-agent/knowledge.md | 2 +- docs-mslearn/toolkit/sre-agent/kusto-tools.md | 90 +++++++++---------- docs-mslearn/toolkit/sre-agent/overview.md | 2 +- .../toolkit/sre-agent/python-tools.md | 2 +- .../toolkit/sre-agent/scheduled-tasks.md | 26 +++--- docs-mslearn/toolkit/sre-agent/security.md | 2 +- docs-mslearn/toolkit/sre-agent/template.md | 2 +- docs-mslearn/toolkit/sre-agent/tools.md | 4 +- .../toolkit/sre-agent/troubleshooting.md | 2 +- src/scripts/Build-Toolkit.ps1 | 4 +- src/templates/sre-agent/infra/main.bicep | 2 +- 16 files changed, 76 insertions(+), 72 deletions(-) diff --git a/docs-mslearn/toolkit/changelog.md b/docs-mslearn/toolkit/changelog.md index c46cd6c5d..762824bfb 100644 --- a/docs-mslearn/toolkit/changelog.md +++ b/docs-mslearn/toolkit/changelog.md @@ -3,7 +3,7 @@ title: FinOps toolkit changelog description: Review the latest features and enhancements in the FinOps toolkit, including updates to FinOps hubs, Power BI reports, and more. author: MSBrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/hubs/configure-sre.md b/docs-mslearn/toolkit/hubs/configure-sre.md index 0dd1deacf..8a1810137 100644 --- a/docs-mslearn/toolkit/hubs/configure-sre.md +++ b/docs-mslearn/toolkit/hubs/configure-sre.md @@ -3,7 +3,7 @@ title: Configure an SRE agent for FinOps hubs description: Learn how to configure an Azure SRE agent to connect to your FinOps hub for scheduled cost analysis, capacity monitoring, and reporting. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: how-to ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/agents.md b/docs-mslearn/toolkit/sre-agent/agents.md index f074791d2..836779c74 100644 --- a/docs-mslearn/toolkit/sre-agent/agents.md +++ b/docs-mslearn/toolkit/sre-agent/agents.md @@ -3,7 +3,7 @@ title: Specialist agents and skills (Azure SRE Agent in the FinOps toolkit) description: Understand how the FinOps toolkit configures Azure SRE Agent with specialist agents, tools, skills, and knowledge to automate FinOps and capacity management work. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/deploy.md b/docs-mslearn/toolkit/sre-agent/deploy.md index 88e0c3dcc..25d5ed821 100644 --- a/docs-mslearn/toolkit/sre-agent/deploy.md +++ b/docs-mslearn/toolkit/sre-agent/deploy.md @@ -3,7 +3,7 @@ title: Deploy Azure SRE Agent with the FinOps toolkit description: Deploy the FinOps toolkit Azure SRE Agent template from the Azure portal or CLI, connect it to a FinOps hub Data Explorer cluster, and validate the deployment. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: tutorial ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/get-started.md b/docs-mslearn/toolkit/sre-agent/get-started.md index daa869ae7..eefc72449 100644 --- a/docs-mslearn/toolkit/sre-agent/get-started.md +++ b/docs-mslearn/toolkit/sre-agent/get-started.md @@ -3,7 +3,7 @@ title: Get started with the FinOps toolkit on Azure SRE Agent description: Learn what to do after deploying Azure SRE Agent with the FinOps toolkit — first queries, scheduled tasks, and specialized subagents. author: flanakin ms.author: micflan -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: quickstart ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/knowledge.md b/docs-mslearn/toolkit/sre-agent/knowledge.md index 30ee26c5a..985a92b4f 100644 --- a/docs-mslearn/toolkit/sre-agent/knowledge.md +++ b/docs-mslearn/toolkit/sre-agent/knowledge.md @@ -3,7 +3,7 @@ title: Manage knowledge and memory (Azure SRE Agent in the FinOps toolkit) description: Learn how knowledge grounds the FinOps toolkit's Azure SRE Agent in your team's context and how memory keeps operational learnings available across sessions and redeployments. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/kusto-tools.md b/docs-mslearn/toolkit/sre-agent/kusto-tools.md index fbf33361c..029e64f67 100644 --- a/docs-mslearn/toolkit/sre-agent/kusto-tools.md +++ b/docs-mslearn/toolkit/sre-agent/kusto-tools.md @@ -3,7 +3,7 @@ title: Kusto tools description: Review the FinOps hub Kusto tools the FinOps toolkit ships for Azure SRE Agent and learn when to use each tool for cost, commitment discount, anomaly, forecast, AI, and price analysis. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit @@ -13,7 +13,7 @@ ms.reviewer: brettwil # Kusto tools -The FinOps toolkit deployment configures Azure SRE Agent with 37 Kusto tools that query your FinOps hub Azure Data Explorer database through the `finops-hub-kusto` connector. Each tool is configured as a `KustoTool` and generated from the FinOps hub query catalog to ground agent responses in cost, price, recommendation, transaction, KPI, and AI usage data. Query source lives at [`src/queries/catalog`](../../../src/queries/catalog/). The SRE Agent recipe rejects explicit Kusto YAML files so the query catalog stays the only source for Kusto tool definitions. +The FinOps toolkit deployment configures Azure SRE Agent with 37 Kusto tools that query your FinOps hub Azure Data Explorer database through the `finops-hub-kusto` connector. Each tool is configured as a `KustoTool` and generated from the FinOps hub query catalog to ground agent responses in cost, price, recommendation, transaction, KPI, and AI usage data. Query source lives at [`src/queries/catalog`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/). The SRE Agent recipe rejects explicit Kusto YAML files so the query catalog stays the only source for Kusto tool definitions. This reference also calls out related optimization tools that appear in scheduled-task requirements when they affect the same analysis path. Those tools aren't Kusto tools unless explicitly marked as `KustoTool`. @@ -26,12 +26,12 @@ Use this reference when you want to understand which tool fits a prompt, schedul ## Source validation -The template generates every FinOps hub Kusto tool from the 37 `.kql` files in [`src/queries/catalog`](../../../src/queries/catalog/). The recipe keeps 13 `PythonTool` YAML files in [`src/templates/sre-agent/recipes/finops-hub/config/tools`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/). Build validation fails if an explicit Kusto YAML file is added, if a catalog query doesn't generate exactly one Kusto tool, if a KPI-linked query isn't generated as a Kusto tool, or if a KPI-linked query isn't requested by any scheduled task. +The template generates every FinOps hub Kusto tool from the 37 `.kql` files in [`src/queries/catalog`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/). The recipe keeps 13 `PythonTool` YAML files in [`src/templates/sre-agent/recipes/finops-hub/config/tools`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/). Build validation fails if an explicit Kusto YAML file is added, if a catalog query doesn't generate exactly one Kusto tool, if a KPI-linked query isn't generated as a Kusto tool, or if a KPI-linked query isn't requested by any scheduled task. | Source category | Count | Evidence | |-----------------|------:|----------| -| FinOps hub Kusto tools | 37 | Generated from [`src/queries/catalog/*.kql`](../../../src/queries/catalog/) by [`build-extras.py`](../../../src/templates/sre-agent/bin/build-extras.py). The catalog is indexed in [`src/queries/INDEX.md`](../../../src/queries/INDEX.md), and KPI-linked tools are mapped in [`src/queries/KPI.md`](../../../src/queries/KPI.md). | -| Related Python tools | 13 | [`benefit-recommendations`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/benefit-recommendations.yaml), [`capacity-reservation-groups`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/capacity-reservation-groups.yaml), [`data-freshness-check`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/data-freshness-check.yaml), [`db-service-quotas`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/db-service-quotas.yaml), [`deploy-anomaly-alert`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-anomaly-alert.yaml), [`deploy-budget`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-budget.yaml), [`deploy-bulk-anomaly-alerts`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-anomaly-alerts.yaml), [`deploy-bulk-budgets`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-budgets.yaml), [`non-compute-quotas`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/non-compute-quotas.yaml), [`resource-graph-query`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/resource-graph-query.yaml), [`sku-availability`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/sku-availability.yaml), [`suppress-advisor-recommendations`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/suppress-advisor-recommendations.yaml), and [`vm-quota-usage`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/vm-quota-usage.yaml) | +| FinOps hub Kusto tools | 37 | Generated from [`src/queries/catalog/*.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/) by [`build-extras.py`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/bin/build-extras.py). The catalog is indexed in [`src/queries/INDEX.md`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/INDEX.md), and KPI-linked tools are mapped in [`src/queries/KPI.md`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/KPI.md). | +| Related Python tools | 13 | [`benefit-recommendations`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/benefit-recommendations.yaml), [`capacity-reservation-groups`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/capacity-reservation-groups.yaml), [`data-freshness-check`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/data-freshness-check.yaml), [`db-service-quotas`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/db-service-quotas.yaml), [`deploy-anomaly-alert`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-anomaly-alert.yaml), [`deploy-budget`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-budget.yaml), [`deploy-bulk-anomaly-alerts`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-anomaly-alerts.yaml), [`deploy-bulk-budgets`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-budgets.yaml), [`non-compute-quotas`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/non-compute-quotas.yaml), [`resource-graph-query`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/resource-graph-query.yaml), [`sku-availability`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/sku-availability.yaml), [`suppress-advisor-recommendations`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/suppress-advisor-recommendations.yaml), and [`vm-quota-usage`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/vm-quota-usage.yaml) |
@@ -41,7 +41,7 @@ Use cost analysis tools to review cost and usage from different reporting angles ### costs-enriched-base -Source query: [`costs-enriched-base.kql`](../../../src/queries/catalog/costs-enriched-base.kql). +Source query: [`costs-enriched-base.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/costs-enriched-base.kql). Queries a guarded, enriched row-level cost and usage sample with tags, resource details, savings fields, commitment fields, and FinOps toolkit metadata. @@ -53,7 +53,7 @@ Sample output shape: One row per cost record with fields such as `ChargePeriodSt ### monthly-cost-trend -Source query: [`monthly-cost-trend.kql`](../../../src/queries/catalog/monthly-cost-trend.kql). +Source query: [`monthly-cost-trend.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/monthly-cost-trend.kql). Queries monthly billed and effective cost totals to show cost trends over time. @@ -65,7 +65,7 @@ Sample output shape: One row per month with `x_ChargeMonth`, `BilledCost`, and ` ### monthly-cost-change-percentage -Source query: [`monthly-cost-change-percentage.kql`](../../../src/queries/catalog/monthly-cost-change-percentage.kql). +Source query: [`monthly-cost-change-percentage.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/monthly-cost-change-percentage.kql). Queries month-over-month billed and effective cost changes as percentages. @@ -77,7 +77,7 @@ Sample output shape: One row per month with `ChargePeriodStart`, `BilledCost`, ` ### quarterly-cost-by-resource-group -Source query: [`quarterly-cost-by-resource-group.kql`](../../../src/queries/catalog/quarterly-cost-by-resource-group.kql). +Source query: [`quarterly-cost-by-resource-group.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/quarterly-cost-by-resource-group.kql). Queries quarterly cost by resource group, subscription, and month for a reporting window. @@ -89,7 +89,7 @@ Sample output shape: One row per subscription, resource group, and month with `S ### cost-by-region-trend -Source query: [`cost-by-region-trend.kql`](../../../src/queries/catalog/cost-by-region-trend.kql). +Source query: [`cost-by-region-trend.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/cost-by-region-trend.kql). Queries effective cost trends by Azure region. @@ -101,7 +101,7 @@ Sample output shape: One row per region with `RegionName` and `EffectiveCost`. ### cost-by-financial-hierarchy -Source query: [`cost-by-financial-hierarchy.kql`](../../../src/queries/catalog/cost-by-financial-hierarchy.kql). +Source query: [`cost-by-financial-hierarchy.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/cost-by-financial-hierarchy.kql). Queries costs organized by billing profile, invoice section, team, product, application, environment, and other financial hierarchy fields. @@ -113,7 +113,7 @@ Sample output shape: One row per financial hierarchy combination with `x_Billing ### top-services-by-cost -Source query: [`top-services-by-cost.kql`](../../../src/queries/catalog/top-services-by-cost.kql). +Source query: [`top-services-by-cost.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/top-services-by-cost.kql). Queries the Azure services with the highest effective cost. @@ -125,7 +125,7 @@ Sample output shape: One row per service with `ServiceName` and `EffectiveCost`. ### top-resource-types-by-cost -Source query: [`top-resource-types-by-cost.kql`](../../../src/queries/catalog/top-resource-types-by-cost.kql). +Source query: [`top-resource-types-by-cost.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/top-resource-types-by-cost.kql). Queries the resource types with the highest effective cost and resource counts. @@ -137,7 +137,7 @@ Sample output shape: One row per resource type with `ResourceType`, `ResourceCou ### top-resource-groups-by-cost -Source query: [`top-resource-groups-by-cost.kql`](../../../src/queries/catalog/top-resource-groups-by-cost.kql). +Source query: [`top-resource-groups-by-cost.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/top-resource-groups-by-cost.kql). Queries the resource groups with the highest effective cost. @@ -155,7 +155,7 @@ Use commitment discount tools to review reservation and savings plan utilization ### commitment-discount-utilization -Source query: [`commitment-discount-utilization.kql`](../../../src/queries/catalog/commitment-discount-utilization.kql). +Source query: [`commitment-discount-utilization.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/commitment-discount-utilization.kql). Queries consumed core hours by commitment discount type, including reservation, savings plan, and on-demand usage. @@ -167,7 +167,7 @@ Sample output shape: One row per commitment category with `CommitmentDiscountTyp ### reservation-recommendation-breakdown -Source query: [`reservation-recommendation-breakdown.kql`](../../../src/queries/catalog/reservation-recommendation-breakdown.kql). +Source query: [`reservation-recommendation-breakdown.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/reservation-recommendation-breakdown.kql). Queries detailed reservation recommendations, including savings, break-even dates, normalized sizes, scope, and term details. @@ -179,7 +179,7 @@ Sample output shape: One row per reservation recommendation with fields such as ### benefit-recommendations -Source query: [`benefit-recommendations.kql`](../../../src/queries/catalog/benefit-recommendations.kql). +Source query: [`benefit-recommendations.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/benefit-recommendations.kql). Gets Microsoft Cost Management benefit recommendations for savings plans and reserved instances at a billing scope. @@ -191,7 +191,7 @@ Sample output shape: A JSON object with `billing_scope`, `lookback_period`, `ter ### savings-summary-report -Source query: [`savings-summary-report.kql`](../../../src/queries/catalog/savings-summary-report.kql). +Source query: [`savings-summary-report.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/savings-summary-report.kql). Queries list cost, effective cost, negotiated savings, commitment savings, total savings, and savings rate. @@ -203,7 +203,7 @@ Sample output shape: One row per billing currency with `BillingCurrency`, `ListC ### top-commitment-transactions -Source query: [`top-commitment-transactions.kql`](../../../src/queries/catalog/top-commitment-transactions.kql). +Source query: [`top-commitment-transactions.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/top-commitment-transactions.kql). Queries the largest non-usage commitment discount purchase transactions, including reservations and savings plans. @@ -221,7 +221,7 @@ Use anomaly detection tools to identify unusual cost patterns that need investig ### cost-anomaly-detection -Source query: [`cost-anomaly-detection.kql`](../../../src/queries/catalog/cost-anomaly-detection.kql). +Source query: [`cost-anomaly-detection.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/cost-anomaly-detection.kql). Queries cost time series and detects unusual spikes or drops across a configurable history window. @@ -239,7 +239,7 @@ Use forecasting tools to project future cost based on historical patterns. ### cost-forecasting-model -Source query: [`cost-forecasting-model.kql`](../../../src/queries/catalog/cost-forecasting-model.kql). +Source query: [`cost-forecasting-model.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/cost-forecasting-model.kql). Queries historical cost trends and projects future effective cost. @@ -257,7 +257,7 @@ Use AI/ML cost tools to analyze Azure OpenAI and related AI service costs, token ### ai-cost-by-application -Source query: [`ai-cost-by-application.kql`](../../../src/queries/catalog/ai-cost-by-application.kql). +Source query: [`ai-cost-by-application.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/ai-cost-by-application.kql). Queries AI and machine learning costs by application, team, and environment tags. @@ -269,7 +269,7 @@ Sample output shape: One row per application, team, environment, and cost center ### ai-daily-trend -Source query: [`ai-daily-trend.kql`](../../../src/queries/catalog/ai-daily-trend.kql). +Source query: [`ai-daily-trend.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/ai-daily-trend.kql). Queries daily AI and machine learning cost trends. @@ -281,7 +281,7 @@ Sample output shape: One row per day with `ChargePeriodStart`, daily AI cost, da ### ai-model-cost-comparison -Source query: [`ai-model-cost-comparison.kql`](../../../src/queries/catalog/ai-model-cost-comparison.kql). +Source query: [`ai-model-cost-comparison.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/ai-model-cost-comparison.kql). Queries AI model costs so the agent can compare costs across models. @@ -293,7 +293,7 @@ Sample output shape: One row per model with `Model`, `TokenCount`, `EffectiveCos ### ai-token-usage-breakdown -Source query: [`ai-token-usage-breakdown.kql`](../../../src/queries/catalog/ai-token-usage-breakdown.kql). +Source query: [`ai-token-usage-breakdown.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/ai-token-usage-breakdown.kql). Queries AI token usage by model, model version, and input or output direction. @@ -307,101 +307,101 @@ Sample output shape: One row per model and token direction with `Model`, `Direct ## FinOps KPI tools -FinOps KPI tools are generated from the query catalog and map to query links in [`src/queries/KPI.md`](../../../src/queries/KPI.md). Scheduled tasks request these tools through `ftk-database-query` for monthly, semiannual, health, anomaly, capacity, storage, monitoring, AI, and benefit-review scorecards. +FinOps KPI tools are generated from the query catalog and map to query links in [`src/queries/KPI.md`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/KPI.md). Scheduled tasks request these tools through `ftk-database-query` for monthly, semiannual, health, anomaly, capacity, storage, monitoring, AI, and benefit-review scorecards. ### percentage-unallocated-costs -Source query: [`percentage-unallocated-costs.kql`](../../../src/queries/catalog/percentage-unallocated-costs.kql). +Source query: [`percentage-unallocated-costs.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/percentage-unallocated-costs.kql). Measures the share of effective cost that lacks required allocation evidence for the reporting window. ### percentage-untagged-costs -Source query: [`percentage-untagged-costs.kql`](../../../src/queries/catalog/percentage-untagged-costs.kql). +Source query: [`percentage-untagged-costs.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/percentage-untagged-costs.kql). Measures the share of effective cost on resources that have no tags. ### tagging-policy-compliance -Source query: [`tagging-policy-compliance.kql`](../../../src/queries/catalog/tagging-policy-compliance.kql). +Source query: [`tagging-policy-compliance.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/tagging-policy-compliance.kql). Measures cost-weighted compliance with required tag keys. ### allocation-accuracy-index -Source query: [`allocation-accuracy-index.kql`](../../../src/queries/catalog/allocation-accuracy-index.kql). +Source query: [`allocation-accuracy-index.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/allocation-accuracy-index.kql). Measures directly attributed cost as a share of total effective cost. ### anomaly-detection-rate -Source query: [`anomaly-detection-rate.kql`](../../../src/queries/catalog/anomaly-detection-rate.kql). +Source query: [`anomaly-detection-rate.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/anomaly-detection-rate.kql). Measures the share of effective spend in anomaly-flagged daily buckets. ### anomaly-variance-total -Source query: [`anomaly-variance-total.kql`](../../../src/queries/catalog/anomaly-variance-total.kql). +Source query: [`anomaly-variance-total.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/anomaly-variance-total.kql). Quantifies signed and absolute unpredicted spend variance for detected anomaly events. ### cost-visibility-delay -Source query: [`cost-visibility-delay.kql`](../../../src/queries/catalog/cost-visibility-delay.kql). +Source query: [`cost-visibility-delay.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/cost-visibility-delay.kql). Measures cost data visibility delay from charge period end to Hub ingestion. ### data-update-frequency -Source query: [`data-update-frequency.kql`](../../../src/queries/catalog/data-update-frequency.kql). +Source query: [`data-update-frequency.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/data-update-frequency.kql). Measures FinOps hub ingestion update cadence from distinct ingestion timestamps. ### commitment-utilization-score -Source query: [`commitment-utilization-score.kql`](../../../src/queries/catalog/commitment-utilization-score.kql). +Source query: [`commitment-utilization-score.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/commitment-utilization-score.kql). Computes commitment utilization amount, potential, and score by commitment and currency. ### commitment-discount-waste -Source query: [`commitment-discount-waste.kql`](../../../src/queries/catalog/commitment-discount-waste.kql). +Source query: [`commitment-discount-waste.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/commitment-discount-waste.kql). Measures unused commitment value as a share of total commitment cost. ### compute-spend-commitment-coverage -Source query: [`compute-spend-commitment-coverage.kql`](../../../src/queries/catalog/compute-spend-commitment-coverage.kql). +Source query: [`compute-spend-commitment-coverage.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/compute-spend-commitment-coverage.kql). Measures compute spend covered by commitment discounts. ### compute-cost-per-core -Source query: [`compute-cost-per-core.kql`](../../../src/queries/catalog/compute-cost-per-core.kql). +Source query: [`compute-cost-per-core.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/compute-cost-per-core.kql). Computes hourly and effective average compute cost per consumed vCPU core hour. ### cost-optimization-index -Source query: [`cost-optimization-index.kql`](../../../src/queries/catalog/cost-optimization-index.kql). +Source query: [`cost-optimization-index.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/cost-optimization-index.kql). Computes the Hub-wide cost optimization index from current recommendations and cost context. ### cost-per-gb-stored -Source query: [`cost-per-gb-stored.kql`](../../../src/queries/catalog/cost-per-gb-stored.kql). +Source query: [`cost-per-gb-stored.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/cost-per-gb-stored.kql). Calculates storage cost per normalized GB-month. ### macc-consumption-vs-commitment -Source query: [`macc-consumption-vs-commitment.kql`](../../../src/queries/catalog/macc-consumption-vs-commitment.kql). +Source query: [`macc-consumption-vs-commitment.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/macc-consumption-vs-commitment.kql). Measures Microsoft Azure Consumption Commitment drawdown by billing profile and month. ### storage-tier-distribution -Source query: [`storage-tier-distribution.kql`](../../../src/queries/catalog/storage-tier-distribution.kql). +Source query: [`storage-tier-distribution.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/storage-tier-distribution.kql). Summarizes storage cost and GB-month distribution by access-tier bucket. @@ -413,7 +413,7 @@ Use Usage Optimization tools to identify idle, orphaned, or wasteful resources b ### idle-resource-sweep -Source status: No `idle-resource-sweep.yaml` file appears in the source inventory for [`src/templates/sre-agent/recipes/finops-hub/config/tools`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/). +Source status: No `idle-resource-sweep.yaml` file appears in the source inventory for [`src/templates/sre-agent/recipes/finops-hub/config/tools`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/config/tools/). Reviews idle or orphaned resource candidates for Usage Optimization. @@ -431,7 +431,7 @@ Use price analysis tools to compare prices, savings, and non-commitment transact ### service-price-benchmarking -Source query: [`service-price-benchmarking.kql`](../../../src/queries/catalog/service-price-benchmarking.kql). +Source query: [`service-price-benchmarking.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/service-price-benchmarking.kql). Queries service price benchmarks, including list cost, contracted cost, effective cost, negotiated savings, commitment savings, and total savings. @@ -443,7 +443,7 @@ Sample output shape: One row per service with `ServiceName`, `ListCost`, `Contra ### top-other-transactions -Source query: [`top-other-transactions.kql`](../../../src/queries/catalog/top-other-transactions.kql). +Source query: [`top-other-transactions.kql`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/top-other-transactions.kql). Queries the largest non-usage and non-commitment transactions, such as Marketplace or miscellaneous charges. diff --git a/docs-mslearn/toolkit/sre-agent/overview.md b/docs-mslearn/toolkit/sre-agent/overview.md index e0f62bdb9..3c8433299 100644 --- a/docs-mslearn/toolkit/sre-agent/overview.md +++ b/docs-mslearn/toolkit/sre-agent/overview.md @@ -3,7 +3,7 @@ title: Azure SRE Agent in the FinOps toolkit description: Learn how the FinOps toolkit deploys Azure SRE Agent with FinOps and capacity management automation on top of FinOps hubs. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/python-tools.md b/docs-mslearn/toolkit/sre-agent/python-tools.md index 31831392c..01a869551 100644 --- a/docs-mslearn/toolkit/sre-agent/python-tools.md +++ b/docs-mslearn/toolkit/sre-agent/python-tools.md @@ -3,7 +3,7 @@ title: Python tools description: Review the Python tools the FinOps toolkit ships for Azure SRE Agent for Azure quota, capacity, budgets, anomaly alerts, Resource Graph, FinOps hub health, and Advisor suppressions. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md index 608e277ca..f5afd9396 100644 --- a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md +++ b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md @@ -3,7 +3,7 @@ title: Scheduled tasks (Azure SRE Agent in the FinOps toolkit) description: Learn how the FinOps toolkit's scheduled tasks automate daily, weekly, monthly, and quarterly FinOps operating rhythms on Azure SRE Agent. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit @@ -23,10 +23,12 @@ The template deploys 19 scheduled tasks from `src/templates/sre-agent/recipes/fi Daily tasks run every morning to validate FinOps hub health and monitor Azure capacity signals that feed Planning & Estimating, Architecting & Workload Placement, Usage Optimization, Governance, Policy & Risk, and Automation, Tools & Services. They keep cost and capacity surprises visible before each business day. +The `Agent` column lists the owning agent that runs each task. Some prompts delegate to specialist agents (for example, `ftk-hubs-agent` or `azure-capacity-manager`) for portions of the work; that delegation happens inside the task prompt. + | Task | Agent | Schedule | Description | |------|-------|----------|-------------| -| `HubsHealthCheck` | `ftk-hubs-agent` | Daily at 6:00 AM
`0 6 * * *` | FinOps hub version and data freshness validation | -| `CapacityDailyMonitor` | `azure-capacity-manager` | Daily at 6:30 AM
`30 6 * * *` | Daily capacity health check — quota usage, CRG utilization, zone capacity | +| `HubsHealthCheck` | `finops-practitioner` | Daily at 6:00 AM
`0 6 * * *` | FinOps hub version and data freshness validation | +| `CapacityDailyMonitor` | `finops-practitioner` | Daily at 6:30 AM
`30 6 * * *` | Daily capacity health check — quota usage, CRG utilization, zone capacity |
@@ -36,13 +38,13 @@ Weekly tasks summarize cost optimization, Azure capacity evidence, and benefit r | Task | Agent | Schedule | Description | |------|-------|----------|-------------| -| `ComputeUtilizationTrend` | `azure-capacity-manager` | Weekly on Monday at 7:00 AM
`0 7 * * 1` | Weekly VM quota utilization trend review across subscriptions and regions | +| `ComputeUtilizationTrend` | `finops-practitioner` | Weekly on Monday at 7:00 AM
`0 7 * * 1` | Weekly VM quota utilization trend review across subscriptions and regions | | `CostOptimization` | `finops-practitioner` | Weekly on Monday at 8:00 AM
`0 8 * * 1` | Comprehensive cost optimization report with orphaned resources, rightsizing, and commitment analysis | -| `CapacityWeeklySupplyReview` | `azure-capacity-manager` | Weekly on Monday at 8:00 AM
`0 8 * * 1` | Weekly capacity evidence review — quota headroom, CRG cost optimization, SKU availability, benefit recommendations | -| `NonComputeQuotaAudit` | `azure-capacity-manager` | Weekly on Tuesday at 7:00 AM
`0 7 * * 2` | Weekly audit of storage, network, and non-compute quota usage at risk | -| `DbQuotaAudit` | `azure-capacity-manager` | Weekly on Wednesday at 7:00 AM
`0 7 * * 3` | Weekly audit of database quota and region or zone access risks | -| `SkuAvailabilityAudit` | `azure-capacity-manager` | Weekly on Wednesday at 7:30 AM
`30 7 * * 3` | Weekly audit of regional SKU availability and restrictions that could block deployments | -| `MonitoringScopeValidation` | `ftk-hubs-agent` | Weekly on Thursday at 9:00 AM
`0 9 * * 4` | Weekly validation that FinOps hub monitoring covers all active subscriptions | +| `CapacityWeeklySupplyReview` | `finops-practitioner` | Weekly on Monday at 8:00 AM
`0 8 * * 1` | Weekly capacity evidence review — quota headroom, CRG cost optimization, SKU availability, benefit recommendations | +| `NonComputeQuotaAudit` | `finops-practitioner` | Weekly on Tuesday at 7:00 AM
`0 7 * * 2` | Weekly audit of storage, network, and non-compute quota usage at risk | +| `DbQuotaAudit` | `finops-practitioner` | Weekly on Wednesday at 7:00 AM
`0 7 * * 3` | Weekly audit of database quota and region or zone access risks | +| `SkuAvailabilityAudit` | `finops-practitioner` | Weekly on Wednesday at 7:30 AM
`30 7 * * 3` | Weekly audit of regional SKU availability and restrictions that could block deployments | +| `MonitoringScopeValidation` | `finops-practitioner` | Weekly on Thursday at 9:00 AM
`0 9 * * 4` | Weekly validation that FinOps hub monitoring covers all active subscriptions | | `BenefitRecommendationReview` | `finops-practitioner` | Weekly on Friday at 8:00 AM
`0 8 * * 5` | Weekly review of reservation and savings plan recommendations, with CFO consultation for decision framing |
@@ -53,9 +55,9 @@ Monthly tasks run after billing data finalizes to produce year-to-date analysis, | Task | Agent | Schedule | Description | |------|-------|----------|-------------| -| `StoragePaasGrowthForecast` | `azure-capacity-manager` | Monthly on the 1st at 8:00 AM
`0 8 1 * *` | Monthly storage and PaaS quota growth forecast across active subscriptions | +| `StoragePaasGrowthForecast` | `finops-practitioner` | Monthly on the 1st at 8:00 AM
`0 8 1 * *` | Monthly storage and PaaS quota growth forecast across active subscriptions | | `AdvisorSuppressionReview` | `finops-practitioner` | Monthly on the 1st at 9:00 AM
`0 9 1 * *` | Monthly review of active Advisor recommendation suppressions for stale or expired decisions | -| `CapacityMonthlyPlanning` | `azure-capacity-manager` | Monthly on the 1st at 9:00 AM
`0 9 1 * *` | Monthly capacity planning cycle — demand forecast, capacity request pipeline, governance review | +| `CapacityMonthlyPlanning` | `finops-practitioner` | Monthly on the 1st at 9:00 AM
`0 9 1 * *` | Monthly capacity planning cycle — demand forecast, capacity request pipeline, governance review | | `Monthly` | `finops-practitioner` | Monthly on the 5th at 5:15 PM
`15 17 5 * *` | Autonomous month-over-month cost analysis with FinOps hub tools | | `AIWorkloadCostAnalysis` | `finops-practitioner` | Monthly on the 1st at 10:00 AM
`0 10 1 * *` | Monthly AI workload cost analysis — token economics, model efficiency, and cost allocation for Azure OpenAI | | `Semiannual` | `finops-practitioner` | January 5 and July 5 at 9:00 AM
`0 9 5 1,7 *` | Semiannual year-over-year finance analysis with forecast and CFO consultation | @@ -70,7 +72,7 @@ Quarterly tasks run at the start of each calendar quarter to summarize capacity- | Task | Agent | Schedule | Description | |------|-------|----------|-------------| -| `CapacityQuarterlyStrategy` | `azure-capacity-manager` | Quarterly on January 1, April 1, July 1, and October 1 at 9:00 AM
`0 9 1 1,4,7,10 *` | Quarterly capacity strategy review — FinOps capability maturity, commitment alignment, architecture evolution | +| `CapacityQuarterlyStrategy` | `finops-practitioner` | Quarterly on January 1, April 1, July 1, and October 1 at 9:00 AM
`0 9 1 1,4,7,10 *` | Quarterly capacity strategy review — FinOps capability maturity, commitment alignment, architecture evolution |
diff --git a/docs-mslearn/toolkit/sre-agent/security.md b/docs-mslearn/toolkit/sre-agent/security.md index f4b7e0f6b..0b7d89305 100644 --- a/docs-mslearn/toolkit/sre-agent/security.md +++ b/docs-mslearn/toolkit/sre-agent/security.md @@ -3,7 +3,7 @@ title: Security and permissions for Azure SRE Agent in the FinOps toolkit description: Review the permissions, identities, run modes, and data flows the FinOps toolkit configures on Azure SRE Agent before you deploy it in your environment. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/template.md b/docs-mslearn/toolkit/sre-agent/template.md index 25c7474c6..80047181f 100644 --- a/docs-mslearn/toolkit/sre-agent/template.md +++ b/docs-mslearn/toolkit/sre-agent/template.md @@ -3,7 +3,7 @@ title: Azure SRE Agent template reference (FinOps toolkit) description: Review the FinOps toolkit's Azure SRE Agent deployment template, parameters, outputs, script flags, and Bicep module structure. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/tools.md b/docs-mslearn/toolkit/sre-agent/tools.md index a8447b62f..3ff74be88 100644 --- a/docs-mslearn/toolkit/sre-agent/tools.md +++ b/docs-mslearn/toolkit/sre-agent/tools.md @@ -3,7 +3,7 @@ title: Tools shipped for Azure SRE Agent in the FinOps toolkit description: Review the Kusto and Python tools the FinOps toolkit ships for Azure SRE Agent for cost analysis, anomaly detection, rate optimization, capacity management, and operations. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit @@ -58,7 +58,7 @@ Cost analysis and reporting tools summarize FinOps hub cost data by service, reg ## FinOps KPI scorecard -FinOps KPI scorecard tools are generated from [`src/queries/catalog`](../../../src/queries/catalog/) and map directly to query links in [`src/queries/KPI.md`](../../../src/queries/KPI.md). Scheduled monthly, semiannual, health, anomaly, capacity, storage, monitoring, and benefit-review tasks request these tools through `ftk-database-query`. +FinOps KPI scorecard tools are generated from [`src/queries/catalog`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/catalog/) and map directly to query links in [`src/queries/KPI.md`](https://github.com/microsoft/finops-toolkit/tree/main/src/queries/KPI.md). Scheduled monthly, semiannual, health, anomaly, capacity, storage, monitoring, and benefit-review tasks request these tools through `ftk-database-query`. | Tool | Type | Description | Agents | |------|------|-------------|--------| diff --git a/docs-mslearn/toolkit/sre-agent/troubleshooting.md b/docs-mslearn/toolkit/sre-agent/troubleshooting.md index 53a5af68c..d11ec0516 100644 --- a/docs-mslearn/toolkit/sre-agent/troubleshooting.md +++ b/docs-mslearn/toolkit/sre-agent/troubleshooting.md @@ -3,7 +3,7 @@ title: Troubleshoot Azure SRE Agent deployments from the FinOps toolkit description: Resolve common deployment, tenant, connector, data, and query issues for Azure SRE Agent deployments from the FinOps toolkit. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: how-to ms.service: finops ms.subservice: finops-toolkit diff --git a/src/scripts/Build-Toolkit.ps1 b/src/scripts/Build-Toolkit.ps1 index dfd7e336e..e447e41a5 100644 --- a/src/scripts/Build-Toolkit.ps1 +++ b/src/scripts/Build-Toolkit.ps1 @@ -198,10 +198,12 @@ $templates | ForEach-Object { # Copy required files Write-Host " Copying files..." - $sourceFiles = Get-ChildItem $srcDir | Where-Object { $_.Name -notin @(".build.config", ".buildignore", "scaffold.json") } + $sourceFiles = Get-ChildItem $srcDir -Force | Where-Object { $_.Name -notin @(".build.config", ".buildignore", "scaffold.json") } Write-Verbose " Copying $($sourceFiles.Count) items from source to destination" $sourceFiles | Copy-Item -Destination $destDir -Recurse + Get-ChildItem $destDir -Force -Recurse -Filter ".DS_Store" | Remove-Item -Force + # Run custom build scripts after copying files (operates on release copy, not source) if ($buildConfig.scripts.Count -gt 0) { diff --git a/src/templates/sre-agent/infra/main.bicep b/src/templates/sre-agent/infra/main.bicep index ff49374b9..99baf8339 100644 --- a/src/templates/sre-agent/infra/main.bicep +++ b/src/templates/sre-agent/infra/main.bicep @@ -57,7 +57,7 @@ param finopsHubKustoClusterResourceId string = '' @description('Assign Reader on the deployment subscription to the agent managed identity.') param enableSubscriptionReaderRole bool = true -var targetRgs = empty(targetResourceGroups) ? [resourceGroupName] : targetResourceGroups +var targetRgs = union([resourceGroupName], targetResourceGroups) var agentResourceGroupId = subscriptionResourceId('Microsoft.Resources/resourceGroups', resourceGroupName) var targetRgIds = [for rgName in targetRgs: subscriptionResourceId('Microsoft.Resources/resourceGroups', rgName)] var namingSeed = toLower('${subscription().subscriptionId}|${agentResourceGroupId}|${agentName}') From 2a565780dd34b0c24bb6e2547774f1c587e68cee Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 17 Jun 2026 09:41:41 -0700 Subject: [PATCH 10/10] fix(sre-agent): secure deploy defaults, package integrity, drop telemetry - Default portal/CLI to Low (read-only) access; keep autonomous reporting so the 19 scheduled report tasks run unattended on a least-privilege identity. Stop defaulting subscription-wide Reader. (Roland H1) - Verify the downloaded recipe package: require an expected SHA-256 (fail-closed) and an https host allowlist before Expand-Archive. (Roland H2) - Remove dead bin/telemetry.sh, its hardcoded App Insights key, and the no-op --no-telemetry / SRE_AGENT_NO_TELEMETRY opt-out. (Roland M4) - Parameterize deployer principalType so CI/CD OIDC service-principal deploys assign RBAC correctly. (Roland #2167-adjacent CI finding) Compiled azuredeploy.json + recipe zip are regenerated in a later build pass (two deferred tests remain red until then). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs-mslearn/toolkit/sre-agent/deploy.md | 16 +- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 143 +++++++++++++++++- src/templates/sre-agent/README.md | 11 +- src/templates/sre-agent/bin/deploy.sh | 16 +- src/templates/sre-agent/bin/telemetry.sh | 53 ------- .../sre-agent/createUiDefinition.json | 8 +- .../examples/ci-cd/github-actions-deploy.yml | 1 + src/templates/sre-agent/infra/main.bicep | 11 +- .../infra/modules/apply-extras.bicep | 7 + .../sre-agent/infra/modules/sre-agent.bicep | 6 +- src/templates/sre-agent/infra/resources.bicep | 5 + .../infra/scripts/Apply-SreAgentExtras.ps1 | 24 +++ src/templates/sre-agent/main.bicep | 17 ++- .../sre-agent/recipes/finops-hub/agent.json | 4 +- .../recipes/finops-hub/expected-config.json | 6 +- 15 files changed, 235 insertions(+), 93 deletions(-) delete mode 100755 src/templates/sre-agent/bin/telemetry.sh diff --git a/docs-mslearn/toolkit/sre-agent/deploy.md b/docs-mslearn/toolkit/sre-agent/deploy.md index 25d5ed821..86269d484 100644 --- a/docs-mslearn/toolkit/sre-agent/deploy.md +++ b/docs-mslearn/toolkit/sre-agent/deploy.md @@ -3,7 +3,7 @@ title: Deploy Azure SRE Agent with the FinOps toolkit description: Deploy the FinOps toolkit Azure SRE Agent template from the Azure portal or CLI, connect it to a FinOps hub Data Explorer cluster, and validate the deployment. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: tutorial ms.service: finops ms.subservice: finops-toolkit @@ -79,8 +79,7 @@ bash bin/deploy.sh \ [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] \ [--target-resource-group ...] \ [--dry-run] \ - [--force] \ - [--no-telemetry] + [--force] ``` `bin/deploy.sh --help` is the CLI contract: @@ -100,11 +99,10 @@ Optional: --cluster-uri Kusto connector URI, including database name. Example: https://..kusto.windows.net/Hub --cluster-resource-id Optional Kusto cluster ARM resource ID. Real deployments resolve this from --cluster-uri when possible; dry-run requires it. - --no-subscription-reader Do not assign Reader at subscription scope. Default: assign Reader. + --no-subscription-reader Do not assign Reader at subscription scope. Default: no subscription Reader (opt-in with --subscription-reader). --deploy-name Deployment name override. Defaults to a deterministic name. --dry-run Validate inputs and write parameters without Azure calls. --force Accepted for compatibility. - --no-telemetry Accepted for compatibility. -h, --help Show this help. ``` @@ -130,7 +128,7 @@ The recipe defaults the parent SRE Agent to Azure OpenAI provider-level routing Resource names are deterministic for the subscription ID, agent resource group ID, and agent name. Use the same values to update an existing deployment. Post-provisioning deletes existing scheduled tasks with the recipe's task names before applying manifests so redeployments don't create duplicate automations. `--deploy-name` only changes the ARM deployment record and local build directory. -The deployment assigns `Reader` at subscription scope by default so subscription inventory, Resource Graph, capacity, quota, and monitoring-coverage tools can inspect the deployment subscription. Pass `--no-subscription-reader` only when you grant equivalent read access another way. +The agent defaults to Low (read-only) access level for reporting and analysis without modification risk. Subscription Reader is opt-in (`--subscription-reader`) and only required for subscription-wide ARM-backed reports; otherwise the agent scopes reads via target resource groups. This posture allows the 19 scheduled reports to run autonomously while eliminating write blast radius. If `--cluster-uri` points to an Azure Data Explorer cluster with `publicNetworkAccess` set to `Disabled`, the script still deploys all resources, assigns the agent identity `AllDatabasesViewer`, and creates the `finops-hub-kusto` connector. It also prints a warning with the SRE Agent known-limitations URL because private endpoint ADX blocks direct KQL queries from the hosted agent. The customer can decide whether to enable public query access for the connector after reviewing . @@ -185,14 +183,13 @@ The included GitHub Actions example passes the cluster URI as a deploy flag whil ## Migrating from env-var-driven deploys -The old deploy flow used configuration inputs such as `FINOPS_HUB_CLUSTER_URI`, `FINOPS_HUB_CLUSTER_RESOURCE_ID`, `SRE_AGENT_NO_TELEMETRY`, and `connectors.secrets.env`. Those inputs are no longer supported for identity or config. +The old deploy flow used configuration inputs such as `FINOPS_HUB_CLUSTER_URI`, `FINOPS_HUB_CLUSTER_RESOURCE_ID`, and `connectors.secrets.env`. Those inputs are no longer supported for identity or config. Before: ```bash export FINOPS_HUB_CLUSTER_URI="https://..kusto.windows.net/hub" export FINOPS_HUB_CLUSTER_RESOURCE_ID="/subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/" -export SRE_AGENT_NO_TELEMETRY=1 bash bin/deploy.sh recipes/finops-hub ``` @@ -206,8 +203,7 @@ bash bin/deploy.sh \ --name \ --location \ --cluster-uri https://..kusto.windows.net/Hub \ - [--cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/] \ - --no-telemetry + [--cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/] ``` The only supported environment-variable inputs are secrets: diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index 83b7e3ad7..736b363c4 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -831,7 +831,7 @@ exit 0 It 'limits legacy config env-var references to the allowlist' { if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "git grep -nE 'FINOPS_HUB_CLUSTER_URI|FINOPS_HUB_CLUSTER_RESOURCE_ID|SRE_AGENT_NO_TELEMETRY' -- docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent" + $result = Invoke-BashCommand "git grep -nE 'FINOPS_HUB_CLUSTER_URI|FINOPS_HUB_CLUSTER_RESOURCE_ID' -- docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent" $result.ExitCode | Should -Be 0 $paths = $result.Output -split "`n" | @@ -847,6 +847,59 @@ exit 0 ) } + It 'requires recipe package hash validation before extraction' { + $applyExtrasScriptPath = Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1' + $applyExtrasLines = Get-Content -Path $applyExtrasScriptPath + $applyExtrasScript = $applyExtrasLines -join "`n" + + $applyExtrasScript | Should -Match "\$recipePackageSha256 = Get-RequiredEnv 'recipePackageSha256'" + $applyExtrasScript | Should -Match 'Get-FileHash\s+-Algorithm\s+SHA256' + $applyExtrasScript | Should -Match '(?s)recipePackageSha256.*throw' + + $hashLine = for ($i = 0; $i -lt $applyExtrasLines.Count; $i++) { + if ($applyExtrasLines[$i] -match 'Get-FileHash' -and $applyExtrasLines[$i] -match 'SHA256') { + $i + 1 + break + } + } + $throwLine = for ($i = 0; $i -lt $applyExtrasLines.Count; $i++) { + if ($applyExtrasLines[$i] -match 'throw' -and $applyExtrasLines[$i] -match 'hash|SHA256|recipePackageSha256') { + $i + 1 + break + } + } + $expandArchiveLine = for ($i = 0; $i -lt $applyExtrasLines.Count; $i++) { + if ($applyExtrasLines[$i] -match 'Expand-Archive') { + $i + 1 + break + } + } + + $hashLine | Should -BeGreaterThan 0 + $throwLine | Should -BeGreaterThan 0 + $expandArchiveLine | Should -BeGreaterThan 0 + $hashLine | Should -BeLessThan $expandArchiveLine + $throwLine | Should -BeLessThan $expandArchiveLine + } + + It 'declares recipePackageSha256 in the compiled deploy templates' { + foreach ($compiledPath in @( + (Join-Path $script:RepoRoot 'docs/deploy/sre-agent/latest/azuredeploy.json'), + (Join-Path $script:RepoRoot 'docs/deploy/sre-agent/14.0/azuredeploy.json') + )) { + $compiledTemplate = Get-Content -Path $compiledPath -Raw | ConvertFrom-Json -Depth 100 + $compiledTemplate.parameters.PSObject.Properties.Name | Should -Contain 'recipePackageSha256' + } + } + + It 'requires an https allowlisted recipe package origin before download' { + $applyExtrasScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1') -Raw + + $applyExtrasScript | Should -Match '(?is)\[uri\]\$[A-Za-z0-9_]+\s*=\s*\$recipePackageUri' + $applyExtrasScript | Should -Match "(?is)\.Scheme\s*-ne\s*'https'.*throw" + $applyExtrasScript | Should -Match '(?is)\.Host.*(-notcontains|-notin|-notmatch|-notlike).*(throw|fail)' + } + It 'keeps connectors.secrets.env out of scripts' { if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } $result = Invoke-BashCommand "git grep -nE 'connectors\.secrets\.env' -- src/templates/sre-agent/bin src/templates/sre-agent/infra" @@ -858,6 +911,39 @@ exit 0 Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/hydrate-extensions.sh') | Should -BeFalse } + It 'removes dead telemetry scripts and source references from the SRE Agent template' { + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/telemetry.sh') | Should -BeFalse + + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "git grep -nE 'f10eff7f-b995-4c41-8347-90f0f55d5969|send_telemetry' -- src/templates/sre-agent" + $result.ExitCode | Should -Be 1 -Because $result.Output + } + + It 'removes legacy telemetry flags and env vars from deploy surfaces' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $deployContent = Get-Content -Path $script:DeployScript -Raw + $deployContent | Should -Not -Match '--no-telemetry' + + $result = Invoke-BashCommand "git grep -nE '\-\-no-telemetry|SRE_AGENT_NO_TELEMETRY' -- docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent" + $result.ExitCode | Should -Be 1 -Because $result.Output + } + + It 'parameterizes the deployer principal type in the SRE Agent module' { + $sreAgentBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/modules/sre-agent.bicep') -Raw + + $sreAgentBicep | Should -Match "(?s)@allowed\(\s*\[\s*'User'\s*,\s*'ServicePrincipal'\s*\]\s*\)\s*param\s+deployerPrincipalType\s+string" + $sreAgentBicep | Should -Match 'principalType:\s*deployerPrincipalType' + $sreAgentBicep | Should -Not -Match "principalType:\s*'User'" + } + + It 'passes ServicePrincipal deployer principal type in the CI/CD example' { + $githubActionsDeploy = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml') -Raw + + $githubActionsDeploy | Should -Match 'ServicePrincipal' + $githubActionsDeploy | Should -Match 'deployerPrincipalType|--deployer-principal-type' + } + It 'uses deterministic subscription and resource group identity for support resource names' { $mainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw $resourcesBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/resources.bicep') -Raw @@ -873,6 +959,61 @@ exit 0 $resourcesBicep | Should -Not -Match 'resourceGroup\(\)\.id|deployment\(\)\.name' } + It 'defaults to read-only identity with autonomous reporting' { + $portalMainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/main.bicep') -Raw + $cliMainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw + $createUiDef = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/createUiDefinition.json') -Raw | ConvertFrom-Json -Depth 100 + $deployScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/deploy.sh') -Raw + $recipeAgentJson = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/recipes/finops-hub/agent.json') -Raw | ConvertFrom-Json -Depth 100 + $expectedConfigJson = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/recipes/finops-hub/expected-config.json') -Raw | ConvertFrom-Json -Depth 100 + + $portalMainBicep | Should -Match "param accessLevel string = 'Low'" + $portalMainBicep | Should -Match 'param enableSubscriptionReaderRole bool = false' + $portalMainBicep | Should -Match "param actionMode string = 'autonomous'" + + $cliMainBicep | Should -Match "param accessLevel string = 'Low'" + $cliMainBicep | Should -Match 'param enableSubscriptionReaderRole bool = false' + $cliMainBicep | Should -Match "param actionMode string = 'autonomous'" + + $accessLevelControl = $createUiDef.parameters.steps | + Where-Object { $_.name -eq 'configuration' } | + Select-Object -First 1 -ExpandProperty elements | + Where-Object { $_.name -eq 'accessLevel' } + $accessLevelControl.defaultValue | Should -Be 'Low' + + $subscriptionReaderControl = $createUiDef.parameters.steps | + Where-Object { $_.name -eq 'configuration' } | + Select-Object -First 1 -ExpandProperty elements | + Where-Object { $_.name -eq 'enableSubscriptionReaderRole' } + $subscriptionReaderControl.defaultValue | Should -Be $false + + $actionModeControl = $createUiDef.parameters.steps | + Where-Object { $_.name -eq 'configuration' } | + Select-Object -First 1 -ExpandProperty elements | + Where-Object { $_.name -eq 'actionMode' } + $actionModeControl.defaultValue | Should -Be 'autonomous' + + $deployScript | Should -Match 'ENABLE_SUBSCRIPTION_READER="false"' + + $recipeAgentJson.access.accessLevel | Should -Be 'Low' + $recipeAgentJson.access.actionMode | Should -Be 'autonomous' + + $expectedConfigJson.agent.accessLevel | Should -Be 'Low' + $expectedConfigJson.agent.actionMode | Should -Be 'autonomous' + $expectedConfigJson.subscriptionRoleAssignments | Should -Be @() + } + + It 'declares Low accessLevel and disabled subscription Reader in the compiled deploy templates' { + foreach ($compiledPath in @( + (Join-Path $script:RepoRoot 'docs/deploy/sre-agent/latest/azuredeploy.json'), + (Join-Path $script:RepoRoot 'docs/deploy/sre-agent/14.0/azuredeploy.json') + )) { + $compiledTemplate = Get-Content -Path $compiledPath -Raw | ConvertFrom-Json -Depth 100 + $compiledTemplate.parameters.accessLevel.defaultValue | Should -Be 'Low' + $compiledTemplate.parameters.enableSubscriptionReaderRole.defaultValue | Should -Be $false + } + } + It 'applies subagents after their local handoff targets' { if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } diff --git a/src/templates/sre-agent/README.md b/src/templates/sre-agent/README.md index 82b0dffb8..00bc6a6e5 100644 --- a/src/templates/sre-agent/README.md +++ b/src/templates/sre-agent/README.md @@ -110,8 +110,7 @@ bash bin/deploy.sh \ [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] \ [--target-resource-group ...] \ [--dry-run] \ - [--force] \ - [--no-telemetry] + [--force] ``` `bin/deploy.sh --help` is the CLI contract: @@ -132,10 +131,10 @@ Optional: Example: https://..kusto.windows.net/Hub --cluster-resource-id Optional Kusto cluster ARM resource ID. Real deployments resolve this from --cluster-uri when possible; dry-run requires it. --no-subscription-reader Do not assign Reader at subscription scope. Default: assign Reader. + --deployer-principal-type Principal type of the deployer (User or ServicePrincipal). Default: User. --deploy-name Deployment name override. Defaults to a deterministic name. --dry-run Validate inputs and write parameters without Azure calls. --force Accepted for compatibility. - --no-telemetry Accepted for compatibility. -h, --help Show this help. ``` @@ -209,14 +208,13 @@ The GitHub Actions example passes the cluster URI as a script flag while keeping ## Migrating from env-var-driven deploys -The old deploy path accepted config through environment variables such as `FINOPS_HUB_CLUSTER_URI`, `FINOPS_HUB_CLUSTER_RESOURCE_ID`, `SRE_AGENT_NO_TELEMETRY`, and `connectors.secrets.env`. Those inputs are no longer supported for config or identity. +The old deploy path accepted config through environment variables such as `FINOPS_HUB_CLUSTER_URI`, `FINOPS_HUB_CLUSTER_RESOURCE_ID`, and `connectors.secrets.env`. Those inputs are no longer supported for config or identity. Before: ```bash export FINOPS_HUB_CLUSTER_URI="https://..kusto.windows.net/hub" export FINOPS_HUB_CLUSTER_RESOURCE_ID="/subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/" -export SRE_AGENT_NO_TELEMETRY=1 bash bin/deploy.sh recipes/finops-hub ``` @@ -230,8 +228,7 @@ bash bin/deploy.sh \ --name \ --location \ --cluster-uri https://..kusto.windows.net/Hub \ - --cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/ \ - --no-telemetry + --cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/ ``` The only supported environment-variable inputs are secrets: diff --git a/src/templates/sre-agent/bin/deploy.sh b/src/templates/sre-agent/bin/deploy.sh index 3b9a5f53c..e40373733 100755 --- a/src/templates/sre-agent/bin/deploy.sh +++ b/src/templates/sre-agent/bin/deploy.sh @@ -38,10 +38,10 @@ Optional: Example: https://..kusto.windows.net/Hub --cluster-resource-id Optional Kusto cluster ARM resource ID. Real deployments resolve this from --cluster-uri when possible; dry-run requires it. --no-subscription-reader Do not assign Reader at subscription scope. Default: assign Reader. + --deployer-principal-type Principal type of the deployer (User or ServicePrincipal). Default: User. --deploy-name Deployment name override. Defaults to a deterministic name. --dry-run Validate inputs and write parameters without Azure calls. --force Accepted for compatibility. - --no-telemetry Accepted for compatibility. -h, --help Show this help. EOF exit "${1:-0}" @@ -247,7 +247,8 @@ CLUSTER_URI="" CLUSTER_RESOURCE_ID="" DEPLOY_NAME="" DRY_RUN="" -ENABLE_SUBSCRIPTION_READER="true" +ENABLE_SUBSCRIPTION_READER="false" +DEPLOYER_PRINCIPAL_TYPE="User" TARGET_RGS=() while [[ $# -gt 0 ]]; do @@ -300,6 +301,11 @@ while [[ $# -gt 0 ]]; do ENABLE_SUBSCRIPTION_READER="false" shift ;; + --deployer-principal-type) + require_value "--deployer-principal-type" "${2:-}" + DEPLOYER_PRINCIPAL_TYPE="$2" + shift 2 + ;; --deploy-name) require_value "--deploy-name" "${2:-}" DEPLOY_NAME="$2" @@ -309,7 +315,7 @@ while [[ $# -gt 0 ]]; do DRY_RUN="true" shift ;; - --force|--no-telemetry) + --force) shift ;; -h|--help) @@ -414,6 +420,7 @@ jq -n \ --argjson monthlyAgentUnitLimit "$MONTHLY_AGENT_UNIT_LIMIT" \ --arg kustoClusterId "$CLUSTER_RESOURCE_ID" \ --argjson enableSubscriptionReaderRole "$ENABLE_SUBSCRIPTION_READER" \ + --arg deployerPrincipalType "$DEPLOYER_PRINCIPAL_TYPE" \ --argjson targetResourceGroups "$TARGET_RGS_JSON" \ --argjson experimentalSettings "$EXPERIMENTAL_SETTINGS" \ --argjson tags "$TAGS" \ @@ -434,7 +441,8 @@ jq -n \ "experimentalSettings": { "value": $experimentalSettings }, "tags": { "value": $tags }, "finopsHubKustoClusterResourceId": { "value": $kustoClusterId }, - "enableSubscriptionReaderRole": { "value": $enableSubscriptionReaderRole } + "enableSubscriptionReaderRole": { "value": $enableSubscriptionReaderRole }, + "deployerPrincipalType": { "value": $deployerPrincipalType } } }' > "$PARAMETERS_FILE" diff --git a/src/templates/sre-agent/bin/telemetry.sh b/src/templates/sre-agent/bin/telemetry.sh deleted file mode 100755 index 97aa3a02a..000000000 --- a/src/templates/sre-agent/bin/telemetry.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash -# telemetry.sh — anonymous usage tracking for recipe popularity. -# -# Sends a single custom event to App Insights. Non-blocking, best-effort. -# No PII is collected — only recipe name, action, region, OS, and coarse booleans. -# -# Usage (sourced by other scripts): -# source "$(dirname "$0")/telemetry.sh" -# send_telemetry "deploy" "finops-hub" "westus3" "true" "false" "true" "false" "deploy" - -_TELEMETRY_IKEY="f10eff7f-b995-4c41-8347-90f0f55d5969" -_TELEMETRY_ENDPOINT="https://eastus2-3.in.applicationinsights.azure.com/v2/track" - -send_telemetry() { - [[ "${_NO_TELEMETRY:-}" == "true" ]] && return 0 - - local action="${1:-unknown}" - local recipe="${2:-unknown}" - local region="${3:-unknown}" - local used_recipe_flag="${4:-false}" - local used_legacy_positional="${5:-false}" - local has_cluster_uri="${6:-false}" - local has_cluster_resource_id="${7:-false}" - local mode="${8:-deploy}" - local os_type - os_type="$(uname -s 2>/dev/null || echo unknown)" - - # Fire and forget — never block or fail the main script - (curl -s -o /dev/null -m 5 -X POST "$_TELEMETRY_ENDPOINT" \ - -H "Content-Type: application/json" \ - -d "[{ - \"name\": \"Microsoft.ApplicationInsights.Event\", - \"time\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\", - \"iKey\": \"${_TELEMETRY_IKEY}\", - \"data\": { - \"baseType\": \"EventData\", - \"baseData\": { - \"name\": \"recipe-usage\", - \"properties\": { - \"action\": \"${action}\", - \"recipe\": \"${recipe}\", - \"region\": \"${region}\", - \"os\": \"${os_type}\", - \"used_recipe_flag\": \"${used_recipe_flag}\", - \"used_legacy_positional\": \"${used_legacy_positional}\", - \"has_cluster_uri\": \"${has_cluster_uri}\", - \"has_cluster_resource_id\": \"${has_cluster_resource_id}\", - \"mode\": \"${mode}\" - } - } - } - }]" 2>/dev/null &) 2>/dev/null -} diff --git a/src/templates/sre-agent/createUiDefinition.json b/src/templates/sre-agent/createUiDefinition.json index 87e82bcaa..25d538b3e 100644 --- a/src/templates/sre-agent/createUiDefinition.json +++ b/src/templates/sre-agent/createUiDefinition.json @@ -101,8 +101,8 @@ "name": "accessLevel", "type": "Microsoft.Common.OptionsGroup", "label": "Access level", - "defaultValue": "High", - "toolTip": "High adds Contributor on target resource groups for autonomous remediation workflows. Low grants read-only monitoring roles.", + "defaultValue": "Low", + "toolTip": "Low grants read-only monitoring roles (recommended for reporting and analysis). High adds Contributor on target resource groups for autonomous remediation workflows.", "constraints": { "allowedValues": [ { @@ -147,8 +147,8 @@ "name": "enableSubscriptionReaderRole", "type": "Microsoft.Common.CheckBox", "label": "Grant subscription Reader to the agent", - "toolTip": "Recommended. Grants the agent managed identity Reader on the deployment subscription for inventory, Resource Graph, capacity, quota, and monitoring coverage workflows.", - "defaultValue": true, + "toolTip": "Optional — required only for subscription-wide ARM-backed reports; otherwise scope reads via target resource groups.", + "defaultValue": false, "visible": true } ] diff --git a/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml b/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml index afa74e4e7..a13358445 100644 --- a/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml +++ b/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml @@ -29,4 +29,5 @@ jobs: --location ${{ vars.SRE_AGENT_LOCATION }} --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} --cluster-uri "$CLUSTER_URI" + --deployer-principal-type ServicePrincipal --force diff --git a/src/templates/sre-agent/infra/main.bicep b/src/templates/sre-agent/infra/main.bicep index 99baf8339..67198548c 100644 --- a/src/templates/sre-agent/infra/main.bicep +++ b/src/templates/sre-agent/infra/main.bicep @@ -25,7 +25,7 @@ param accessLevel string = 'Low' @description('Agent action mode.') @allowed(['review', 'autonomous', 'readOnly']) -param actionMode string = 'review' +param actionMode string = 'autonomous' @description('Agent upgrade channel.') @allowed(['Stable', 'Preview']) @@ -54,8 +54,12 @@ param tags object = {} @description('Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment.') param finopsHubKustoClusterResourceId string = '' -@description('Assign Reader on the deployment subscription to the agent managed identity.') -param enableSubscriptionReaderRole bool = true +@description('Assign Reader on the deployment subscription to the agent managed identity. Optional — required only for subscription-wide ARM-backed reports; otherwise scope reads via target resource groups.') +param enableSubscriptionReaderRole bool = false + +@description('Principal type of the deployer.') +@allowed(['User', 'ServicePrincipal']) +param deployerPrincipalType string = 'User' var targetRgs = union([resourceGroupName], targetResourceGroups) var agentResourceGroupId = subscriptionResourceId('Microsoft.Resources/resourceGroups', resourceGroupName) @@ -84,6 +88,7 @@ module resources 'resources.bicep' = { defaultModelName: defaultModelName monthlyAgentUnitLimit: monthlyAgentUnitLimit experimentalSettings: experimentalSettings + deployerPrincipalType: deployerPrincipalType tags: tags } } diff --git a/src/templates/sre-agent/infra/modules/apply-extras.bicep b/src/templates/sre-agent/infra/modules/apply-extras.bicep index 4adbe17a8..4cc76f86f 100644 --- a/src/templates/sre-agent/infra/modules/apply-extras.bicep +++ b/src/templates/sre-agent/infra/modules/apply-extras.bicep @@ -15,6 +15,9 @@ param subscriptionId string @description('Public URI for the generated SRE Agent recipe package.') param recipePackageUri string +@description('SHA256 hash of the recipe package for integrity verification.') +param recipePackageSha256 string + @description('Optional database-qualified Kusto connector URI.') param kustoConnectorUri string = '' @@ -88,6 +91,10 @@ resource applyExtras 'Microsoft.Resources/deploymentScripts@2023-08-01' = { name: 'recipePackageUri' value: recipePackageUri } + { + name: 'recipePackageSha256' + value: recipePackageSha256 + } { name: 'kustoConnectorUri' value: kustoConnectorUri diff --git a/src/templates/sre-agent/infra/modules/sre-agent.bicep b/src/templates/sre-agent/infra/modules/sre-agent.bicep index 4eb264822..ded39f596 100644 --- a/src/templates/sre-agent/infra/modules/sre-agent.bicep +++ b/src/templates/sre-agent/infra/modules/sre-agent.bicep @@ -44,6 +44,10 @@ param experimentalSettings object @description('Azure resource tags.') param tags object = {} +@description('Principal type of the deployer.') +@allowed(['User', 'ServicePrincipal']) +param deployerPrincipalType string = 'User' + var sreAgentAdminRoleId = 'e79298df-d852-4c6d-84f9-5d13249d1e55' #disable-next-line BCP081 @@ -91,7 +95,7 @@ resource sreAgentAdminRoleAssignment 'Microsoft.Authorization/roleAssignments@20 properties: { roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', sreAgentAdminRoleId) principalId: deployer().objectId - principalType: 'User' + principalType: deployerPrincipalType } } diff --git a/src/templates/sre-agent/infra/resources.bicep b/src/templates/sre-agent/infra/resources.bicep index 1fd023349..3107d9dee 100644 --- a/src/templates/sre-agent/infra/resources.bicep +++ b/src/templates/sre-agent/infra/resources.bicep @@ -34,6 +34,10 @@ param monthlyAgentUnitLimit int @description('Agent experimental settings.') param experimentalSettings object +@description('Principal type of the deployer.') +@allowed(['User', 'ServicePrincipal']) +param deployerPrincipalType string = 'User' + @description('Azure resource tags.') param tags object = {} @@ -66,6 +70,7 @@ module sreAgent 'modules/sre-agent.bicep' = { defaultModelName: defaultModelName monthlyAgentUnitLimit: monthlyAgentUnitLimit experimentalSettings: experimentalSettings + deployerPrincipalType: deployerPrincipalType tags: tags } } diff --git a/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 b/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 index 7a8db80ef..85f6e9daf 100644 --- a/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 +++ b/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 @@ -120,6 +120,7 @@ $resourceGroupName = Get-RequiredEnv 'resourceGroupName' $agentName = Get-RequiredEnv 'agentName' $agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/') $recipePackageUri = Get-RequiredEnv 'recipePackageUri' +$recipePackageSha256 = Get-RequiredEnv 'recipePackageSha256' $kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri' $armApiVersion = '2025-05-01-preview' $armBase = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName" @@ -134,10 +135,33 @@ $zipPath = Join-Path $tempRoot 'sre-agent-recipe.zip' Remove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue New-Item -Path $workRoot -ItemType Directory -Force | Out-Null +Write-Output "Validating SRE Agent recipe package URI: $recipePackageUri" +[uri]$parsedUri = $recipePackageUri +if ($parsedUri.Scheme -ne 'https') { + throw "Recipe package URI must use https scheme, got: $($parsedUri.Scheme)" +} + +$allowedHosts = @( + 'raw.githubusercontent.com', + 'github.com', + 'aka.ms' +) + +if ($allowedHosts -notcontains $parsedUri.Host -and $parsedUri.Host -notlike '*.blob.core.windows.net') { + throw "Recipe package host '$($parsedUri.Host)' is not in the allowlist. Allowed: raw.githubusercontent.com, github.com, aka.ms, *.blob.core.windows.net" +} + Write-Output "Downloading SRE Agent recipe package: $recipePackageUri" Invoke-WithRetry -Label 'download recipe package' -Action { Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath } | Out-Null + +Write-Output "Verifying recipe package integrity..." +$actualHash = (Get-FileHash -Algorithm SHA256 -Path $zipPath).Hash +if ($actualHash -ne $recipePackageSha256) { + throw "Recipe package hash mismatch: expected $recipePackageSha256 got $actualHash" +} + Expand-Archive -Path $zipPath -DestinationPath $workRoot -Force $extrasPath = Join-Path $workRoot 'extras.json' diff --git a/src/templates/sre-agent/main.bicep b/src/templates/sre-agent/main.bicep index fd4632140..373ccd0e3 100644 --- a/src/templates/sre-agent/main.bicep +++ b/src/templates/sre-agent/main.bicep @@ -25,9 +25,9 @@ param finopsHubKustoConnectorUri string = '' @description('Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment.') param finopsHubKustoClusterResourceId string = '' -@description('Agent access level.') +@description('Agent access level. Low (read-only) is recommended for reporting and analysis without modification risk.') @allowed(['Low', 'High']) -param accessLevel string = 'High' +param accessLevel string = 'Low' @description('Agent action mode.') @allowed(['review', 'autonomous', 'readOnly']) @@ -54,12 +54,15 @@ param experimentalSettings object = { EnableWorkspaceTools: true } -@description('Assign Reader on the deployment subscription to the agent managed identity.') -param enableSubscriptionReaderRole bool = true +@description('Assign Reader on the deployment subscription to the agent managed identity. Optional — required only for subscription-wide ARM-backed reports; otherwise scope reads via target resource groups.') +param enableSubscriptionReaderRole bool = false @description('Public URI for the generated SRE Agent recipe package. Deploy-to-Azure links derive this from the template URI.') param recipePackageUri string = uri(any(deployment()).properties.templateLink.uri, 'sre-agent-recipe.zip') +@description('SHA256 hash of the recipe package for integrity verification.') +param recipePackageSha256 string = 'PLACEHOLDER_RECIPE_PACKAGE_SHA256' + @description('Forces the recipe deployment script to run when the template is redeployed.') param forceUpdateTag string = utcNow() @@ -69,6 +72,10 @@ param tags object = { source: 'microsoft-finops-toolkit' } +@description('Principal type of the deployer.') +@allowed(['User', 'ServicePrincipal']) +param deployerPrincipalType string = 'User' + var rawTargetResourceGroups = split(replace(targetResourceGroupNames, ' ', ''), ',') var parsedTargetResourceGroups = filter(rawTargetResourceGroups, rgName => !empty(rgName)) var targetRgs = union([resourceGroupName], targetResourceGroups, parsedTargetResourceGroups) @@ -102,6 +109,7 @@ module resources 'infra/resources.bicep' = { defaultModelName: defaultModelName monthlyAgentUnitLimit: monthlyAgentUnitLimit experimentalSettings: experimentalSettings + deployerPrincipalType: deployerPrincipalType tags: tags } } @@ -144,6 +152,7 @@ module applyExtras 'infra/modules/apply-extras.bicep' = { agentEndpoint: resources.outputs.agentEndpoint subscriptionId: subscription().subscriptionId recipePackageUri: recipePackageUri + recipePackageSha256: recipePackageSha256 kustoConnectorUri: finopsHubKustoConnectorUri forceUpdateTag: forceUpdateTag tags: tags diff --git a/src/templates/sre-agent/recipes/finops-hub/agent.json b/src/templates/sre-agent/recipes/finops-hub/agent.json index a2a90bbe8..b2b21d260 100644 --- a/src/templates/sre-agent/recipes/finops-hub/agent.json +++ b/src/templates/sre-agent/recipes/finops-hub/agent.json @@ -1,7 +1,7 @@ { "access": { - "accessLevel": "High", - "actionMode": "Autonomous" + "accessLevel": "Low", + "actionMode": "autonomous" }, "upgradeChannel": "Preview", "defaultModelProvider": "MicrosoftFoundry", diff --git a/src/templates/sre-agent/recipes/finops-hub/expected-config.json b/src/templates/sre-agent/recipes/finops-hub/expected-config.json index 9e6e49a04..d4e041716 100644 --- a/src/templates/sre-agent/recipes/finops-hub/expected-config.json +++ b/src/templates/sre-agent/recipes/finops-hub/expected-config.json @@ -1,6 +1,6 @@ { "agent": { - "accessLevel": "High", + "accessLevel": "Low", "actionMode": "autonomous", "upgradeChannel": "Preview", "defaultModelProvider": "MicrosoftFoundry", @@ -9,9 +9,7 @@ "EnableWorkspaceTools" ] }, - "subscriptionRoleAssignments": [ - "Reader" - ], + "subscriptionRoleAssignments": [], "builtInTools": { "enabled": [ "PlotAreaChartWithCorrelation",

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 z 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 aZcs}F1^@s6009620672v0KG{C0002qu>Iu# literal 0 HcmV?d00001 diff --git a/docs/deploy/sre-agent/latest/azuredeploy.json b/docs/deploy/sre-agent/latest/azuredeploy.json new file mode 100644 index 000000000..4b6a6d0eb --- /dev/null +++ b/docs/deploy/sre-agent/latest/azuredeploy.json @@ -0,0 +1,1119 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "2403415415579441400" + } + }, + "parameters": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group that holds the SRE Agent resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "location": { + "type": "string", + "defaultValue": "eastus2", + "allowedValues": [ + "australiaeast", + "canadacentral", + "eastus2", + "francecentral", + "koreacentral", + "swedencentral", + "uksouth" + ], + "metadata": { + "description": "Primary location for all resources." + } + }, + "targetResourceGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Resource groups the agent can observe or act on. The agent resource group is always included." + } + }, + "targetResourceGroupNames": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Comma-separated resource groups the agent can observe or act on. Used by the Azure portal form." + } + }, + "finopsHubKustoConnectorUri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional database-qualified FinOps Hub Kusto connector URI. Example: https://..kusto.windows.net/Hub" + } + }, + "finopsHubKustoClusterResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment." + } + }, + "accessLevel": { + "type": "string", + "defaultValue": "High", + "allowedValues": [ + "Low", + "High" + ], + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "defaultValue": "autonomous", + "allowedValues": [ + "review", + "autonomous", + "readOnly" + ], + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "defaultValue": "Preview", + "allowedValues": [ + "Stable", + "Preview" + ], + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "defaultValue": "MicrosoftFoundry", + "allowedValues": [ + "MicrosoftFoundry", + "Anthropic" + ], + "metadata": { + "description": "Default SRE Agent model provider. MicrosoftFoundry maps to the Azure OpenAI provider in the SRE Agent portal." + } + }, + "defaultModelName": { + "type": "string", + "defaultValue": "Automatic", + "metadata": { + "description": "Default SRE Agent model name. Automatic lets SRE Agent route to the appropriate model within the selected provider." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "defaultValue": 10000, + "minValue": 1, + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "defaultValue": { + "EnableSandboxGroup": true, + "EnableWorkspaceTools": true + }, + "metadata": { + "description": "Agent experimental settings." + } + }, + "enableSubscriptionReaderRole": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Assign Reader on the deployment subscription to the agent managed identity." + } + }, + "recipePackageUri": { + "type": "string", + "defaultValue": "[uri(deployment().properties.templateLink.uri, 'sre-agent-recipe.zip')]", + "metadata": { + "description": "Public URI for the generated SRE Agent recipe package. Deploy-to-Azure links derive this from the template URI." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Forces the recipe deployment script to run when the template is redeployed." + } + }, + "tags": { + "type": "object", + "defaultValue": { + "finops-toolkit": "sre-agent", + "source": "microsoft-finops-toolkit" + }, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "copy": [ + { + "name": "targetRgIds", + "count": "[length(variables('targetRgs'))]", + "input": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('targetRgs')[copyIndex('targetRgIds')])]" + } + ], + "rawTargetResourceGroups": "[split(replace(parameters('targetResourceGroupNames'), ' ', ''), ',')]", + "parsedTargetResourceGroups": "[filter(variables('rawTargetResourceGroups'), lambda('rgName', not(empty(lambdaVariables('rgName')))))]", + "targetRgs": "[union(createArray(parameters('resourceGroupName')), parameters('targetResourceGroups'), variables('parsedTargetResourceGroups'))]", + "agentResourceGroupId": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]", + "namingSeed": "[toLower(format('{0}|{1}|{2}', subscription().subscriptionId, variables('agentResourceGroupId'), parameters('agentName')))]", + "readerRoleId": "acdd72a7-3385-48ef-bd42-f606fba81ae7", + "hasKustoCluster": "[not(empty(parameters('finopsHubKustoClusterResourceId')))]", + "kustoClusterSubscriptionId": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[2], '')]", + "kustoClusterResourceGroupName": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[4], '')]", + "kustoClusterName": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[8], '')]" + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2024-03-01", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + { + "condition": "[parameters('enableSubscriptionReaderRole')]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(subscription().id, variables('namingSeed'), variables('readerRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('readerRoleId'))]", + "principalId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "resources-deployment", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "agentName": { + "value": "[parameters('agentName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "namingSeed": { + "value": "[variables('namingSeed')]" + }, + "targetResourceGroupIds": { + "value": "[variables('targetRgIds')]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + }, + "actionMode": { + "value": "[parameters('actionMode')]" + }, + "upgradeChannel": { + "value": "[parameters('upgradeChannel')]" + }, + "defaultModelProvider": { + "value": "[parameters('defaultModelProvider')]" + }, + "defaultModelName": { + "value": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": { + "value": "[parameters('monthlyAgentUnitLimit')]" + }, + "experimentalSettings": { + "value": "[parameters('experimentalSettings')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11748842726639098374" + } + }, + "parameters": { + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location for all resources." + } + }, + "namingSeed": { + "type": "string", + "metadata": { + "description": "Deterministic naming seed built from subscription ID, agent resource group ID, and agent name." + } + }, + "targetResourceGroupIds": { + "type": "array", + "metadata": { + "description": "Resource group IDs shown as managed resources in the SRE Agent." + } + }, + "accessLevel": { + "type": "string", + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model provider." + } + }, + "defaultModelName": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model name." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "metadata": { + "description": "Agent experimental settings." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "uniqueSuffix": "[uniqueString(parameters('namingSeed'))]", + "logAnalyticsName": "[format('law-{0}', variables('uniqueSuffix'))]", + "appInsightsName": "[format('appi-{0}', variables('uniqueSuffix'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "monitoring", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsName": { + "value": "[variables('logAnalyticsName')]" + }, + "appInsightsName": { + "value": "[variables('appInsightsName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "9164683275614055037" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for resources" + } + }, + "logAnalyticsName": { + "type": "string", + "metadata": { + "description": "Log Analytics Workspace name" + } + }, + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Application Insights name" + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsName')]", + "location": "[parameters('location')]", + "properties": { + "sku": { + "name": "PerGB2018" + }, + "retentionInDays": 30 + } + }, + { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('appInsightsName')]", + "location": "[parameters('location')]", + "kind": "web", + "properties": { + "Application_Type": "web", + "Request_Source": "IbizaAIExtension", + "WorkspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + }, + "dependsOn": [ + "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + ] + } + ], + "outputs": { + "logAnalyticsWorkspaceId": { + "type": "string", + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "value": "[parameters('logAnalyticsName')]" + }, + "appInsightsId": { + "type": "string", + "value": "[resourceId('Microsoft.Insights/components', parameters('appInsightsName'))]" + }, + "appInsightsAppId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('appInsightsName')), '2020-02-02').AppId]" + }, + "appInsightsConnectionString": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('appInsightsName')), '2020-02-02').ConnectionString]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "sre-agent", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "agentName": { + "value": "[parameters('agentName')]" + }, + "appInsightsAppId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsAppId.value]" + }, + "appInsightsConnectionString": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsConnectionString.value]" + }, + "appInsightsId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsId.value]" + }, + "managedResourceGroupIds": { + "value": "[parameters('targetResourceGroupIds')]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + }, + "actionMode": { + "value": "[parameters('actionMode')]" + }, + "upgradeChannel": { + "value": "[parameters('upgradeChannel')]" + }, + "defaultModelProvider": { + "value": "[parameters('defaultModelProvider')]" + }, + "defaultModelName": { + "value": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": { + "value": "[parameters('monthlyAgentUnitLimit')]" + }, + "experimentalSettings": { + "value": "[parameters('experimentalSettings')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6562535881153200016" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "appInsightsAppId": { + "type": "string", + "metadata": { + "description": "Application Insights App ID." + } + }, + "appInsightsConnectionString": { + "type": "securestring", + "metadata": { + "description": "Application Insights connection string." + } + }, + "appInsightsId": { + "type": "string", + "metadata": { + "description": "Application Insights resource ID." + } + }, + "managedResourceGroupIds": { + "type": "array", + "metadata": { + "description": "Resource group IDs to add as managed resources." + } + }, + "accessLevel": { + "type": "string", + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model provider." + } + }, + "defaultModelName": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model name." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "metadata": { + "description": "Agent experimental settings." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "sreAgentAdminRoleId": "e79298df-d852-4c6d-84f9-5d13249d1e55" + }, + "resources": [ + { + "type": "Microsoft.App/agents", + "apiVersion": "2026-01-01", + "name": "[parameters('agentName')]", + "location": "[parameters('location')]", + "tags": "[union(parameters('tags'), createObject('hidden-link: /app-insights-resource-id', parameters('appInsightsId'), 'source', 'microsoft-sre-agent-starter-lab', 'finops-toolkit', 'sre-agent'))]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "knowledgeGraphConfiguration": { + "managedResources": "[parameters('managedResourceGroupIds')]", + "identity": "system" + }, + "actionConfiguration": { + "mode": "[parameters('actionMode')]", + "identity": "system", + "accessLevel": "[parameters('accessLevel')]" + }, + "upgradeChannel": "[parameters('upgradeChannel')]", + "defaultModel": { + "provider": "[parameters('defaultModelProvider')]", + "name": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": "[parameters('monthlyAgentUnitLimit')]", + "experimentalSettings": "[parameters('experimentalSettings')]", + "mcpServers": [], + "logConfiguration": { + "applicationInsightsConfiguration": { + "appId": "[parameters('appInsightsAppId')]", + "connectionString": "[parameters('appInsightsConnectionString')]" + } + } + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/agents', parameters('agentName'))]", + "name": "[guid(resourceId('Microsoft.App/agents', parameters('agentName')), deployer().objectId, variables('sreAgentAdminRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('sreAgentAdminRoleId'))]", + "principalId": "[deployer().objectId]", + "principalType": "User" + }, + "dependsOn": [ + "[resourceId('Microsoft.App/agents', parameters('agentName'))]" + ] + } + ], + "outputs": { + "agentName": { + "type": "string", + "value": "[parameters('agentName')]" + }, + "agentId": { + "type": "string", + "value": "[resourceId('Microsoft.App/agents', parameters('agentName'))]" + }, + "agentEndpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01').agentEndpoint]" + }, + "agentPortalUrl": { + "type": "string", + "value": "[format('https://sre.azure.com/#/agent/{0}/{1}/{2}', subscription().subscriptionId, resourceGroup().name, parameters('agentName'))]" + }, + "agentPrincipalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01', 'full').identity.principalId]" + }, + "agentTenantId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01', 'full').identity.tenantId]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'monitoring')]" + ] + } + ], + "outputs": { + "agentName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentName.value]" + }, + "agentEndpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "agentPortalUrl": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentPortalUrl.value]" + }, + "agentPrincipalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "agentTenantId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentTenantId.value]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.logAnalyticsWorkspaceId.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]" + ] + }, + { + "copy": { + "name": "targetRbac", + "count": "[length(variables('targetRgs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('target-rbac-{0}', uniqueString(toLower(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('targetRgs')[copyIndex()])), variables('namingSeed')))]", + "resourceGroup": "[variables('targetRgs')[copyIndex()]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6305641259472431615" + } + }, + "parameters": { + "principalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the managed identity to assign roles to." + } + }, + "accessLevel": { + "type": "string", + "allowedValues": [ + "Low", + "High" + ], + "metadata": { + "description": "Agent access level." + } + } + }, + "variables": { + "readerRoleId": "acdd72a7-3385-48ef-bd42-f606fba81ae7", + "monitoringReaderRoleId": "43d0d8ad-25c7-4714-9337-8ba259a9fe05", + "logAnalyticsReaderRoleId": "73c42c96-874c-492b-b04d-ab87d138a893", + "contributorRoleId": "b24988ac-6180-42a0-ab88-20f7382dd24c", + "roleIds": "[if(equals(parameters('accessLevel'), 'High'), createArray(variables('readerRoleId'), variables('monitoringReaderRoleId'), variables('logAnalyticsReaderRoleId'), variables('contributorRoleId')), createArray(variables('readerRoleId'), variables('monitoringReaderRoleId'), variables('logAnalyticsReaderRoleId')))]" + }, + "resources": [ + { + "copy": { + "name": "roleAssignments", + "count": "[length(variables('roleIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(resourceGroup().id, parameters('principalId'), variables('roleIds')[copyIndex()])]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleIds')[copyIndex()])]", + "principalId": "[parameters('principalId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "condition": "[variables('hasKustoCluster')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('kusto-rbac-{0}', uniqueString(parameters('finopsHubKustoClusterResourceId'), variables('namingSeed')))]", + "subscriptionId": "[variables('kustoClusterSubscriptionId')]", + "resourceGroup": "[variables('kustoClusterResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "clusterName": { + "value": "[variables('kustoClusterName')]" + }, + "principalApplicationId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "principalTenantId": { + "value": "[tenant().tenantId]" + }, + "principalAssignmentName": { + "value": "[format('sre-agent-{0}', uniqueString(parameters('finopsHubKustoClusterResourceId'), variables('namingSeed'), 'all-db-viewer'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15341408879505554256" + } + }, + "parameters": { + "clusterName": { + "type": "string", + "metadata": { + "description": "Kusto cluster name." + } + }, + "principalApplicationId": { + "type": "string", + "metadata": { + "description": "Microsoft Entra application/client ID to assign to the Kusto cluster." + } + }, + "principalTenantId": { + "type": "string", + "metadata": { + "description": "Principal tenant ID." + } + }, + "principalAssignmentName": { + "type": "string", + "metadata": { + "description": "Stable principal assignment name." + } + } + }, + "resources": [ + { + "type": "Microsoft.Kusto/clusters/principalAssignments", + "apiVersion": "2024-04-13", + "name": "[format('{0}/{1}', parameters('clusterName'), parameters('principalAssignmentName'))]", + "properties": { + "principalId": "[parameters('principalApplicationId')]", + "principalType": "App", + "role": "AllDatabasesViewer", + "tenantId": "[parameters('principalTenantId')]" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "apply-extras", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "agentName": { + "value": "[parameters('agentName')]" + }, + "agentEndpoint": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "subscriptionId": { + "value": "[subscription().subscriptionId]" + }, + "recipePackageUri": { + "value": "[parameters('recipePackageUri')]" + }, + "kustoConnectorUri": { + "value": "[parameters('finopsHubKustoConnectorUri')]" + }, + "forceUpdateTag": { + "value": "[parameters('forceUpdateTag')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "5168893811325309322" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for the deployment script resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "agentEndpoint": { + "type": "string", + "metadata": { + "description": "SRE Agent data-plane endpoint." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "Subscription that contains the SRE Agent." + } + }, + "recipePackageUri": { + "type": "string", + "metadata": { + "description": "Public URI for the generated SRE Agent recipe package." + } + }, + "kustoConnectorUri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional database-qualified Kusto connector URI." + } + }, + "forceUpdateTag": { + "type": "string", + "metadata": { + "description": "Forces the deployment script to run when the template is redeployed." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "$fxv#0": "# Copyright (c) Microsoft Corporation.\n# Licensed under the MIT License.\n\n$ErrorActionPreference = 'Stop'\n\nfunction Get-RequiredEnv($Name) {\n $value = [Environment]::GetEnvironmentVariable($Name)\n if ([string]::IsNullOrWhiteSpace($value)) {\n throw \"Missing required environment variable: $Name\"\n }\n return $value\n}\n\nfunction Get-OptionalEnv($Name) {\n return [Environment]::GetEnvironmentVariable($Name)\n}\n\nfunction ConvertTo-BodyJson($Value) {\n return ($Value | ConvertTo-Json -Depth 100 -Compress)\n}\n\nfunction Get-PropertyValue($Object, [string[]]$Names, $Default = '') {\n foreach ($name in $Names) {\n if ($null -ne $Object -and $Object.PSObject.Properties[$name] -and $null -ne $Object.$name) {\n return $Object.$name\n }\n }\n return $Default\n}\n\nfunction Get-HttpStatusCode($Exception) {\n if ($Exception.Response -and $Exception.Response.StatusCode) {\n return [int]$Exception.Response.StatusCode\n }\n return $null\n}\n\nfunction Invoke-WithRetry([scriptblock]$Action, [string]$Label, [int]$MaxAttempts = 5, [int]$DelaySeconds = 15) {\n for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {\n try {\n return & $Action\n }\n catch {\n $statusCode = Get-HttpStatusCode $_.Exception\n if ($statusCode -and $statusCode -notin @(401, 403, 408, 429, 500, 502, 503, 504)) {\n throw\n }\n if ($attempt -eq $MaxAttempts) {\n throw\n }\n Write-Output \"$Label attempt $attempt/$MaxAttempts failed: $($_.Exception.Message)\"\n Start-Sleep -Seconds $DelaySeconds\n }\n }\n}\n\nfunction Invoke-JsonRest([string]$Method, [string]$Uri, [string]$Token, $Body = $null) {\n $headers = @{\n Authorization = \"Bearer $Token\"\n 'Content-Type' = 'application/json'\n }\n $parameters = @{\n Method = $Method\n Uri = $Uri\n Headers = $headers\n }\n if ($null -ne $Body) {\n $parameters.Body = ConvertTo-BodyJson $Body\n }\n return Invoke-RestMethod @parameters\n}\n\nfunction Get-KnowledgeSourceName([string]$FileName) {\n $name = [IO.Path]::GetFileName($FileName).ToLowerInvariant() -replace '[^a-z0-9-]+', '-'\n $name = $name -replace '-+', '-'\n return $name.Trim('-')\n}\n\nfunction Get-Collection($Value) {\n if ($null -eq $Value) {\n return @()\n }\n return @($Value)\n}\n\nfunction Convert-TokenToString($Token) {\n if ($Token -is [Security.SecureString]) {\n $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token)\n try {\n return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)\n }\n finally {\n [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)\n }\n }\n return [string]$Token\n}\n\nfunction Get-ArmAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://management.azure.com/').Token\n}\n\nfunction Get-SreAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://azuresre.dev').Token\n}\n\n$subscriptionId = Get-RequiredEnv 'subscriptionId'\n$resourceGroupName = Get-RequiredEnv 'resourceGroupName'\n$agentName = Get-RequiredEnv 'agentName'\n$agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/')\n$recipePackageUri = Get-RequiredEnv 'recipePackageUri'\n$kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri'\n$armApiVersion = '2025-05-01-preview'\n$armBase = \"https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName\"\n\nWrite-Output 'Connecting with deployment script managed identity...'\nConnect-AzAccount -Identity | Out-Null\nSet-AzContext -Subscription $subscriptionId | Out-Null\n\n$workRoot = Join-Path $env:TEMP 'sre-agent-recipe'\n$zipPath = Join-Path $env:TEMP 'sre-agent-recipe.zip'\nRemove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue\nNew-Item -Path $workRoot -ItemType Directory -Force | Out-Null\n\nWrite-Output \"Downloading SRE Agent recipe package: $recipePackageUri\"\nInvoke-WithRetry -Label 'download recipe package' -Action {\n Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath\n} | Out-Null\nExpand-Archive -Path $zipPath -DestinationPath $workRoot -Force\n\n$extrasPath = Join-Path $workRoot 'extras.json'\nif (-not (Test-Path $extrasPath)) {\n throw \"Recipe package did not contain extras.json\"\n}\n\n$extras = Get-Content $extrasPath -Raw | ConvertFrom-Json -Depth 100\nWrite-Output \"Loaded recipe package from $extrasPath\"\n\nif ([string]::IsNullOrWhiteSpace($kustoConnectorUri)) {\n $extras.connectors = @(\n Get-Collection $extras.connectors | Where-Object {\n $type = Get-PropertyValue $_.properties @('dataConnectorType', 'type')\n $type -ine 'Kusto'\n }\n )\n}\nelse {\n foreach ($connector in Get-Collection $extras.connectors) {\n $type = Get-PropertyValue $connector.properties @('dataConnectorType', 'type')\n if ($type -ieq 'Kusto') {\n $connector.properties.dataSource = $kustoConnectorUri\n if (-not $connector.properties.PSObject.Properties['identity']) {\n $connector.properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n }\n }\n}\n\nfunction Invoke-ArmPutConnector([string]$Name, $Body) {\n $uri = \"$armBase/connectors/$Name`?api-version=$armApiVersion\"\n Invoke-WithRetry -Label \"ARM PUT connector $Name\" -Action {\n Invoke-JsonRest -Method PUT -Uri $uri -Token (Get-ArmAccessTokenString) -Body $Body\n } | Out-Null\n Write-Output \" ARM PUT connectors/${Name}: ok\"\n}\n\nfunction Invoke-SreApi([string]$Method, [string]$Path, $Body = $null) {\n $uri = \"$agentEndpoint$Path\"\n return Invoke-WithRetry -Label \"$Method $Path\" -MaxAttempts 21 -DelaySeconds 30 -Action {\n Invoke-JsonRest -Method $Method -Uri $uri -Token (Get-SreAccessTokenString) -Body $Body\n }\n}\n\nfunction Invoke-ExtendedPut([string]$Kind, [string]$Name, [string]$Type, $Properties) {\n $encodedName = [Uri]::EscapeDataString($Name)\n $body = @{\n name = $Name\n type = $Type\n tags = @()\n properties = $Properties\n }\n Invoke-SreApi -Method PUT -Path \"/api/v2/extendedAgent/$Kind/$encodedName\" -Body $body | Out-Null\n Write-Output \" PUT $Kind/${Name}: ok\"\n}\n\nWrite-Output 'Step 1/7: Applying connectors...'\nforeach ($connector in Get-Collection $extras.connectors) {\n $name = [string]$connector.name\n $properties = $connector.properties\n if (-not $properties.PSObject.Properties['identity']) {\n $properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n Invoke-ArmPutConnector -Name $name -Body @{ properties = $properties }\n}\n\nWrite-Output 'Step 2/7: Configuring built-in tools...'\n$overrides = Get-Collection $extras.builtInTools.overrides\nif ($overrides.Count -gt 0) {\n $body = @{\n overrides = @($overrides | ForEach-Object {\n @{\n name = $_.name\n enabled = [bool]$_.enabled\n }\n })\n }\n Invoke-SreApi -Method POST -Path '/api/v2/agent/tools/configure' -Body $body | Out-Null\n Write-Output \" built-in tools configured: $($overrides.Count) overrides\"\n}\n\nWrite-Output 'Step 3/7: Uploading knowledge sources...'\nforeach ($item in Get-Collection $extras.knowledgeItems) {\n $sourceName = Get-KnowledgeSourceName ([string]$item.name)\n $bytes = [Text.Encoding]::UTF8.GetBytes([string]$item.content)\n $body = @{\n properties = @{\n dataConnectorType = 'KnowledgeFile'\n dataSource = $sourceName\n extendedProperties = @{\n displayName = [string]$item.name\n fileName = [string]$item.name\n fileContent = [Convert]::ToBase64String($bytes)\n contentType = [string](Get-PropertyValue $item @('contentType') 'application/octet-stream')\n }\n }\n }\n Invoke-ArmPutConnector -Name $sourceName -Body $body\n Start-Sleep -Seconds 5\n}\n\nWrite-Output 'Step 4/7: Applying tools...'\nforeach ($tool in Get-Collection $extras.tools) {\n $name = [string]$tool.metadata.name\n $properties = $tool.spec\n if ($properties.type -eq 'PythonTool') {\n $properties.type = 'PythonFunctionTool'\n }\n Invoke-ExtendedPut -Kind 'tools' -Name $name -Type 'ExtendedAgentTool' -Properties $properties\n}\n\nWrite-Output 'Step 5/7: Applying skills...'\nforeach ($skill in Get-Collection $extras.skills) {\n $name = [string]$skill.metadata.name\n $tools = @()\n if ($skill.metadata.spec -and $skill.metadata.spec.tools) {\n $tools = Get-Collection $skill.metadata.spec.tools\n }\n $properties = @{\n name = $name\n description = [string](Get-PropertyValue $skill.metadata @('description'))\n tools = $tools\n skillContent = [string](Get-PropertyValue $skill @('skillContent'))\n additionalFiles = @()\n }\n Invoke-ExtendedPut -Kind 'skills' -Name $name -Type 'Skill' -Properties $properties\n}\n\nWrite-Output 'Step 6/7: Applying subagents...'\nforeach ($subagent in Get-Collection $extras.subagents) {\n $name = [string]$subagent.metadata.name\n Invoke-ExtendedPut -Kind 'agents' -Name $name -Type 'ExtendedAgent' -Properties $subagent.spec\n}\n\nWrite-Output 'Step 7/7: Applying scheduled tasks...'\n$scheduledTasks = Get-Collection $extras.scheduledTasks\nif ($scheduledTasks.Count -gt 0) {\n $existing = Invoke-SreApi -Method GET -Path '/api/v1/scheduledtasks'\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n foreach ($match in (Get-Collection $existing | Where-Object { $_.name -eq $name })) {\n if ($match.id) {\n Invoke-SreApi -Method DELETE -Path \"/api/v1/scheduledtasks/$($match.id)\" | Out-Null\n Write-Output \" deleted existing scheduledtasks/$name\"\n }\n }\n }\n\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n $spec = $task.spec\n $properties = @{\n name = [string](Get-PropertyValue $spec @('name') $name)\n description = [string](Get-PropertyValue $spec @('description'))\n cronExpression = [string](Get-PropertyValue $spec @('schedule', 'cronExpression', 'cron_expression'))\n agentPrompt = [string](Get-PropertyValue $spec @('prompt', 'agentPrompt', 'agent_prompt'))\n agentMode = [string](Get-PropertyValue $spec @('mode', 'agentMode', 'agent_mode') 'Review')\n isEnabled = [bool](Get-PropertyValue $spec @('enabled') $true)\n agent = [string](Get-PropertyValue $spec @('agent'))\n }\n Invoke-ExtendedPut -Kind 'scheduledtasks' -Name $name -Type 'ScheduledTask' -Properties $properties\n }\n}\n\nWrite-Output 'SRE Agent extras complete.'\n", + "identityName": "[format('id-sre-apply-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", + "scriptName": "[format('apply-sre-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", + "sreAgentAdminRoleId": "e79298df-d852-4c6d-84f9-5d13249d1e55" + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[variables('identityName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/agents', parameters('agentName'))]", + "name": "[guid(resourceId('Microsoft.App/agents', parameters('agentName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), variables('sreAgentAdminRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('sreAgentAdminRoleId'))]", + "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), '2023-01-31').principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]" + ] + }, + { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[variables('scriptName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "AzurePowerShell", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')))]": {} + } + }, + "properties": { + "azPowerShellVersion": "11.0", + "retentionInterval": "PT1H", + "cleanupPreference": "OnSuccess", + "timeout": "PT2H", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "scriptContent": "[variables('$fxv#0')]", + "environmentVariables": [ + { + "name": "subscriptionId", + "value": "[parameters('subscriptionId')]" + }, + { + "name": "resourceGroupName", + "value": "[resourceGroup().name]" + }, + { + "name": "agentName", + "value": "[parameters('agentName')]" + }, + { + "name": "agentEndpoint", + "value": "[parameters('agentEndpoint')]" + }, + { + "name": "recipePackageUri", + "value": "[parameters('recipePackageUri')]" + }, + { + "name": "kustoConnectorUri", + "value": "[parameters('kustoConnectorUri')]" + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]", + "[extensionResourceId(resourceId('Microsoft.App/agents', parameters('agentName')), 'Microsoft.Authorization/roleAssignments', guid(resourceId('Microsoft.App/agents', parameters('agentName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), variables('sreAgentAdminRoleId')))]" + ] + } + ], + "outputs": { + "identityName": { + "type": "string", + "value": "[variables('identityName')]" + }, + "scriptName": { + "type": "string", + "value": "[variables('scriptName')]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]", + "targetRbac" + ] + } + ], + "outputs": { + "AZURE_RESOURCE_GROUP": { + "type": "string", + "value": "[parameters('resourceGroupName')]" + }, + "AZURE_LOCATION": { + "type": "string", + "value": "[parameters('location')]" + }, + "SRE_AGENT_NAME": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentName.value]" + }, + "SRE_AGENT_ENDPOINT": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "AGENT_PORTAL_URL": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPortalUrl.value]" + }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "SYSTEM_MANAGED_IDENTITY_TENANT_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentTenantId.value]" + }, + "LOG_ANALYTICS_WORKSPACE_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.logAnalyticsWorkspaceId.value]" + }, + "APPLY_EXTRAS_SCRIPT": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'apply-extras'), '2025-04-01').outputs.scriptName.value]" + } + } +} \ No newline at end of file diff --git a/docs/deploy/sre-agent/latest/createUiDefinition.json b/docs/deploy/sre-agent/latest/createUiDefinition.json new file mode 100644 index 000000000..87e82bcaa --- /dev/null +++ b/docs/deploy/sre-agent/latest/createUiDefinition.json @@ -0,0 +1,169 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#", + "handler": "Microsoft.Azure.CreateUIDef", + "version": "0.1.2-preview", + "parameters": { + "config": { + "basics": { + "description": "Deploy Azure SRE Agent with the FinOps toolkit recipe for FinOps hub analysis, capacity monitoring, scheduled tasks, and specialist agents.", + "location": { + "label": "Location", + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ] + } + } + }, + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ], + "basics": [ + { + "name": "resourceGroupName", + "type": "Microsoft.Common.TextBox", + "label": "Agent resource group", + "defaultValue": "finops-hub-sre", + "toolTip": "Resource group that will contain the Azure SRE Agent, monitoring resources, and deployment script identity.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9._()\\-]{1,90}$", + "validationMessage": "Enter a valid Azure resource group name." + }, + "visible": true + }, + { + "name": "agentName", + "type": "Microsoft.Common.TextBox", + "label": "Agent name", + "defaultValue": "finops-hub-sre", + "toolTip": "Name of the Azure SRE Agent resource.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9][a-zA-Z0-9\\-]{1,61}[a-zA-Z0-9]$", + "validationMessage": "Name must be 3-63 characters and can contain letters, numbers, and hyphens. The first and last characters must be alphanumeric." + }, + "visible": true + } + ], + "steps": [ + { + "name": "configuration", + "label": "Configuration", + "elements": [ + { + "name": "finopsHubKustoConnectorUri", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto URI", + "defaultValue": "", + "toolTip": "Optional database-qualified Azure Data Explorer URI for the FinOps hub. Example: https://cluster.region.kusto.windows.net/Hub", + "constraints": { + "required": false, + "regex": "^$|^https://.+\\.kusto\\.windows\\.net/.+", + "validationMessage": "Enter a database-qualified Kusto URI such as https://cluster.region.kusto.windows.net/Hub, or leave blank." + }, + "visible": true + }, + { + "name": "finopsHubKustoClusterResourceId", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto cluster resource ID", + "defaultValue": "", + "toolTip": "Optional Azure Data Explorer cluster resource ID. Provide this to assign the agent managed identity AllDatabasesViewer on the cluster.", + "constraints": { + "required": false, + "regex": "^$|^/subscriptions/.+/resourceGroups/.+/providers/Microsoft\\.Kusto/clusters/.+", + "validationMessage": "Enter a valid Microsoft.Kusto/clusters resource ID, or leave blank." + }, + "visible": true + }, + { + "name": "targetResourceGroups", + "type": "Microsoft.Common.TextBox", + "label": "Additional target resource groups", + "defaultValue": "", + "toolTip": "Optional comma-separated resource group names the agent can observe or act on. The agent resource group is always included.", + "constraints": { + "required": false, + "regex": "^$|^[A-Za-z0-9_.()\\-]+(\\s*,\\s*[A-Za-z0-9_.()\\-]+)*$", + "validationMessage": "Enter a comma-separated list of resource group names without blank entries or trailing commas." + }, + "visible": true + }, + { + "name": "accessLevel", + "type": "Microsoft.Common.OptionsGroup", + "label": "Access level", + "defaultValue": "High", + "toolTip": "High adds Contributor on target resource groups for autonomous remediation workflows. Low grants read-only monitoring roles.", + "constraints": { + "allowedValues": [ + { + "label": "High", + "value": "High" + }, + { + "label": "Low", + "value": "Low" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "actionMode", + "type": "Microsoft.Common.OptionsGroup", + "label": "Action mode", + "defaultValue": "autonomous", + "toolTip": "Review requires approval before write actions. Autonomous lets the agent run enabled actions within its assigned access.", + "constraints": { + "allowedValues": [ + { + "label": "Autonomous", + "value": "autonomous" + }, + { + "label": "Review", + "value": "review" + }, + { + "label": "Read only", + "value": "readOnly" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "enableSubscriptionReaderRole", + "type": "Microsoft.Common.CheckBox", + "label": "Grant subscription Reader to the agent", + "toolTip": "Recommended. Grants the agent managed identity Reader on the deployment subscription for inventory, Resource Graph, capacity, quota, and monitoring coverage workflows.", + "defaultValue": true, + "visible": true + } + ] + } + ], + "outputs": { + "resourceGroupName": "[basics('resourceGroupName')]", + "agentName": "[basics('agentName')]", + "location": "[location()]", + "targetResourceGroupNames": "[steps('configuration').targetResourceGroups]", + "finopsHubKustoConnectorUri": "[steps('configuration').finopsHubKustoConnectorUri]", + "finopsHubKustoClusterResourceId": "[steps('configuration').finopsHubKustoClusterResourceId]", + "accessLevel": "[steps('configuration').accessLevel]", + "actionMode": "[steps('configuration').actionMode]", + "enableSubscriptionReaderRole": "[steps('configuration').enableSubscriptionReaderRole]" + } + } +} diff --git a/docs/deploy/sre-agent/latest/sre-agent-recipe.zip b/docs/deploy/sre-agent/latest/sre-agent-recipe.zip new file mode 100644 index 0000000000000000000000000000000000000000..159ae7454137f5096b46f48672aeefb4b3f4c11f GIT binary patch literal 346636 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%0A)e)d3rs&)|sg|KHplPj~#pU_9+m5qE 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 z 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%0D6D`-ZdASrQP9OimVrY6mqmXI2owz@k-Eo#;# zn03z$MGL%}xoN4r#kD&o?ARbJOcm6l*Yyv%Pi3QoYdGurPYU_*V2V2!Z|poUCi-Gj!oZZ=xoA zsFgY8BHDsDHvzurS7>@ysuL4AUa6NxWG!2ZnF_XbtWc@;HLt2|X+s37T&?n&Bcu;T zmYRM9=qpo``5gA^QqvC+y$v;7V#|)SAJFqJ!Bh>%eoIsVxt8gPSFLxYn#D^ysIg5p zEz}k9Z`OfFUzM7Ug}O2|{Rq+<<(p+p(@og6Le%K(bxi@a1i0l5gaWmw*`#cCQzH?p zH{dX9coH4{^fuJE+%m?rzB%uF2aNUAskyPZtqvsYt5dV9k992?PYZy$rQLCZ$kDJH zDo-mTyMu47EKp$8NA3 z+kTse`@aw30fv*az`@nJbOs>`2?}gZ_cGPc7Unt#JFanQc;L>{a^VojZ4E z@m$Q#_6ae&CBtl=>ats!%l1huyCtw}AB4PH0CM0CzaC@~WPvRpU4n74aavFM@ql}P zFcW!9=}Kies$>S}>-K@I4foX*gIc!_65TC8bo=nn-9kUN5A576sB`;}&E3K^Lsw?M z%-iS2oW#=anm1ZIPUJgXJB~=dYx!GbaBfwDvj+NODrTFmhRb|er-Fe`#(7t14~F}$ za≺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