Skip to content

Commit

Permalink
feat: Slack notifier IaC (#341)
Browse files Browse the repository at this point in the history
Adding bicep and workflow for Slack notifier function app deployment

---------

Co-authored-by: Are Almaas <arealmaas@gmail.com>
  • Loading branch information
oskogstad and arealmaas authored Jan 15, 2024
1 parent 77a3538 commit 80c3579
Show file tree
Hide file tree
Showing 16 changed files with 321 additions and 64 deletions.
21 changes: 10 additions & 11 deletions .azure/appConfiguration/addReaderRoles.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@ param appConfigurationName string
param principalIds array

resource appConfig 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = {
name: appConfigurationName
name: appConfigurationName
}

@description('This is the built-in App Configuration Data Reader role. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#app-configuration-data-reader')
resource dataReaderRoleDefinition 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
scope: subscription()
name: '516239f1-63e1-4d78-a4de-a74fb236a071'
scope: subscription()
name: '516239f1-63e1-4d78-a4de-a74fb236a071'
}

resource roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for principalId in principalIds: {
scope: appConfig
name: guid(subscription().id, principalId, dataReaderRoleDefinition.id)
properties: {
roleDefinitionId: dataReaderRoleDefinition.id
principalId: principalId
principalType: 'ServicePrincipal'
}
scope: appConfig
name: guid(subscription().id, principalId, dataReaderRoleDefinition.id)
properties: {
roleDefinitionId: dataReaderRoleDefinition.id
principalId: principalId
principalType: 'ServicePrincipal'
}
}]

22 changes: 22 additions & 0 deletions .azure/applicationInsights/addReaderRoles.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
param appInsightsName string
param principalIds array

resource appInsights 'Microsoft.Insights/components@2020-02-02' existing = {
name: appInsightsName
}

@description('This is the built-in Reader role. See https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#reader')
resource readerRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
scope: subscription()
name: 'acdd72a7-3385-48ef-bd42-f606fba81ae7'
}

resource roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for principalId in principalIds: {
scope: appInsights
name: guid(subscription().id, principalId, readerRole.id)
properties: {
roleDefinitionId: readerRole.id
principalId: principalId
principalType: 'ServicePrincipal'
}
}]
5 changes: 3 additions & 2 deletions .azure/applicationInsights/create.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ param namePrefix string
param location string

resource appInsightsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
name: '${namePrefix}-insightsWorkspace'
location: location
name: '${namePrefix}-insightsWorkspace'
location: location
}

resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
Expand All @@ -18,3 +18,4 @@ resource appInsights 'Microsoft.Insights/components@2020-02-02' = {

output connectionString string = appInsights.properties.ConnectionString
output appInsightsWorkspaceName string = appInsightsWorkspace.name
output appInsightsName string = appInsights.name
4 changes: 2 additions & 2 deletions .azure/containerApp/createExternal.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ var initContainers = [
value: migrationJob.name
}
{
name: 'RESOURCE_GROUP_NAME'
value: resourceGroup().name
name: 'RESOURCE_GROUP_NAME'
value: resourceGroup().name
}
])
}]
Expand Down
13 changes: 13 additions & 0 deletions .azure/functionApp/appSettings.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
param webAppName string
param appSettings object
param currentAppSettings object

resource webApp 'Microsoft.Web/sites@2023-01-01' existing = {
name: webAppName
}

resource siteconfig 'Microsoft.Web/sites/config@2023-01-01' = {
parent: webApp
name: 'appsettings'
properties: union(currentAppSettings, appSettings)
}
127 changes: 127 additions & 0 deletions .azure/functionApp/slackNotifier.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
param location string
param applicationInsightsName string
param namePrefix string
param keyVaultName string

// Storage account names only supports lower case and numbers
var storageAccountName = '${replace(namePrefix, '-', '')}slacknotifiersa'

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'Storage'
properties: {
supportsHttpsTrafficOnly: true
defaultToOAuthAuthentication: true
}
}

resource applicationServicePlan 'Microsoft.Web/serverfarms@2021-03-01' = {
name: '${namePrefix}-slacknotifier-asp'
location: location
sku: {
name: 'Y1'
tier: 'Dynamic'
}
properties: {}
}

resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = {
name: applicationInsightsName
}

