Skip to content

Commit e6731a8

Browse files
committed
--wip-- [skip ci]
1 parent 083417b commit e6731a8

File tree

10 files changed

+129
-51
lines changed

10 files changed

+129
-51
lines changed

.azure/appConfiguration/addReaderRoles.bicep

-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,3 @@ resource roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' =
2020
principalType: 'ServicePrincipal'
2121
}
2222
}]
23-
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
param appInsightsName string
2+
param principalIds array
3+
4+
resource appInsights 'Microsoft.Insights/components@2020-02-02' existing = {
5+
name: appInsightsName
6+
}
7+
8+
@description('This is the built-in Reader role. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#reader')
9+
resource readerRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
10+
scope: subscription()
11+
name: 'acdd72a7-3385-48ef-bd42-f606fba81ae7'
12+
}
13+
14+
resource roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for principalId in principalIds: {
15+
scope: appInsights
16+
name: guid(subscription().id, principalId, readerRole.id)
17+
properties: {
18+
roleDefinitionId: readerRole.id
19+
principalId: principalId
20+
principalType: 'ServicePrincipal'
21+
}
22+
}]

.azure/containerApp/createExternal.bicep

+11-9
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ var initContainers = [
9999
value: migrationJob.name
100100
}
101101
{
102-
name: 'RESOURCE_GROUP_NAME'
103-
value: resourceGroup().name
102+
name: 'RESOURCE_GROUP_NAME'
103+
value: resourceGroup().name
104104
}
105105
])
106106
}]
@@ -129,13 +129,15 @@ var probes = [
129129
var ingress = {
130130
targetPort: port
131131
external: true
132-
ipSecurityRestrictions: [
133-
{
134-
name: 'allow-apim-ip'
135-
action: 'Allow'
136-
ipAddressRange: apiManagementIp
137-
}
138-
]
132+
// #### TEMP
133+
// ipSecurityRestrictions: [
134+
// {
135+
// name: 'allow-apim-ip'
136+
// action: 'Allow'
137+
// ipAddressRange: apiManagementIp
138+
// }
139+
// ]
140+
// #### TEMP
139141
}
140142

141143
var webapiSoName = '${namePrefix}-webapi-so-ca'

.azure/deployBicep.ps1

+3-3
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ AddMemberPath $paramsJson "parameters.environment.value" $environment
5353
# Format parameters to be used in az deployment sub create
5454
$formattedParamsJson = $paramsJson `
5555
| ConvertTo-Json -Compress -Depth 100 `
56-
# | % {$_ -replace "`"", "\`""} `
57-
# | % {$_ -replace "`n", ""} `
58-
# | % {$_ -replace "\s", ""}
56+
| % {$_ -replace "`"", "\`""} `
57+
| % {$_ -replace "`n", ""} `
58+
| % {$_ -replace "\s", ""}
5959

6060
# Deploy
6161
$deploymentOutputs = @( `

.azure/functionApp/appSettings.bicep

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
param webAppName string
2+
param appSettings object
3+
param currentAppSettings object
4+
5+
resource webApp 'Microsoft.Web/sites@2023-01-01' existing = {
6+
name: webAppName
7+
}
8+
9+
resource siteconfig 'Microsoft.Web/sites/config@2023-01-01' = {
10+
parent: webApp
11+
name: 'appsettings'
12+
properties: union(currentAppSettings, appSettings)
13+
}

.azure/functionApp/slackNotifier.bicep

+40-28
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
param location string
22
param applicationInsightsName string
33
param namePrefix string
4+
param keyVaultName string
45

56
// Storage account names only supports lower case and numbers
67
var storageAccountName = '${replace(namePrefix, '-', '')}slacknotifiersa'
@@ -42,38 +43,33 @@ resource functionApp 'Microsoft.Web/sites@2023-01-01' = {
4243
}
4344
properties: {
4445
serverFarmId: applicationServicePlan.id
46+
publicNetworkAccess: 'Enabled'
4547
siteConfig: {
46-
appSettings: [
47-
{
48-
name: 'AzureWebJobsStorage'
49-
value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
50-
}
51-
{
52-
name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
53-
value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
54-
}
55-
{
56-
name: 'WEBSITE_CONTENTSHARE'
57-
value: toLower(functionAppName)
58-
}
59-
{
60-
name: 'FUNCTIONS_EXTENSION_VERSION'
61-
value: '~4'
62-
}
63-
{
64-
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
65-
value: applicationInsights.properties.InstrumentationKey
66-
}
67-
{
68-
name: 'FUNCTIONS_WORKER_RUNTIME'
69-
value: 'dotnet'
70-
}
71-
]
48+
// Setting/updating appSettings in separate module in order no not delete already deployed functions, see below
7249
}
7350
httpsOnly: true
7451
}
7552
}
7653

54+
var appSettings = {
55+
AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
56+
WEBSITE_CONTENTAZUREFILECONNECTIONSTRING: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
57+
WEBSITE_CONTENTSHARE: toLower(functionAppName)
58+
FUNCTIONS_EXTENSION_VERSION: '~4'
59+
APPINSIGHTS_INSTRUMENTATIONKEY: applicationInsights.properties.InstrumentationKey
60+
Slack__WebhookUrl: '@Microsoft.KeyVault(VaultName=${keyVaultName};SecretName=Slack--Webhook--Url)'
61+
FUNCTIONS_WORKER_RUNTIME: 'dotnet-isolated'
62+
}
63+
64+
module updateAppSettings 'appSettings.bicep' = {
65+
name: '${functionAppName}-appsettings'
66+
params: {
67+
webAppName: functionAppName
68+
currentAppSettings: list(resourceId('Microsoft.Web/sites/config', functionAppName, 'appsettings'), '2023-01-01').properties
69+
appSettings: appSettings
70+
}
71+
}
72+
7773
var defaultFunctionKey = listkeys('${functionApp.id}/host/default', '2023-01-01').functionKeys.default
7874

7975
resource notifyDevTeam 'Microsoft.Insights/actionGroups@2023-01-01' = {
@@ -82,12 +78,22 @@ resource notifyDevTeam 'Microsoft.Insights/actionGroups@2023-01-01' = {
8278
properties: {
8379
enabled: true
8480
groupShortName: 'DevNotify'
81+
// TEMP
82+
webhookReceivers: [
83+
{
84+
name: 'WebHukTest'
85+
serviceUri: 'https://webhook.site/16163247-af35-4d0d-a529-18ec3a780229'
86+
useAadAuth: false
87+
useCommonAlertSchema: true
88+
}
89+
]
90+
// TEMP
8591
azureFunctionReceivers: [
8692
{
8793
name: functionApp.properties.defaultHostName
8894
functionName: 'ForwardAlertToSlack'
8995
functionAppResourceId: functionApp.id
90-
httpTriggerUrl: 'https://${functionApp.properties.defaultHostName}/api/ForwardAlertToSlack?code=${defaultFunctionKey}'
96+
httpTriggerUrl: 'https://${functionApp.properties.defaultHostName}/api/forewardalerttoslack?code=${defaultFunctionKey}'
9197
useCommonAlertSchema: true
9298
}
9399
]
@@ -102,10 +108,14 @@ resource exceptionOccuredAlertRule 'Microsoft.Insights/scheduledQueryRules@2023-
102108
evaluationFrequency: 'PT5M'
103109
windowSize: 'PT5M'
104110
scopes: [applicationInsights.id]
111+
autoMitigate: false
112+
targetResourceTypes: [
113+
'microsoft.insights/components'
114+
]
105115
criteria: {
106116
allOf: [
107117
{
108-
query: 'exceptions\n| summarize count = count() by environment = tostring(customDimensions.AspNetCoreEnvironment), problemId\n\n'
118+
query: 'exceptions | summarize count = count() by environment = tostring(customDimensions.AspNetCoreEnvironment), problemId'
109119
operator: 'GreaterThan'
110120
threshold: 0
111121
timeAggregation: 'Count'
@@ -123,3 +133,5 @@ resource exceptionOccuredAlertRule 'Microsoft.Insights/scheduledQueryRules@2023-
123133
}
124134
}
125135
}
136+
137+
output functionAppPrincipalId string = functionApp.identity.principalId

.azure/keyvault/copySecrets.bicep

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ module secrets 'upsertSecret.bicep' = [for key in environmentKeys: if (key.isEnv
3333
secretName: key.value
3434
secretValue: srcKeyVaultResource.getSecret(key.fullName)
3535
}
36-
}]
36+
}]

.azure/main.bicep

+27-4
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ module postgresql 'postgreSql/create.bicep' = {
8686
}
8787
}
8888

