From 69d59d8d0f4722e13c6d1a7e11f9bd2b4de81524 Mon Sep 17 00:00:00 2001 From: dm-chelupati Date: Sun, 12 Oct 2025 22:36:02 -0700 Subject: [PATCH] Add Bicep deployment samples for SRE Agent - Add comprehensive Bicep templates for SRE Agent deployment - Include subscription and cross-resource group targeting - Provide interactive deployment scripts with CLI support - Add role assignment templates for security configuration - Include examples, documentation, and troubleshooting guides This contribution enables Infrastructure as Code (IaC) deployment of Azure SRE Agents with advanced configuration options including: - Custom subscription and resource group targeting - Multi-resource group access permissions - Cross-subscription support - High/Low access level configurations - Automated role assignments --- samples/README.md | 46 ++ samples/bicep-deployment/LICENSE | 21 + samples/bicep-deployment/README.md | 176 ++++++ .../bicep/minimal-sre-agent.bicep | 62 ++ .../bicep/role-assignments-minimal.bicep | 80 +++ .../bicep/role-assignments-target.bicep | 35 ++ .../bicep/sre-agent-resources.bicep | 266 ++++++++ .../minimal-sre-agent.parameters.json | 38 ++ .../examples/sre-agent-no-targets.config | 25 + .../examples/sre-agent.config | 29 + samples/bicep-deployment/scripts/deploy.sh | 567 ++++++++++++++++++ .../scripts/quick-deploy-no-targets.sh | 97 +++ samples/bicep-deployment/scripts/validate.sh | 63 ++ 13 files changed, 1505 insertions(+) create mode 100644 samples/README.md create mode 100644 samples/bicep-deployment/LICENSE create mode 100644 samples/bicep-deployment/README.md create mode 100644 samples/bicep-deployment/bicep/minimal-sre-agent.bicep create mode 100644 samples/bicep-deployment/bicep/role-assignments-minimal.bicep create mode 100644 samples/bicep-deployment/bicep/role-assignments-target.bicep create mode 100644 samples/bicep-deployment/bicep/sre-agent-resources.bicep create mode 100644 samples/bicep-deployment/examples/minimal-sre-agent.parameters.json create mode 100644 samples/bicep-deployment/examples/sre-agent-no-targets.config create mode 100644 samples/bicep-deployment/examples/sre-agent.config create mode 100755 samples/bicep-deployment/scripts/deploy.sh create mode 100755 samples/bicep-deployment/scripts/quick-deploy-no-targets.sh create mode 100755 samples/bicep-deployment/scripts/validate.sh diff --git a/samples/README.md b/samples/README.md new file mode 100644 index 0000000..97f2698 --- /dev/null +++ b/samples/README.md @@ -0,0 +1,46 @@ +# SRE Agent Samples + +This directory contains community-contributed samples and deployment templates for the Azure SRE Agent. + +## Available Samples + +### [Bicep Deployment](./bicep-deployment/) + +A comprehensive Bicep-based Infrastructure as Code (IaC) solution for deploying Azure SRE Agents with advanced configuration options. + +**Features:** +- 🎯 **Subscription Targeting**: Deploy SRE Agents to specific Azure subscriptions +- 🏗️ **Custom Resource Groups**: Deploy to any resource group with flexible naming +- 🔐 **Multi-Resource Group Access**: Grant SRE Agent permissions across multiple resource groups +- 🌐 **Cross-Subscription Support**: Target resource groups across different subscriptions +- 🤖 **Interactive Deployment**: User-friendly deployment scripts with CLI and config file support +- 📋 **Role Assignment Management**: Automated permission setup with high/low access levels + +**What's Included:** +- Complete Bicep templates for SRE Agent deployment +- Role assignment templates for security configuration +- Interactive deployment scripts with CLI interface +- Configuration examples and parameter files +- Comprehensive documentation and troubleshooting guides + +**Quick Start:** +```bash +cd bicep-deployment +chmod +x scripts/deploy.sh +./scripts/deploy.sh +``` + +## Contributing + +We welcome community contributions! If you have samples, templates, or tools that would help others deploy and manage SRE Agents, please feel free to contribute. + +### Guidelines for New Samples +- Include comprehensive documentation +- Provide example configurations +- Follow Azure best practices +- Include proper error handling +- Test thoroughly before submitting + +## Support + +For issues specific to these samples, please open a GitHub issue in this repository. For SRE Agent product support, please use the appropriate Azure support channels. diff --git a/samples/bicep-deployment/LICENSE b/samples/bicep-deployment/LICENSE new file mode 100644 index 0000000..71d7437 --- /dev/null +++ b/samples/bicep-deployment/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Azure SRE Agent Bicep Deployment + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/samples/bicep-deployment/README.md b/samples/bicep-deployment/README.md new file mode 100644 index 0000000..d12695e --- /dev/null +++ b/samples/bicep-deployment/README.md @@ -0,0 +1,176 @@ +# SRE Agent Bicep Deployment + +This Bicep deployment allows you to deploy an SRE Agent with configurable subscription, resource group targeting, and role assignments across multiple resource groups. + +## New Features + +1. **Subscription Targeting**: Specify the subscription where the SRE Agent should be deployed +2. **Custom Resource Group**: Deploy the SRE Agent to any resource group +3. **Multi-Resource Group Access**: Grant the SRE Agent permissions across multiple resource groups +4. **Cross-Subscription Support**: Target resource groups across different subscriptions + +## Files Structure + +- `minimal-sre-agent.bicep` - Main template (subscription-scoped) +- `sre-agent-resources.bicep` - Resource group-scoped module containing all resources +- `role-assignments-minimal.bicep` - Role assignments for the deployment resource group +- `role-assignments-target.bicep` - Role assignments for target resource groups +- `minimal-sre-agent.parameters.json` - Example parameters file +- `deploy.sh` - Interactive deployment script with command-line interface + +## Parameters + +### Required Parameters +- `agentName`: Name of the SRE Agent +- `deploymentResourceGroupName`: Resource group where SRE Agent will be deployed + +### Optional Parameters +- `subscriptionId`: Target subscription (defaults to current subscription) +- `location`: Azure region (default: eastus2) +- `existingManagedIdentityId`: Use existing managed identity instead of creating new one +- `accessLevel`: High or Low access level (default: High) +- `agentMode`: Review, Autonomous, or ReadOnly (default: Review) +- `targetResourceGroups`: Array of resource group names to grant access to +- `targetSubscriptions`: Array of subscription IDs for target resource groups + +## Deployment Methods + +### Quick Start: Deploy Without Target Resource Groups + +If you want to deploy just the SRE Agent infrastructure without assigning it to any target resource groups: + +```bash +# Interactive mode - leave target RGs empty +./deploy.sh + +# Or use the no-targets config file +./deploy.sh --config sre-agent-no-targets.config + +# Or command line mode +./deploy.sh --no-interactive \ + -s "your-subscription-id" \ + -r "rg-sre-agent" \ + -n "my-sre-agent" \ + --yes +``` + +See [DEPLOY-NO-TARGETS.md](DEPLOY-NO-TARGETS.md) for complete details on standalone deployment. + +### Method 1: Using Azure CLI with Parameters File + +1. Update `minimal-sre-agent.parameters.json` with your values: +```json +{ + "parameters": { + "agentName": { "value": "my-sre-agent" }, + "subscriptionId": { "value": "12345678-1234-1234-1234-123456789012" }, + "deploymentResourceGroupName": { "value": "rg-sre-agent" }, + "targetResourceGroups": { + "value": ["rg-production-web", "rg-production-data"] + } + } +} +``` + +2. Deploy: +```bash +az deployment sub create \ + --subscription "12345678-1234-1234-1234-123456789012" \ + --location "eastus2" \ + --template-file minimal-sre-agent.bicep \ + --parameters @minimal-sre-agent.parameters.json +``` + +### Method 2: Using the Deployment Script + +Make the script executable and run: +```bash +chmod +x deploy.sh +./deploy.sh -s "12345678-1234-1234-1234-123456789012" \ + -r "rg-sre-agent" \ + -n "my-sre-agent" \ + -l "eastus2" \ + -a "High" \ + -m "Review" \ + -t "rg-prod-web,rg-prod-data,rg-staging" +``` + +### Method 3: Direct Azure CLI with Inline Parameters + +```bash +az deployment sub create \ + --subscription "12345678-1234-1234-1234-123456789012" \ + --location "eastus2" \ + --template-file minimal-sre-agent.bicep \ + --parameters \ + agentName="my-sre-agent" \ + subscriptionId="12345678-1234-1234-1234-123456789012" \ + deploymentResourceGroupName="rg-sre-agent" \ + location="eastus2" \ + accessLevel="High" \ + agentMode="Review" \ + targetResourceGroups='["rg-prod-web","rg-prod-data"]' +``` + +## Access Levels + +### Low Access Level +- Log Analytics Reader +- Reader + +### High Access Level +- Log Analytics Reader +- Reader +- Contributor + +## Cross-Subscription Targeting + +To target resource groups in different subscriptions, provide both `targetResourceGroups` and `targetSubscriptions` arrays: + +```json +{ + "targetResourceGroups": { + "value": ["rg-prod-web", "rg-prod-data", "rg-staging"] + }, + "targetSubscriptions": { + "value": [ + "12345678-1234-1234-1234-123456789012", + "12345678-1234-1234-1234-123456789012", + "87654321-4321-4321-4321-210987654321" + ] + } +} +``` + +The arrays are matched by index - the first resource group uses the first subscription, etc. + +## Outputs + +The template provides these outputs: +- `agentName`: Name of the created SRE Agent +- `agentId`: Resource ID of the SRE Agent +- `agentPortalUrl`: Direct link to manage the agent in Azure Portal +- `userAssignedIdentityId`: Resource ID of the managed identity +- `applicationInsightsConnectionString`: Connection string for Application Insights +- `logAnalyticsWorkspaceId`: Resource ID of the Log Analytics workspace +- `createdNewManagedIdentity`: Boolean indicating if a new managed identity was created + +## Prerequisites + +- Azure CLI installed and authenticated +- Appropriate permissions to create resources and assign roles +- Owner or User Access Administrator role on target subscriptions/resource groups +- SRE Agent resource provider registered in target subscriptions + +## Troubleshooting + +### Permission Issues +Ensure you have: +- Owner or Contributor + User Access Administrator roles +- Permission to create role assignments across target resource groups +- Permission to create resources in the deployment resource group + +### Cross-Subscription Scenarios +- Ensure you have permissions in all target subscriptions +- Verify resource group names exist in their respective subscriptions +- Check that the SRE Agent resource provider is available in target regions diff --git a/samples/bicep-deployment/bicep/minimal-sre-agent.bicep b/samples/bicep-deployment/bicep/minimal-sre-agent.bicep new file mode 100644 index 0000000..c83cae2 --- /dev/null +++ b/samples/bicep-deployment/bicep/minimal-sre-agent.bicep @@ -0,0 +1,62 @@ +targetScope = 'subscription' + +#disable-next-line BCP081 +@description('The name of the SRE Agent') +param agentName string + +@description('The subscription ID where resources will be deployed') +param subscriptionId string = subscription().subscriptionId + +@description('The name of the resource group where the SRE Agent will be deployed') +param deploymentResourceGroupName string + +@description('The location where the resources will be deployed') +@allowed(['swedencentral', 'uksouth', 'eastus2', 'australiaeast']) +param location string = 'eastus2' + +@description('Optional: The resource ID of an existing user-assigned managed identity. If not provided, a new one will be created.') +param existingManagedIdentityId string = '' + +@description('The access level for the SRE Agent') +@allowed(['High', 'Low']) +param accessLevel string = 'High' + +@description('Array of resource group names that the SRE Agent should have permissions to manage') +param targetResourceGroups array = [] + +@description('Array of subscription IDs where the target resource groups exist (optional, defaults to deployment subscription)') +param targetSubscriptions array = [] + +// Generate unique suffix for resource names +var uniqueSuffix = uniqueString(subscriptionId, deploymentResourceGroupName) + +// Reference to the deployment resource group +resource deploymentResourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' existing = { + name: deploymentResourceGroupName + scope: subscription(subscriptionId) +} + +// Deploy SRE Agent resources to the deployment resource group +module sreAgentResourcesDeployment 'sre-agent-resources.bicep' = { + name: 'sre-agent-resources-${uniqueString(deployment().name)}' + scope: deploymentResourceGroup + params: { + agentName: agentName + location: location + existingManagedIdentityId: existingManagedIdentityId + accessLevel: accessLevel + targetResourceGroups: targetResourceGroups + targetSubscriptions: targetSubscriptions + subscriptionId: subscriptionId + uniqueSuffix: uniqueSuffix + } +} + +// Outputs +output agentName string = sreAgentResourcesDeployment.outputs.agentName +output agentId string = sreAgentResourcesDeployment.outputs.agentId +output agentPortalUrl string = sreAgentResourcesDeployment.outputs.agentPortalUrl +output userAssignedIdentityId string = sreAgentResourcesDeployment.outputs.userAssignedIdentityId +output applicationInsightsConnectionString string = sreAgentResourcesDeployment.outputs.applicationInsightsConnectionString +output logAnalyticsWorkspaceId string = sreAgentResourcesDeployment.outputs.logAnalyticsWorkspaceId +output createdNewManagedIdentity bool = sreAgentResourcesDeployment.outputs.createdNewManagedIdentity diff --git a/samples/bicep-deployment/bicep/role-assignments-minimal.bicep b/samples/bicep-deployment/bicep/role-assignments-minimal.bicep new file mode 100644 index 0000000..23474a9 --- /dev/null +++ b/samples/bicep-deployment/bicep/role-assignments-minimal.bicep @@ -0,0 +1,80 @@ +@description('The principal ID of the user-assigned managed identity') +param userAssignedIdentityPrincipalId string + +@description('The principal ID of the system-assigned managed identity (optional)') +param systemAssignedIdentityPrincipalId string = '' + +@description('The access level for role assignments') +@allowed(['Low', 'Medium', 'High']) +param accessLevel string + +@description('Enable Key Vault role assignments') +param enableKeyVault bool = true + +@description('Key Vault resource ID for scoped role assignments (optional)') +param keyVaultResourceId string = '' + +// Define role definition IDs based on the access level +var roleDefinitions = { + Low: [ + '92aaf0da-9dab-42b6-94a3-d43ce8d16293' // Log Analytics Reader + ] + Medium: [ + '92aaf0da-9dab-42b6-94a3-d43ce8d16293' // Log Analytics Reader + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' // Reader + ] + High: [ + '92aaf0da-9dab-42b6-94a3-d43ce8d16293' // Log Analytics Reader + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' // Reader + 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor + ] +} + +// Create role assignments based on access level for user-assigned identity +resource roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleDefinitionId, index) in roleDefinitions[accessLevel]: { + name: guid(resourceGroup().id, userAssignedIdentityPrincipalId, roleDefinitionId) + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) + principalId: userAssignedIdentityPrincipalId + principalType: 'ServicePrincipal' + } +}] + +// Create Application Insights Component Contributor role assignment for system-assigned identity (if provided) +// Note: This creates the role assignment at the resource group level for now +resource appInsightsRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(systemAssignedIdentityPrincipalId)) { + name: guid(resourceGroup().id, systemAssignedIdentityPrincipalId, 'ae349356-3a1b-4a5e-921d-050484c6347e') + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e') // Application Insights Component Contributor + principalId: systemAssignedIdentityPrincipalId + principalType: 'ServicePrincipal' + } +} + +// Create Key Vault role assignments for the user-assigned identity (if Key Vault is enabled) +// Key Vault Certificate User role +resource keyVaultCertificateUserRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableKeyVault && !empty(keyVaultResourceId)) { + name: guid(keyVaultResourceId, userAssignedIdentityPrincipalId, 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba') + scope: resourceGroup() + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba') // Key Vault Certificate User + principalId: userAssignedIdentityPrincipalId + principalType: 'ServicePrincipal' + } +} + +// Key Vault Secrets User role +resource keyVaultSecretsUserRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableKeyVault && !empty(keyVaultResourceId)) { + name: guid(keyVaultResourceId, userAssignedIdentityPrincipalId, '4633458b-17de-408a-b874-0445c86b69e6') + scope: resourceGroup() + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6') // Key Vault Secrets User + principalId: userAssignedIdentityPrincipalId + principalType: 'ServicePrincipal' + } +} + +output assignedRoles array = [for (roleDefinitionId, index) in roleDefinitions[accessLevel]: { + roleDefinitionId: roleDefinitionId + principalId: userAssignedIdentityPrincipalId +}] diff --git a/samples/bicep-deployment/bicep/role-assignments-target.bicep b/samples/bicep-deployment/bicep/role-assignments-target.bicep new file mode 100644 index 0000000..31abc20 --- /dev/null +++ b/samples/bicep-deployment/bicep/role-assignments-target.bicep @@ -0,0 +1,35 @@ +@description('The principal ID of the user-assigned managed identity') +param userAssignedIdentityPrincipalId string + +@description('The access level for role assignments') +@allowed(['Low', 'High']) +param accessLevel string + +// Define role definition IDs based on the access level +var roleDefinitions = { + Low: [ + '92aaf0da-9dab-42b6-94a3-d43ce8d16293' // Log Analytics Reader + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' // Reader + ] + High: [ + '92aaf0da-9dab-42b6-94a3-d43ce8d16293' // Log Analytics Reader + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' // Reader + 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor + ] +} + +// Create role assignments based on access level for user-assigned identity in target resource groups +resource roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleDefinitionId, index) in roleDefinitions[accessLevel]: { + name: guid(resourceGroup().id, userAssignedIdentityPrincipalId, roleDefinitionId) + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) + principalId: userAssignedIdentityPrincipalId + principalType: 'ServicePrincipal' + } +}] + +output assignedRoles array = [for (roleDefinitionId, index) in roleDefinitions[accessLevel]: { + roleDefinitionId: roleDefinitionId + principalId: userAssignedIdentityPrincipalId + resourceGroupId: resourceGroup().id +}] diff --git a/samples/bicep-deployment/bicep/sre-agent-resources.bicep b/samples/bicep-deployment/bicep/sre-agent-resources.bicep new file mode 100644 index 0000000..e2eabdd --- /dev/null +++ b/samples/bicep-deployment/bicep/sre-agent-resources.bicep @@ -0,0 +1,266 @@ +@description('The name of the SRE Agent') +param agentName string + +@description('The location where the resources will be deployed') +param location string + +@description('Optional: The resource ID of an existing user-assigned managed identity. If not provided, a new one will be created.') +param existingManagedIdentityId string = '' + +@description('The access level for the SRE Agent') +@allowed(['High', 'Low']) +param accessLevel string = 'High' + +@description('Array of resource group names that the SRE Agent should have permissions to manage') +param targetResourceGroups array = [] + +@description('Array of subscription IDs where the target resource groups exist') +param targetSubscriptions array = [] + +@description('The subscription ID where resources will be deployed') +param subscriptionId string + +@description('The unique suffix for resource names') +param uniqueSuffix string + +// Determine if we should create a new managed identity or use an existing one +var shouldCreateManagedIdentity = empty(existingManagedIdentityId) + +// Resource names +var logAnalyticsWorkspaceName = 'workspace${uniqueSuffix}' +var appInsightsName = 'app-insights-${uniqueSuffix}' +var userAssignedIdentityName = '${agentName}-${uniqueSuffix}' + +// Create Log Analytics Workspace +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsWorkspaceName + location: location + properties: { + sku: { + name: 'PerGB2018' + } + retentionInDays: 30 + features: { + enableLogAccessUsingOnlyResourcePermissions: true + } + } +} + +// Create Application Insights +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { + name: appInsightsName + location: location + kind: 'web' + properties: { + Application_Type: 'web' + Request_Source: 'SreAgent' + WorkspaceResourceId: logAnalyticsWorkspace.id + } +} + +// Create Action Group for Smart Detection alerts +resource smartDetectionActionGroup 'Microsoft.Insights/actionGroups@2023-01-01' = { + name: 'Application Insights Smart Detection' + location: 'Global' + properties: { + groupShortName: 'SmartDetect' + enabled: true + armRoleReceivers: [ + { + name: 'Monitoring Contributor' + roleId: '749f88d5-cbae-40b8-bcfc-e573ddc772fa' + useCommonAlertSchema: true + } + { + name: 'Monitoring Reader' + roleId: '43d0d8ad-25c7-4714-9337-8ba259a9fe05' + useCommonAlertSchema: true + } + ] + } +} + +// Create Smart Detector Alert Rule for Failure Anomalies +resource failureAnomaliesSmartDetector 'Microsoft.AlertsManagement/smartDetectorAlertRules@2021-04-01' = { + name: 'Failure Anomalies - ${appInsightsName}' + location: 'Global' + properties: { + description: 'Failure Anomalies notifies you of an unusual rise in the rate of failed HTTP requests or dependency calls.' + state: 'Enabled' + severity: 'Sev3' + frequency: 'PT1M' + detector: { + id: 'FailureAnomaliesDetector' + } + scope: [ + applicationInsights.id + ] + actionGroups: { + groupIds: [ + smartDetectionActionGroup.id + ] + } + } +} + +// Create User-Assigned Managed Identity (only if not using existing one) +#disable-next-line BCP073 +resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' = if (shouldCreateManagedIdentity) { + name: userAssignedIdentityName + location: location + properties: { + isolationScope: 'Regional' + } +} + +// Reference to the managed identity (either existing or newly created) +resource existingManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' existing = if (!shouldCreateManagedIdentity) { + name: last(split(existingManagedIdentityId, '/')) + scope: resourceGroup(split(existingManagedIdentityId, '/')[2], split(existingManagedIdentityId, '/')[4]) +} + +// Define role assignments for target resource groups (new identity) +module targetRoleAssignmentsNew 'role-assignments-target.bicep' = [for (targetRG, index) in targetResourceGroups: if (shouldCreateManagedIdentity) { + name: 'targetRoleAssignments-new-${index}-${uniqueString(deployment().name)}' + scope: resourceGroup(length(targetSubscriptions) > index ? targetSubscriptions[index] : subscriptionId, targetRG) + params: { + userAssignedIdentityPrincipalId: userAssignedIdentity!.properties.principalId + accessLevel: accessLevel + } +}] + +// Define role assignments for target resource groups (existing identity) +module targetRoleAssignmentsExisting 'role-assignments-target.bicep' = [for (targetRG, index) in targetResourceGroups: if (!shouldCreateManagedIdentity) { + name: 'targetRoleAssignments-existing-${index}-${uniqueString(deployment().name)}' + scope: resourceGroup(length(targetSubscriptions) > index ? targetSubscriptions[index] : subscriptionId, targetRG) + params: { + userAssignedIdentityPrincipalId: existingManagedIdentity!.properties.principalId + accessLevel: accessLevel + } +}] + +// Define role assignments for the deployment resource group (new identity) +module deploymentRoleAssignmentsNew 'role-assignments-minimal.bicep' = if (shouldCreateManagedIdentity) { + name: 'deploymentRoleAssignments-new-${uniqueString(deployment().name)}' + params: { + userAssignedIdentityPrincipalId: userAssignedIdentity!.properties.principalId + systemAssignedIdentityPrincipalId: '' + accessLevel: accessLevel + enableKeyVault: false + keyVaultResourceId: '' + } +} + +// Define role assignments for the deployment resource group (existing identity) +module deploymentRoleAssignmentsExisting 'role-assignments-minimal.bicep' = if (!shouldCreateManagedIdentity) { + name: 'deploymentRoleAssignments-existing-${uniqueString(deployment().name)}' + params: { + userAssignedIdentityPrincipalId: existingManagedIdentity!.properties.principalId + systemAssignedIdentityPrincipalId: '' + accessLevel: accessLevel + enableKeyVault: false + keyVaultResourceId: '' + } +} + +// Create the SRE Agent with new managed identity +#disable-next-line BCP081 +resource sreAgentNew 'Microsoft.App/agents@2025-05-01-preview' = if (shouldCreateManagedIdentity) { + name: agentName + location: location + identity: { + type: 'SystemAssigned, UserAssigned' + userAssignedIdentities: { + '${userAssignedIdentity.id}': {} + } + } + properties: { + knowledgeGraphConfiguration: { + identity: userAssignedIdentity.id + managedResources: [] + } + actionConfiguration: { + accessLevel: accessLevel + identity: userAssignedIdentity.id + mode: 'Review' + } + logConfiguration: { + applicationInsightsConfiguration: { + appId: applicationInsights.properties.AppId + connectionString: applicationInsights.properties.ConnectionString + } + } + } + dependsOn: [ + deploymentRoleAssignmentsNew + targetRoleAssignmentsNew + ] +} + +// Create the SRE Agent with existing managed identity +#disable-next-line BCP081 +resource sreAgentExisting 'Microsoft.App/agents@2025-05-01-preview' = if (!shouldCreateManagedIdentity) { + name: agentName + location: location + identity: { + type: 'SystemAssigned, UserAssigned' + userAssignedIdentities: { + '${existingManagedIdentityId}': {} + } + } + properties: { + knowledgeGraphConfiguration: { + identity: existingManagedIdentityId + managedResources: [] + } + actionConfiguration: { + accessLevel: accessLevel + identity: existingManagedIdentityId + mode: 'Review' + } + logConfiguration: { + applicationInsightsConfiguration: { + appId: applicationInsights.properties.AppId + connectionString: applicationInsights.properties.ConnectionString + } + } + } + dependsOn: [ + deploymentRoleAssignmentsExisting + targetRoleAssignmentsExisting + ] +} + +// Assign SRE Agent Administrator role to the deployment user on the SRE Agent resource (for new identity) +// The user needs this role to manage the SRE Agent through the portal, configure workflows, and monitor the agent +// Using deployer().objectId automatically gets the principal ID of whoever runs the deployment +resource sreAgentAdminUserRoleAssignmentNew 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (shouldCreateManagedIdentity) { + name: guid(sreAgentNew.id, deployer().objectId, 'e79298df-d852-4c6d-84f9-5d13249d1e55-user') + scope: sreAgentNew + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'e79298df-d852-4c6d-84f9-5d13249d1e55') // SRE Agent Administrator + principalId: deployer().objectId + principalType: 'User' + } +} + +// Assign SRE Agent Administrator role to the deployment user on the SRE Agent resource (for existing identity) +// The user needs this role to manage the SRE Agent through the portal, configure workflows, and monitor the agent +resource sreAgentAdminUserRoleAssignmentExisting 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!shouldCreateManagedIdentity) { + name: guid(sreAgentExisting.id, deployer().objectId, 'e79298df-d852-4c6d-84f9-5d13249d1e55-user') + scope: sreAgentExisting + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'e79298df-d852-4c6d-84f9-5d13249d1e55') // SRE Agent Administrator + principalId: deployer().objectId + principalType: 'User' + } +} + +// Outputs +output agentName string = shouldCreateManagedIdentity ? sreAgentNew.name : sreAgentExisting.name +output agentId string = shouldCreateManagedIdentity ? sreAgentNew.id : sreAgentExisting.id +output agentPortalUrl string = 'https://ms.portal.azure.com/#view/Microsoft_Azure_PaasServerless/AgentFrameBlade.ReactView/id/${replace(shouldCreateManagedIdentity ? sreAgentNew.id : sreAgentExisting.id, '/', '%2F')}' +output userAssignedIdentityId string = shouldCreateManagedIdentity ? userAssignedIdentity.id : existingManagedIdentityId +output applicationInsightsConnectionString string = applicationInsights.properties.ConnectionString +output logAnalyticsWorkspaceId string = logAnalyticsWorkspace.id +output createdNewManagedIdentity bool = shouldCreateManagedIdentity diff --git a/samples/bicep-deployment/examples/minimal-sre-agent.parameters.json b/samples/bicep-deployment/examples/minimal-sre-agent.parameters.json new file mode 100644 index 0000000..5b30d17 --- /dev/null +++ b/samples/bicep-deployment/examples/minimal-sre-agent.parameters.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "agentName": { + "value": "my-sre-agent" + }, + "subscriptionId": { + "value": "your-subscription-id-here" + }, + "deploymentResourceGroupName": { + "value": "rg-sre-agent" + }, + "location": { + "value": "eastus2" + }, + "existingManagedIdentityId": { + "value": "" + }, + "accessLevel": { + "value": "High" + }, + "targetResourceGroups": { + "value": [ + "rg-production-web", + "rg-production-data", + "rg-staging-web" + ] + }, + "targetSubscriptions": { + "value": [ + "subscription-id-1", + "subscription-id-1", + "subscription-id-2" + ] + } + } +} diff --git a/samples/bicep-deployment/examples/sre-agent-no-targets.config b/samples/bicep-deployment/examples/sre-agent-no-targets.config new file mode 100644 index 0000000..7b94ff1 --- /dev/null +++ b/samples/bicep-deployment/examples/sre-agent-no-targets.config @@ -0,0 +1,25 @@ +# Azure SRE Agent Configuration - No Target Resource Groups +# Deploy SRE Agent without assigning permissions to any target resource groups +# Use this when you only want the SRE Agent infrastructure without cross-RG access + +# Required Configuration +SUBSCRIPTION_ID="your-subscription-id-here" +RESOURCE_GROUP="rg-sre-agent" +AGENT_NAME="sre-agent-standalone" + +# Basic Configuration +LOCATION="eastus2" # swedencentral, uksouth, eastus2, australiaeast +ACCESS_LEVEL="High" # High, Low (doesn't matter when no targets) + +# Target Resource Groups - LEAVE EMPTY for standalone deployment +TARGET_RGS="" + +# Target Subscriptions - LEAVE EMPTY for standalone deployment +TARGET_SUBS="" + +# Optional: Existing Managed Identity (leave empty to create new) +EXISTING_IDENTITY="" + +# Deployment Options +CONFIRM_DEPLOYMENT=true # Set to false to skip confirmation prompt +VERBOSE_OUTPUT=false # Set to true for detailed output diff --git a/samples/bicep-deployment/examples/sre-agent.config b/samples/bicep-deployment/examples/sre-agent.config new file mode 100644 index 0000000..35b7bec --- /dev/null +++ b/samples/bicep-deployment/examples/sre-agent.config @@ -0,0 +1,29 @@ +# Azure SRE Agent Configuration File +# This file contains the configuration for deploying an SRE Agent +# You can modify these values and use them with: ./deploy.sh --config + +# Required Configuration +SUBSCRIPTION_ID="your-subscription-id-here" +RESOURCE_GROUP="rg-sre-agent" +AGENT_NAME="sre-agent-$(date +%Y%m%d)" + +# Basic Configuration +LOCATION="eastus2" # swedencentral, uksouth, eastus2, australiaeast +ACCESS_LEVEL="High" # High, Low +MODE="Review" # Review, Autonomous, ReadOnly + +# Target Resource Groups (comma-separated, can be empty) +TARGET_RGS="" +# Example: TARGET_RGS="rg-prod-web,rg-prod-data,rg-staging" + +# Target Subscriptions (comma-separated, optional - matches TARGET_RGS order) +TARGET_SUBS="" +# Example: TARGET_SUBS="sub1-id,sub1-id,sub2-id" + +# Optional: Existing Managed Identity (leave empty to create new) +EXISTING_IDENTITY="" +# Example: EXISTING_IDENTITY="/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.ManagedIdentity/userAssignedIdentities/xxx" + +# Deployment Options +CONFIRM_DEPLOYMENT=true # Set to false to skip confirmation prompt +VERBOSE_OUTPUT=false # Set to true for detailed output diff --git a/samples/bicep-deployment/scripts/deploy.sh b/samples/bicep-deployment/scripts/deploy.sh new file mode 100755 index 0000000..c301cb7 --- /dev/null +++ b/samples/bicep-deployment/scripts/deploy.sh @@ -0,0 +1,567 @@ +#!/bin/bash + +# Azure SRE Agent Interactive Deployment Script +# This script deploys an SRE Agent with configurable subscription, resource groups, and target assignments + +set -e + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +TEMPLATE_FILE="$PROJECT_ROOT/bicep/minimal-sre-agent.bicep" +PARAMETERS_FILE="$PROJECT_ROOT/examples/minimal-sre-agent.parameters.json" +DEFAULT_CONFIG_FILE="$PROJECT_ROOT/examples/sre-agent.config" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to load configuration from file +load_config() { + local config_file="$1" + + if [[ ! -f "$config_file" ]]; then + echo -e "${RED}Configuration file '$config_file' not found!${NC}" + echo -e "${BLUE}Creating a template configuration file...${NC}" + create_config_template "$config_file" + echo -e "${GREEN}Template created at '$config_file'. Please edit it and run the script again.${NC}" + exit 1 + fi + + echo -e "${BLUE}Loading configuration from '$config_file'...${NC}" + + # Source the config file + source "$config_file" + + # Validate required parameters + if [[ -z "$SUBSCRIPTION_ID" || -z "$RESOURCE_GROUP" || -z "$AGENT_NAME" ]]; then + echo -e "${RED}Error: Missing required configuration in '$config_file'${NC}" + echo -e "${BLUE}Required: SUBSCRIPTION_ID, RESOURCE_GROUP, AGENT_NAME${NC}" + exit 1 + fi + + echo -e "${GREEN}Configuration loaded successfully.${NC}" +} + +# Function to create configuration template +create_config_template() { + local config_file="$1" + + # Get current Azure info if available + local current_sub_id="" + if az account show &>/dev/null; then + current_sub_id=$(az account show --query 'id' -o tsv) + fi + + cat > "$config_file" << EOF +# Azure SRE Agent Configuration File +# This file contains the configuration for deploying an SRE Agent +# You can modify these values and use them with: ./deploy.sh --config + +# Required Configuration +SUBSCRIPTION_ID="${current_sub_id:-"your-subscription-id-here"}" +RESOURCE_GROUP="rg-sre-agent" +AGENT_NAME="sre-agent-\$(date +%Y%m%d)" + +# Basic Configuration +LOCATION="eastus2" # swedencentral, uksouth, eastus2, australiaeast +ACCESS_LEVEL="High" # High, Low + +# Target Resource Groups (comma-separated, can be empty) +TARGET_RGS="" +# Example: TARGET_RGS="rg-prod-web,rg-prod-data,rg-staging" + +# Target Subscriptions (comma-separated, optional - matches TARGET_RGS order) +TARGET_SUBS="" +# Example: TARGET_SUBS="sub1-id,sub1-id,sub2-id" + +# Optional: Existing Managed Identity (leave empty to create new) +EXISTING_IDENTITY="" +# Example: EXISTING_IDENTITY="/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.ManagedIdentity/userAssignedIdentities/xxx" + +# Deployment Options +CONFIRM_DEPLOYMENT=true # Set to false to skip confirmation prompt +VERBOSE_OUTPUT=false # Set to true for detailed output +EOF +} + +# Function to display usage +usage() { + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Modes:" + echo " Interactive Mode (default): $0" + echo " Config File Mode: $0 --config [CONFIG_FILE]" + echo " Command Line Mode: $0 --no-interactive [OPTIONS]" + echo "" + echo "Options:" + echo " -i, --interactive Run in interactive mode (default)" + echo " -c, --config CONFIG_FILE Use configuration file (default: sre-agent.config)" + echo " --no-interactive Disable interactive mode" + echo " --create-config CONFIG_FILE Create a configuration file template" + echo " -s, --subscription-id SUBSCRIPTION_ID Target subscription ID" + echo " -r, --resource-group RESOURCE_GROUP Resource group where SRE Agent will be deployed" + echo " -n, --agent-name AGENT_NAME Name of the SRE Agent" + echo " -l, --location LOCATION Azure region (eastus2, swedencentral, uksouth, australiaeast)" + echo " -a, --access-level ACCESS_LEVEL Access level (High, Low)" + echo " -t, --target-rgs \"RG1,RG2,RG3\" Comma-separated list of target resource groups" + echo " -u, --target-subs \"SUB1,SUB2,SUB3\" Comma-separated list of target subscriptions (optional)" + echo " -e, --existing-identity IDENTITY_ID Existing managed identity resource ID (optional)" + echo " -y, --yes Skip confirmation prompts" + echo " -v, --verbose Verbose output" + echo " -h, --help Display this help message" + echo "" + echo "Examples:" + echo "" + echo " Interactive Mode (guided setup):" + echo " $0" + echo "" + echo " Config File Mode (edit sre-agent.config first):" + echo " $0 --config" + echo " $0 --config my-custom.config" + echo "" + echo " Create Config Template:" + echo " $0 --create-config my-config.config" + echo "" + echo " Command Line Mode:" + echo " $0 --no-interactive \\" + echo " -s \"12345678-1234-1234-1234-123456789012\" \\" + echo " -r \"rg-sre-agent\" \\" + echo " -n \"my-sre-agent\" \\" + echo " -t \"rg-prod-web,rg-prod-data\"" +} + +# Function to get current Azure account info +get_azure_info() { + echo -e "${BLUE}Getting current Azure account information...${NC}" + + # Check if user is logged in + if ! az account show &>/dev/null; then + echo -e "${RED}You are not logged in to Azure. Please run 'az login' first.${NC}" + exit 1 + fi + + # Get current subscription info + CURRENT_SUB_INFO=$(az account show --query '{id:id, name:name}' -o tsv) + CURRENT_SUB_ID=$(echo "$CURRENT_SUB_INFO" | cut -f1) + CURRENT_SUB_NAME=$(echo "$CURRENT_SUB_INFO" | cut -f2) + + echo -e "${GREEN}Current Azure subscription:${NC}" + echo -e " ID: ${YELLOW}$CURRENT_SUB_ID${NC}" + echo -e " Name: ${YELLOW}$CURRENT_SUB_NAME${NC}" +} + +# Function to prompt for input with default value +prompt_with_default() { + local prompt="$1" + local default="$2" + local var_name="$3" + + if [[ -n "$default" ]]; then + echo -e -n "${BLUE}$prompt${NC} [${YELLOW}$default${NC}]: " + else + echo -e -n "${BLUE}$prompt${NC}: " + fi + + read -r input + if [[ -z "$input" && -n "$default" ]]; then + input="$default" + fi + + eval "$var_name='$input'" +} + +# Function to validate subscription ID format +validate_subscription_id() { + local sub_id="$1" + if [[ ! "$sub_id" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]]; then + echo -e "${RED}Invalid subscription ID format. Please use the format: 12345678-1234-1234-1234-123456789012${NC}" + return 1 + fi + return 0 +} + +# Function to validate Azure region +validate_location() { + local location="$1" + local valid_locations=("swedencentral" "uksouth" "eastus2" "australiaeast") + + for valid_loc in "${valid_locations[@]}"; do + if [[ "$location" == "$valid_loc" ]]; then + return 0 + fi + done + + echo -e "${RED}Invalid location. Valid options are: ${valid_locations[*]}${NC}" + return 1 +} + +# Function to run interactive mode +interactive_mode() { + echo -e "${GREEN}=== Azure SRE Agent Interactive Deployment ===${NC}" + echo "" + + # Get Azure info + get_azure_info + echo "" + + # Get subscription ID + while true; do + prompt_with_default "Enter subscription ID" "$CURRENT_SUB_ID" "SUBSCRIPTION_ID" + if validate_subscription_id "$SUBSCRIPTION_ID"; then + break + fi + done + + # Get resource group name + while true; do + prompt_with_default "Enter resource group name for SRE Agent deployment" "rg-sre-agent" "RESOURCE_GROUP" + if [[ -n "$RESOURCE_GROUP" ]]; then + break + fi + echo -e "${RED}Resource group name cannot be empty${NC}" + done + + # Get agent name + while true; do + prompt_with_default "Enter SRE Agent name" "sre-agent-$(date +%Y%m%d)" "AGENT_NAME" + if [[ -n "$AGENT_NAME" ]]; then + break + fi + echo -e "${RED}Agent name cannot be empty${NC}" + done + + # Get location + while true; do + prompt_with_default "Enter Azure region (swedencentral, uksouth, eastus2, australiaeast)" "eastus2" "LOCATION" + if validate_location "$LOCATION"; then + break + fi + done + + # Get access level + while true; do + prompt_with_default "Enter access level (High, Low)" "High" "ACCESS_LEVEL" + if [[ "$ACCESS_LEVEL" =~ ^(High|Low)$ ]]; then + break + fi + echo -e "${RED}Access level must be 'High' or 'Low'${NC}" + done + + # Get target resource groups + echo "" + echo -e "${BLUE}Target Resource Groups Configuration:${NC}" + echo -e "Enter the resource groups that the SRE Agent should manage." + echo -e "You can enter multiple resource groups separated by commas." + echo -e "Leave empty if you only want the agent to manage its own resource group." + prompt_with_default "Enter target resource groups (comma-separated)" "" "TARGET_RGS" + + # Get target subscriptions (optional) + if [[ -n "$TARGET_RGS" ]]; then + echo "" + echo -e "${BLUE}Target Subscriptions Configuration (Optional):${NC}" + echo -e "If your target resource groups are in different subscriptions," + echo -e "enter subscription IDs in the same order as resource groups." + echo -e "Leave empty to use the deployment subscription for all resource groups." + prompt_with_default "Enter target subscriptions (comma-separated)" "" "TARGET_SUBS" + fi + + # Get existing managed identity (optional) + echo "" + echo -e "${BLUE}Managed Identity Configuration (Optional):${NC}" + echo -e "You can use an existing managed identity instead of creating a new one." + prompt_with_default "Enter existing managed identity resource ID (optional)" "" "EXISTING_IDENTITY" + + # Display configuration summary + echo "" + echo -e "${GREEN}=== Deployment Configuration Summary ===${NC}" + echo -e "Subscription ID: ${YELLOW}$SUBSCRIPTION_ID${NC}" + echo -e "Resource Group: ${YELLOW}$RESOURCE_GROUP${NC}" + echo -e "Agent Name: ${YELLOW}$AGENT_NAME${NC}" + echo -e "Location: ${YELLOW}$LOCATION${NC}" + echo -e "Access Level: ${YELLOW}$ACCESS_LEVEL${NC}" + echo -e "Target Resource Groups: ${YELLOW}${TARGET_RGS:-"None (deployment RG only)"}${NC}" + echo -e "Target Subscriptions: ${YELLOW}${TARGET_SUBS:-"Use deployment subscription"}${NC}" + echo -e "Existing Identity: ${YELLOW}${EXISTING_IDENTITY:-"Create new identity"}${NC}" + + # Confirm deployment + if [[ "$CONFIRM_DEPLOYMENT" != "false" ]]; then + echo "" + echo -e -n "${BLUE}Proceed with deployment? (y/N):${NC} " + read -r confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo -e "${YELLOW}Deployment cancelled.${NC}" + exit 0 + fi + fi +} + +# Default to interactive mode +INTERACTIVE_MODE=true +CONFIG_MODE=false +CONFIG_FILE="" +VERBOSE_OUTPUT=false +CONFIRM_DEPLOYMENT=true + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + -i|--interactive) + INTERACTIVE_MODE=true + CONFIG_MODE=false + shift + ;; + -c|--config) + CONFIG_MODE=true + INTERACTIVE_MODE=false + if [[ -n "$2" && "$2" != -* ]]; then + CONFIG_FILE="$2" + shift 2 + else + CONFIG_FILE="$DEFAULT_CONFIG_FILE" + shift + fi + ;; + --no-interactive) + INTERACTIVE_MODE=false + CONFIG_MODE=false + shift + ;; + --create-config) + if [[ -n "$2" && "$2" != -* ]]; then + create_config_template "$2" + echo -e "${GREEN}Configuration template created at '$2'${NC}" + echo -e "${BLUE}Edit the file and then run: $0 --config $2${NC}" + else + create_config_template "$DEFAULT_CONFIG_FILE" + echo -e "${GREEN}Configuration template created at '$DEFAULT_CONFIG_FILE'${NC}" + echo -e "${BLUE}Edit the file and then run: $0 --config${NC}" + fi + exit 0 + ;; + -s|--subscription-id) + SUBSCRIPTION_ID="$2" + INTERACTIVE_MODE=false + CONFIG_MODE=false + shift 2 + ;; + -r|--resource-group) + RESOURCE_GROUP="$2" + INTERACTIVE_MODE=false + CONFIG_MODE=false + shift 2 + ;; + -n|--agent-name) + AGENT_NAME="$2" + INTERACTIVE_MODE=false + CONFIG_MODE=false + shift 2 + ;; + -l|--location) + LOCATION="$2" + INTERACTIVE_MODE=false + CONFIG_MODE=false + shift 2 + ;; + -a|--access-level) + ACCESS_LEVEL="$2" + INTERACTIVE_MODE=false + CONFIG_MODE=false + shift 2 + ;; + -t|--target-rgs) + TARGET_RGS="$2" + INTERACTIVE_MODE=false + CONFIG_MODE=false + shift 2 + ;; + -u|--target-subs) + TARGET_SUBS="$2" + INTERACTIVE_MODE=false + CONFIG_MODE=false + shift 2 + ;; + -e|--existing-identity) + EXISTING_IDENTITY="$2" + INTERACTIVE_MODE=false + CONFIG_MODE=false + shift 2 + ;; + -y|--yes) + CONFIRM_DEPLOYMENT=false + shift + ;; + -v|--verbose) + VERBOSE_OUTPUT=true + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Unknown option $1" + usage + exit 1 + ;; + esac +done + +# Determine execution mode and load configuration +if [[ "$CONFIG_MODE" == "true" ]]; then + # Config file mode + load_config "$CONFIG_FILE" + + # Evaluate any variables in the config (like date commands) + AGENT_NAME=$(eval echo "$AGENT_NAME") + + echo -e "${GREEN}=== Config File Mode ===${NC}" + echo -e "Using configuration from: ${YELLOW}$CONFIG_FILE${NC}" + echo "" + echo -e "${GREEN}=== Configuration Summary ===${NC}" + echo -e "Subscription ID: ${YELLOW}$SUBSCRIPTION_ID${NC}" + echo -e "Resource Group: ${YELLOW}$RESOURCE_GROUP${NC}" + echo -e "Agent Name: ${YELLOW}$AGENT_NAME${NC}" + echo -e "Location: ${YELLOW}$LOCATION${NC}" + echo -e "Access Level: ${YELLOW}$ACCESS_LEVEL${NC}" + echo -e "Target Resource Groups: ${YELLOW}${TARGET_RGS:-"None"}${NC}" + echo -e "Target Subscriptions: ${YELLOW}${TARGET_SUBS:-"Use deployment subscription"}${NC}" + echo -e "Existing Identity: ${YELLOW}${EXISTING_IDENTITY:-"Create new identity"}${NC}" + + # Confirm deployment if required + if [[ "$CONFIRM_DEPLOYMENT" != "false" ]]; then + echo "" + echo -e -n "${BLUE}Proceed with deployment? (y/N):${NC} " + read -r confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo -e "${YELLOW}Deployment cancelled.${NC}" + exit 0 + fi + fi + +elif [[ "$INTERACTIVE_MODE" == "true" ]]; then + # Interactive mode + interactive_mode + +else + # Command line mode - validate required parameters + if [[ -z "$SUBSCRIPTION_ID" || -z "$RESOURCE_GROUP" || -z "$AGENT_NAME" ]]; then + echo -e "${RED}Error: Missing required parameters for command line mode${NC}" + usage + exit 1 + fi +fi + +# Set defaults for command line mode +LOCATION=${LOCATION:-"eastus2"} +ACCESS_LEVEL=${ACCESS_LEVEL:-"High"} +MODE=${MODE:-"Review"} +EXISTING_IDENTITY=${EXISTING_IDENTITY:-""} + +# Process target resource groups +if [[ -n "$TARGET_RGS" ]]; then + IFS=',' read -ra RG_ARRAY <<< "$TARGET_RGS" + TARGET_RGS_JSON="[" + for i in "${!RG_ARRAY[@]}"; do + if [[ $i -gt 0 ]]; then + TARGET_RGS_JSON+="," + fi + TARGET_RGS_JSON+="\"${RG_ARRAY[$i]}\"" + done + TARGET_RGS_JSON+="]" +else + TARGET_RGS_JSON="[]" +fi + +# Process target subscriptions +if [[ -n "$TARGET_SUBS" ]]; then + IFS=',' read -ra SUB_ARRAY <<< "$TARGET_SUBS" + TARGET_SUBS_JSON="[" + for i in "${!SUB_ARRAY[@]}"; do + if [[ $i -gt 0 ]]; then + TARGET_SUBS_JSON+="," + fi + TARGET_SUBS_JSON+="\"${SUB_ARRAY[$i]}\"" + done + TARGET_SUBS_JSON+="]" +else + TARGET_SUBS_JSON="[]" +fi + +echo "" +echo -e "${GREEN}=== Starting SRE Agent Deployment ===${NC}" +echo -e "Subscription: ${YELLOW}$SUBSCRIPTION_ID${NC}" +echo -e "Resource Group: ${YELLOW}$RESOURCE_GROUP${NC}" +echo -e "Agent Name: ${YELLOW}$AGENT_NAME${NC}" +echo -e "Location: ${YELLOW}$LOCATION${NC}" +echo -e "Access Level: ${YELLOW}$ACCESS_LEVEL${NC}" +echo -e "Target Resource Groups: ${YELLOW}$TARGET_RGS_JSON${NC}" +echo -e "Target Subscriptions: ${YELLOW}$TARGET_SUBS_JSON${NC}" + +# Create resource group if it doesn't exist +echo "" +echo -e "${BLUE}Creating resource group if it doesn't exist...${NC}" +if az group create --name "$RESOURCE_GROUP" --location "$LOCATION" --subscription "$SUBSCRIPTION_ID" &>/dev/null; then + echo -e "${GREEN}✓ Resource group '$RESOURCE_GROUP' ready${NC}" +else + echo -e "${YELLOW}⚠ Resource group may already exist or creation failed${NC}" +fi + +# Deploy the Bicep template +echo "" +echo -e "${BLUE}Deploying SRE Agent...${NC}" +echo -e "${YELLOW}This may take several minutes...${NC}" + +DEPLOYMENT_NAME="sre-agent-deployment-$(date +%Y%m%d%H%M%S)" + +# Set deployment output based on verbose mode +if [[ "$VERBOSE_OUTPUT" == "true" ]]; then + DEPLOYMENT_OUTPUT="json" + QUERY_OUTPUT="--query 'properties.outputs'" +else + DEPLOYMENT_OUTPUT="table" + QUERY_OUTPUT="--query 'properties.outputs' --output table" +fi + +if az deployment sub create \ + --name "$DEPLOYMENT_NAME" \ + --subscription "$SUBSCRIPTION_ID" \ + --location "$LOCATION" \ + --template-file "$TEMPLATE_FILE" \ + --parameters \ + agentName="$AGENT_NAME" \ + subscriptionId="$SUBSCRIPTION_ID" \ + deploymentResourceGroupName="$RESOURCE_GROUP" \ + location="$LOCATION" \ + existingManagedIdentityId="$EXISTING_IDENTITY" \ + accessLevel="$ACCESS_LEVEL" \ + targetResourceGroups="$TARGET_RGS_JSON" \ + targetSubscriptions="$TARGET_SUBS_JSON" \ + $QUERY_OUTPUT; then + + echo "" + echo -e "${GREEN}🎉 SRE Agent deployment completed successfully!${NC}" + echo "" + echo -e "${BLUE}Next steps:${NC}" + echo -e "1. Visit the Azure portal to configure your SRE Agent" + echo -e "2. Set up workflows and monitoring rules" + echo -e "3. Test the agent in Review mode before switching to Autonomous" + echo "" + echo -e "${BLUE}Useful commands:${NC}" + echo -e "• View deployment: ${YELLOW}az deployment sub show --name '$DEPLOYMENT_NAME' --subscription '$SUBSCRIPTION_ID'${NC}" + echo -e "• View agent: ${YELLOW}az resource show --resource-group '$RESOURCE_GROUP' --name '$AGENT_NAME' --resource-type 'Microsoft.App/agents'${NC}" + +else + echo "" + echo -e "${RED}❌ SRE Agent deployment failed!${NC}" + echo "" + echo -e "${BLUE}Troubleshooting steps:${NC}" + echo -e "1. Check if you have the required permissions" + echo -e "2. Verify the subscription ID and resource group name" + echo -e "3. Ensure the SRE Agent resource provider is registered" + echo -e "4. View deployment details: ${YELLOW}az deployment sub show --name '$DEPLOYMENT_NAME' --subscription '$SUBSCRIPTION_ID'${NC}" + exit 1 +fi diff --git a/samples/bicep-deployment/scripts/quick-deploy-no-targets.sh b/samples/bicep-deployment/scripts/quick-deploy-no-targets.sh new file mode 100755 index 0000000..eeb6136 --- /dev/null +++ b/samples/bicep-deployment/scripts/quick-deploy-no-targets.sh @@ -0,0 +1,97 @@ +#!/bin/bash +# Quick Deploy - SRE Agent Without Target Resource Groups +# This script deploys a standalone SRE Agent + +set -e + +# Get script directory and project root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" + +echo "🚀 Quick Deploy: SRE Agent (No Target Resource Groups)" +echo "========================================================" +echo "" + +# Check if Azure CLI is installed and user is logged in +if ! command -v az &> /dev/null; then + echo "❌ Azure CLI is not installed. Please install it first." + exit 1 +fi + +if ! az account show &>/dev/null; then + echo "❌ Not logged in to Azure. Please run 'az login' first." + exit 1 +fi + +# Get current subscription +CURRENT_SUB=$(az account show --query 'id' -o tsv) +CURRENT_SUB_NAME=$(az account show --query 'name' -o tsv) + +echo "✅ Current Subscription: $CURRENT_SUB_NAME" +echo " ID: $CURRENT_SUB" +echo "" + +# Prompt for basic info +read -p "Resource Group Name [rg-sre-agent]: " RG_NAME +RG_NAME=${RG_NAME:-rg-sre-agent} + +read -p "Agent Name [sre-agent-$(date +%Y%m%d)]: " AGENT_NAME +AGENT_NAME=${AGENT_NAME:-sre-agent-$(date +%Y%m%d)} + +read -p "Location [eastus2]: " LOCATION +LOCATION=${LOCATION:-eastus2} + +read -p "Access Level (High/Low) [High]: " ACCESS_LEVEL +ACCESS_LEVEL=${ACCESS_LEVEL:-High} + +echo "" +echo "📋 Deployment Configuration:" +echo " Subscription: $CURRENT_SUB" +echo " Resource Group: $RG_NAME" +echo " Agent Name: $AGENT_NAME" +echo " Location: $LOCATION" +echo " Access Level: $ACCESS_LEVEL" +echo " Target Resource Groups: NONE (standalone deployment)" +echo "" + +read -p "Proceed with deployment? (y/n) " -n 1 -r +echo "" +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "❌ Deployment cancelled." + exit 1 +fi + +echo "" +echo "🔨 Creating resource group..." +az group create --name "$RG_NAME" --location "$LOCATION" --subscription "$CURRENT_SUB" + +echo "" +echo "🚀 Starting deployment..." +DEPLOYMENT_NAME="sre-agent-deployment-$(date +%Y%m%d-%H%M%S)" + +az deployment sub create \ + --name "$DEPLOYMENT_NAME" \ + --location "$LOCATION" \ + --template-file "$PROJECT_ROOT/bicep/minimal-sre-agent.bicep" \ + --parameters \ + agentName="$AGENT_NAME" \ + subscriptionId="$CURRENT_SUB" \ + deploymentResourceGroupName="$RG_NAME" \ + location="$LOCATION" \ + accessLevel="$ACCESS_LEVEL" \ + targetResourceGroups='[]' + +echo "" +echo "✅ Deployment completed successfully!" +echo "" +echo "📊 Deployment Outputs:" +az deployment sub show --name "$DEPLOYMENT_NAME" --query 'properties.outputs' -o table + +echo "" +echo "🎉 Your SRE Agent is ready!" +echo "" +echo "Next steps:" +echo "1. Access the agent portal (see agentPortalUrl above)" +echo "2. Install SRECTL tool: dotnet tool install sreagent.cli --global" +echo "3. Configure sub-agents (see SRECTL-guide-v2.md)" +echo "4. Optional: Add target resource groups later via redeployment" diff --git a/samples/bicep-deployment/scripts/validate.sh b/samples/bicep-deployment/scripts/validate.sh new file mode 100755 index 0000000..a4bcb41 --- /dev/null +++ b/samples/bicep-deployment/scripts/validate.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# Validate Bicep Templates +# This script validates all Bicep templates in the project + +set -e + +# Get script directory and project root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +BICEP_DIR="$PROJECT_ROOT/bicep" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo -e "${BLUE}🔍 Validating Bicep Templates${NC}" +echo "=================================" + +# Check if Bicep CLI is available +if ! command -v az bicep &> /dev/null; then + echo -e "${RED}❌ Bicep CLI not found. Installing...${NC}" + az bicep install +fi + +echo -e "${BLUE}📁 Bicep templates directory: $BICEP_DIR${NC}" +echo "" + +# Validate main template +echo -e "${YELLOW}Validating main template...${NC}" +az bicep build --file "$BICEP_DIR/minimal-sre-agent.bicep" +echo -e "${GREEN}✅ minimal-sre-agent.bicep - Valid${NC}" + +# Validate resource module +echo -e "${YELLOW}Validating resource module...${NC}" +az bicep build --file "$BICEP_DIR/sre-agent-resources.bicep" +echo -e "${GREEN}✅ sre-agent-resources.bicep - Valid${NC}" + +# Validate role assignment modules +echo -e "${YELLOW}Validating role assignment modules...${NC}" +az bicep build --file "$BICEP_DIR/role-assignments-minimal.bicep" +echo -e "${GREEN}✅ role-assignments-minimal.bicep - Valid${NC}" + +az bicep build --file "$BICEP_DIR/role-assignments-target.bicep" +echo -e "${GREEN}✅ role-assignments-target.bicep - Valid${NC}" + +echo "" +echo -e "${GREEN}🎉 All templates validated successfully!${NC}" + +# Optional: Run What-If analysis if parameters provided +if [[ -f "$PROJECT_ROOT/examples/minimal-sre-agent.parameters.json" ]]; then + echo "" + echo -e "${BLUE}💡 To run What-If analysis, use:${NC}" + echo -e "${YELLOW} az deployment sub what-if \\${NC}" + echo -e "${YELLOW} --location eastus2 \\${NC}" + echo -e "${YELLOW} --template-file $BICEP_DIR/minimal-sre-agent.bicep \\${NC}" + echo -e "${YELLOW} --parameters @$PROJECT_ROOT/examples/minimal-sre-agent.parameters.json${NC}" +fi + +echo "" +echo -e "${GREEN}✅ Validation complete!${NC}"