var functionAppName = '${namePrefix}-slacknotifier-fa'
resource functionApp 'Microsoft.Web/sites@2023-01-01' = {
name: functionAppName
location: location
kind: 'functionapp'
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: applicationServicePlan.id
publicNetworkAccess: 'Enabled'
siteConfig: {
// Setting/updating appSettings in separate module in order to not delete already deployed functions, see below
}
httpsOnly: true
}
}

var appSettings = {
AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
WEBSITE_CONTENTAZUREFILECONNECTIONSTRING: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
WEBSITE_CONTENTSHARE: toLower(functionAppName)
FUNCTIONS_EXTENSION_VERSION: '~4'
APPINSIGHTS_INSTRUMENTATIONKEY: applicationInsights.properties.InstrumentationKey
Slack__WebhookUrl: '@Microsoft.KeyVault(VaultName=${keyVaultName};SecretName=Slack--Webhook--Url)'
FUNCTIONS_WORKER_RUNTIME: 'dotnet-isolated'
}

module updateAppSettings 'appSettings.bicep' = {
name: '${functionAppName}-appsettings'
params: {
webAppName: functionAppName
currentAppSettings: list(resourceId('Microsoft.Web/sites/config', functionAppName, 'appsettings'), '2023-01-01').properties
appSettings: appSettings
}
}

var defaultFunctionKey = listkeys('${functionApp.id}/host/default', '2023-01-01').functionKeys.default

resource notifyDevTeam 'Microsoft.Insights/actionGroups@2023-01-01' = {
name: '${namePrefix}-notify-devteam-ag'
location: 'Global'
properties: {
enabled: true
groupShortName: 'DevNotify'
azureFunctionReceivers: [
{
name: functionApp.properties.defaultHostName
functionName: 'ForwardAlertToSlack'
functionAppResourceId: functionApp.id
httpTriggerUrl: 'https://${functionApp.properties.defaultHostName}/api/forwardalerttoslack?code=${defaultFunctionKey}'
useCommonAlertSchema: true
}
]
}
}

resource exceptionOccuredAlertRule 'Microsoft.Insights/scheduledQueryRules@2023-03-15-preview' = {
name: '${namePrefix}-exception-occured-sqr'
location: location
properties: {
severity: 1
evaluationFrequency: 'PT5M'
windowSize: 'PT5M'
scopes: [ applicationInsights.id ]
autoMitigate: false
targetResourceTypes: [
'microsoft.insights/components'
]
criteria: {
allOf: [
{
query: 'exceptions | summarize count = count() by environment = tostring(customDimensions.AspNetCoreEnvironment), problemId'
operator: 'GreaterThan'
threshold: 0
timeAggregation: 'Count'
failingPeriods: {
numberOfEvaluationPeriods: 1
minFailingPeriodsToAlert: 1
}
}
]
}
actions: {
actionGroups: [
notifyDevTeam.id
]
}
}
}

output functionAppPrincipalId string = functionApp.identity.principalId
28 changes: 14 additions & 14 deletions .azure/keyvault/addReaderRoles.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ param keyvaultName string
param principalIds array

var readerAccessPoliciesArray = [for principalId in principalIds: {
objectId: principalId
tenantId: subscription().tenantId
permissions: {
certificates: [ 'get', 'list' ]
keys: [ 'get', 'list' ]
secrets: [ 'get', 'list' ]
}
objectId: principalId
tenantId: subscription().tenantId
permissions: {
certificates: [ 'get', 'list' ]
keys: [ 'get', 'list' ]
secrets: [ 'get', 'list' ]
}
}]

resource keyvault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
name: keyvaultName
resource readerAccessPolicies 'accessPolicies' = {
name: 'add'
properties: {
accessPolicies: readerAccessPoliciesArray
}
name: keyvaultName
resource readerAccessPolicies 'accessPolicies' = {
name: 'add'
properties: {
accessPolicies: readerAccessPoliciesArray
}
}
}
}
2 changes: 1 addition & 1 deletion .azure/keyvault/copySecrets.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ module secrets 'upsertSecret.bicep' = [for key in environmentKeys: if (key.isEnv
secretName: key.value
secretValue: srcKeyVaultResource.getSecret(key.fullName)
}
}]
}]
Loading

0 comments on commit 80c3579

Please sign in to comment.