89-
module copySecrets 'keyvault/copySecrets.bicep' = {
89+
module copyEnvironmentSecrets 'keyvault/copySecrets.bicep' = {
9090
scope: resourceGroup
91-
name: 'copySecrets'
91+
name: 'copyEnvironmentSecrets'
9292
params: {
9393
srcKeyVaultKeys: keyVault.source.keys
9494
srcKeyVaultName: secrets.sourceKeyVaultName
@@ -99,13 +99,27 @@ module copySecrets 'keyvault/copySecrets.bicep' = {
9999
}
100100
}
101101

102+
module copyCrossEnvironmentSecrets 'keyvault/copySecrets.bicep' = {
103+
scope: resourceGroup
104+
name: 'copyCrossEnvironmentSecrets'
105+
params: {
106+
srcKeyVaultKeys: keyVault.source.keys
107+
srcKeyVaultName: secrets.sourceKeyVaultName
108+
srcKeyVaultRGNName: secrets.sourceKeyVaultResourceGroup
109+
srcKeyVaultSubId: secrets.sourceKeyVaultSubscriptionId
110+
destKeyVaultName: keyVaultModule.outputs.name
111+
secretPrefix: 'dialogporten--any--'
112+
}
113+
}
114+
102115
module slackNotifier 'functionApp/slackNotifier.bicep' = {
103116
name: 'slackNotifier'
104117
scope: resourceGroup
105118
params: {
106119
location: location
107-
applicationInsightsName: appInsights.outputs.appInsightsName
120+
keyVaultName: keyVaultModule.outputs.name
108121
namePrefix: namePrefix
122+
applicationInsightsName: appInsights.outputs.appInsightsName
109123
}
110124
}
111125

@@ -185,6 +199,15 @@ module appConfigReaderAccessPolicy 'appConfiguration/addReaderRoles.bicep' = {
185199
}
186200
}
187201

202+
module appInsightsReaderAccessPolicy 'applicationInsights/addReaderRoles.bicep' = {
203+
scope: resourceGroup
204+
name: 'appInsightsReaderAccessPolicy'
205+
params: {
206+
appInsightsName: appInsights.outputs.appInsightsName
207+
principalIds: [slackNotifier.outputs.functionAppPrincipalId]
208+
}
209+
}
210+
188211
module appConfigConfigurations 'appConfiguration/upsertKeyValue.bicep' = {
189212
scope: resourceGroup
190213
name: 'AppConfig_Add_DialogDbConnectionString'
@@ -201,7 +224,7 @@ module keyVaultReaderAccessPolicy 'keyvault/addReaderRoles.bicep' = {
201224
name: 'keyVaultReaderAccessPolicy'
202225
params: {
203226
keyvaultName: keyVaultModule.outputs.name
204-
principalIds: containerAppsPrincipals
227+
principalIds: concat(containerAppsPrincipals, [slackNotifier.outputs.functionAppPrincipalId])
205228
}
206229
}
207230

src/Digdir.Tool.Dialogporten.SlackNotifier/External/AppInsights/IAppInsightsClient.cs

+9-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ public async Task<AppInsightsQueryResponseDto[]> QueryAppInsights(AzureAlertDto
3434
})
3535
.Select(_httpClient.SendAsync);
3636
var responses = await Task.WhenAll(requests);
37-
var typedResponses = await Task.WhenAll(responses.Select(x => x.Content.ReadFromJsonAsync<AppInsightsQueryResponseDto>()));
37+
38+
foreach (var httpResponseMessage in responses)
39+
{
40+
httpResponseMessage.EnsureSuccessStatusCode();
41+
}
42+
43+
var typedResponses = await Task.WhenAll(responses.Select(x =>
44+
x.Content.ReadFromJsonAsync<AppInsightsQueryResponseDto>(cancellationToken: cancellationToken)));
3845
return typedResponses!;
3946
}
40-
}
47+
}

src/Digdir.Tool.Dialogporten.SlackNotifier/README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ HTTP POST [Slack_Webhook_Url]
2727
3. Start the function app
2828
4. Send a log alert v2 format to the app
2929
30-
The configured url does'nt have to be an actual slack workflow webhook url. It could point to an online webhook tester like https://webhook.site or a homemade webhook tester on your local machine.
30+
The configured url doesn't have to be an actual slack workflow webhook url. It could point to an online webhook tester like https://webhook.site or a homemade webhook tester on your local machine.
3131
3232
### Get a valid log alert v2 request
33-
This function app uses the links in the incoming alerts request to fetch data. Threrfore the requests are app instance and time specific. The provided example request is most likly to be invalid by the time this article is read. Do the following to get a valid request:
33+
This function app uses the links in the incoming alerts request to fetch data. Therefore the requests are app instance and time specific. The provided example request is most likely to be invalid by the time this article is read. Do the following to get a valid request:
3434
1. Go to https://webhook.site and copy your unique url
3535
2. Add the url as a webhook action of the azure action group
3636
3. Trigger the alert
@@ -96,4 +96,4 @@ Example log alert v2 request:
9696
}
9797
}
9898
99-
```
99+
```

0 commit comments

Comments
 (0)