diff --git a/.azure/infrastructure/main.bicep b/.azure/infrastructure/main.bicep index 37c93f97a..2472094bb 100644 --- a/.azure/infrastructure/main.bicep +++ b/.azure/infrastructure/main.bicep @@ -282,6 +282,16 @@ module slackNotifier '../modules/functionApp/slackNotifier.bicep' = { } } +module containerAppIdentity '../modules/managedIdentity/main.bicep' = { + scope: resourceGroup + name: 'containerAppIdentity' + params: { + name: '${namePrefix}-cae-id' + location: location + tags: tags + } +} + module containerAppEnv '../modules/containerAppEnv/main.bicep' = { scope: resourceGroup name: 'containerAppEnv' @@ -289,11 +299,23 @@ module containerAppEnv '../modules/containerAppEnv/main.bicep' = { namePrefix: namePrefix location: location appInsightWorkspaceName: appInsights.outputs.appInsightsWorkspaceName + appInsightsConnectionString: appInsights.outputs.connectionString + monitorMetricsIngestionEndpoint: monitorWorkspace.outputs.containerAppEnvironmentMetricsIngestionEndpoint + userAssignedIdentityId: containerAppIdentity.outputs.managedIdentityId subnetId: vnet.outputs.containerAppEnvironmentSubnetId tags: tags } } +module monitorMetricsPublisherRoles '../modules/monitor-workspace/addMetricsPublisherRoles.bicep' = { + scope: resourceGroup + name: 'monitorMetricsPublisherRoles' + params: { + monitorWorkspaceName: monitorWorkspace.outputs.monitorWorkspaceName + principalIds: [containerAppIdentity.outputs.managedIdentityPrincipalId] + } +} + module appInsightsReaderAccessPolicy '../modules/applicationInsights/addReaderRoles.bicep' = { scope: resourceGroup name: 'appInsightsReaderAccessPolicy' diff --git a/.azure/modules/containerAppEnv/main.bicep b/.azure/modules/containerAppEnv/main.bicep index 2d038de5b..a05e598cb 100644 --- a/.azure/modules/containerAppEnv/main.bicep +++ b/.azure/modules/containerAppEnv/main.bicep @@ -13,13 +13,28 @@ param tags object @description('The name of the Application Insights workspace') param appInsightWorkspaceName string +@description('The Application Insights connection string') +param appInsightsConnectionString string + +@description('The metrics ingestion endpoint of the Azure Monitor workspace') +param monitorMetricsIngestionEndpoint string + +@description('The ID of the user-assigned managed identity') +param userAssignedIdentityId string + resource appInsightsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' existing = { name: appInsightWorkspaceName } -resource containerAppEnv 'Microsoft.App/managedEnvironments@2024-03-01' = { +resource containerAppEnv 'Microsoft.App/managedEnvironments@2024-02-02-preview' = { name: '${namePrefix}-cae' location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${userAssignedIdentityId}': {} + } + } properties: { appLogsConfiguration: { destination: 'log-analytics' @@ -32,6 +47,29 @@ resource containerAppEnv 'Microsoft.App/managedEnvironments@2024-03-01' = { infrastructureSubnetId: subnetId internal: false } + appInsightsConfiguration: { + connectionString: appInsightsConnectionString + } + openTelemetryConfiguration: { + tracesConfiguration: { + destinations: ['appInsights'] + } + logsConfiguration: { + destinations: ['appInsights'] + } + metricsConfiguration: { + destinations: ['metrics-ingestion'] + } + destinationsConfiguration: { + otlpConfigurations: [ + { + endpoint: monitorMetricsIngestionEndpoint + name: 'metrics-ingestion' + insecure: false + } + ] + } + } } tags: tags } diff --git a/.azure/modules/managedIdentity/main.bicep b/.azure/modules/managedIdentity/main.bicep new file mode 100644 index 000000000..a5f9241ca --- /dev/null +++ b/.azure/modules/managedIdentity/main.bicep @@ -0,0 +1,17 @@ +@description('The location where the resources will be deployed') +param location string + +@description('The name of the managed identity') +param name string + +@description('Tags to apply to resources') +param tags object + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: name + location: location + tags: tags +} + +output managedIdentityId string = managedIdentity.id +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/.azure/modules/monitor-workspace/addMetricsPublisherRoles.bicep b/.azure/modules/monitor-workspace/addMetricsPublisherRoles.bicep new file mode 100644 index 000000000..b79418da6 --- /dev/null +++ b/.azure/modules/monitor-workspace/addMetricsPublisherRoles.bicep @@ -0,0 +1,25 @@ +@description('The name of the Monitor workspace') +param monitorWorkspaceName string + +@description('Array of principal IDs to assign the Monitoring Metrics Publisher role to') +param principalIds array + +resource monitorWorkspace 'Microsoft.Monitor/accounts@2023-04-03' existing = { + name: monitorWorkspaceName +} + +@description('This is the built-in Monitoring Metrics Publisher role. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#monitoring-metrics-publisher') +resource monitoringMetricsPublisherRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + scope: subscription() + name: '3913510d-42f4-4e42-8a64-420c390055eb' +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for principalId in principalIds: { + scope: monitorWorkspace + name: guid(monitorWorkspace.id, principalId, monitoringMetricsPublisherRole.id) + properties: { + roleDefinitionId: monitoringMetricsPublisherRole.id + principalId: principalId + principalType: 'ServicePrincipal' + } +}] diff --git a/.azure/modules/monitor-workspace/main.bicep b/.azure/modules/monitor-workspace/main.bicep index bb763a54e..b24e57d06 100644 --- a/.azure/modules/monitor-workspace/main.bicep +++ b/.azure/modules/monitor-workspace/main.bicep @@ -17,5 +17,57 @@ resource monitorWorkspace 'Microsoft.Monitor/accounts@2023-04-03' = { tags: tags } +resource containerAppEnvironmentDataCollectionEndpoint 'Microsoft.Insights/dataCollectionEndpoints@2023-03-11' = { + name: '${namePrefix}-cae-dce' + location: location + properties: { + description: 'DCE for Container App Environment' + networkAcls: { + publicNetworkAccess: 'Enabled' + } + } + tags: tags +} + +resource containerAppEnvironmentDataCollectionRule 'Microsoft.Insights/dataCollectionRules@2023-03-11' = { + name: '${namePrefix}-cae-dcr' + location: location + properties: { + description: 'DCR for Container App Environment' + dataCollectionEndpointId: containerAppEnvironmentDataCollectionEndpoint.id + dataSources: { + prometheusForwarder: [ + { + streams: [ + 'Microsoft-PrometheusMetrics' + ] + name: 'PrometheusDataSource' + } + ] + } + destinations: { + monitoringAccounts: [ + { + accountResourceId: monitorWorkspace.id + name: 'MonitoringAccountDestination' + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-PrometheusMetrics' + ] + destinations: [ + 'MonitoringAccountDestination' + ] + } + ] + } + tags: tags +} + output monitorWorkspaceId string = monitorWorkspace.id output monitorWorkspaceName string = monitorWorkspace.name +output containerAppEnvironmentMetricsIngestionEndpoint string = containerAppEnvironmentDataCollectionEndpoint.properties.metricsIngestion.endpoint +output containerAppEnvironmentLogsIngestionEndpoint string = containerAppEnvironmentDataCollectionEndpoint.properties.logsIngestion.endpoint