add openhack files

This commit is contained in:
Ryan Peters
2022-11-03 16:41:13 -04:00
commit b2c9f7e29f
920 changed files with 118861 additions and 0 deletions

View File

@ -0,0 +1,26 @@
param resourcesPrefix string
var location = resourceGroup().location
// https://docs.microsoft.com/en-us/azure/templates/microsoft.insights/components?tabs=bicep
resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
name: '${resourcesPrefix}appi'
location: location
kind: 'web'
properties: {
Application_Type: 'web'
}
}
resource appInsightsStaging 'Microsoft.Insights/components@2020-02-02' = {
name: '${resourcesPrefix}appistaging'
location: location
kind: 'web'
properties: {
Application_Type: 'web'
}
}
output appInsightsInstrumentationKey string = appInsights.properties.InstrumentationKey
output appInsightsConnectionString string = appInsights.properties.ConnectionString
output appInsightsStagingInstrumentationKey string = appInsightsStaging.properties.InstrumentationKey
output appInsightsStagingConnectionString string = appInsightsStaging.properties.ConnectionString

View File

@ -0,0 +1,35 @@
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string[]] $HostNames
)
$TestCases = @()
$HostNames.ForEach{ $TestCases += @{HostName = $_ } }
Describe 'Testing connection to Websites' {
It ' <HostName> over HTTPS' -ForEach $TestCases {
try {
$request = [System.Net.WebRequest]::Create("https://$HostName")
$request.AllowAutoRedirect = $false
$statusCode = [int]$request.GetResponse().StatusCode
}
catch [System.Net.WebException] {
$statusCode = [int]$_.Exception.Response.StatusCode
}
$statusCode | Should -BeIn @(200, 404) -Because "the website requires HTTPS"
}
It ' <HostName> over HTTP' -ForEach $TestCases {
try {
$request = [System.Net.WebRequest]::Create("http://$HostName")
$request.AllowAutoRedirect = $false
$statusCode = [int]$request.GetResponse().StatusCode
}
catch [System.Net.WebException] {
$statusCode = [int]$_.Exception.Response.StatusCode
}
$statusCode | Should -BeIn (300..399) -Because "HTTP is not secure"
}
}

774
iac/bicep/appService.bicep Normal file
View File

@ -0,0 +1,774 @@
param resourcesPrefix string
param sqlServerAdminLogin string
@secure()
param sqlServerAdminPassword string
param sqlServerFqdn string
param sqlDatabaseName string
param containerRegistryLoginServer string
param containerRegistryName string
param containerRegistryAdminUsername string
param containerRegistryAdminPassword string
param keyVaultName string // for Key Vault integration
param appInsightsInstrumentationKey string
param appInsightsConnectionString string
param appInsightsStagingInstrumentationKey string
param appInsightsStagingConnectionString string
param apiPoiBaseImageTag string
param apiTripsBaseImageTag string
param apiUserJavaBaseImageTag string
param apiUserprofileBaseImageTag string
var location = resourceGroup().location
var varfile = json(loadTextContent('./variables.json'))
// https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles
// AcrPull
var acrPullRoleDefinitionId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2021-09-01' existing = {
name: containerRegistryName
}
// Prepared for Key Vault integration
resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = {
name: keyVaultName
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/serverfarms?tabs=bicep
resource appServicePlan 'Microsoft.Web/serverfarms@2021-02-01' = {
name: '${resourcesPrefix}plan'
kind: 'linux'
location: location
properties: {
reserved: true
}
sku: {
name: 'S1'
tier: 'Standard'
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites?tabs=bicep
resource appServiceTripviewer 'Microsoft.Web/sites@2021-02-01' = {
name: '${resourcesPrefix}tripviewer'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
acrUseManagedIdentityCreds: true
linuxFxVersion: 'DOCKER|${containerRegistryLoginServer}/devopsoh/tripviewer:latest'
appSettings: [
{
name: 'BING_MAPS_KEY'
value: varfile.bingMapsKey
}
{
name: 'USER_ROOT_URL'
value: 'https://${appServiceApiUserprofile.properties.defaultHostName}'
}
{
name: 'USER_JAVA_ROOT_URL'
value: 'https://${appServiceApiUserJava.properties.defaultHostName}'
}
{
name: 'TRIPS_ROOT_URL'
value: 'https://${appServiceApiTrips.properties.defaultHostName}'
}
{
name: 'POI_ROOT_URL'
value: 'https://${appServiceApiPoi.properties.defaultHostName}'
}
{
name: 'STAGING_USER_ROOT_URL'
value: 'https://${appServiceApiUserprofileStaging.properties.defaultHostName}'
}
{
name: 'STAGING_USER_JAVA_ROOT_URL'
value: 'https://${appServiceApiUserJavaStaging.properties.defaultHostName}'
}
{
name: 'STAGING_TRIPS_ROOT_URL'
value: 'https://${appServiceApiTripsStaging.properties.defaultHostName}'
}
{
name: 'STAGING_POI_ROOT_URL'
value: 'https://${appServiceApiPoiStaging.properties.defaultHostName}'
}
{
name: 'DOCKER_REGISTRY_SERVER_URL'
value: 'https://${containerRegistryLoginServer}'
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsightsInstrumentationKey
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: appInsightsConnectionString
}
]
alwaysOn: true
}
httpsOnly: true
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-logs?tabs=bicep
resource appServiceTripviewerExtension 'Microsoft.Web/sites/config@2021-02-01' = {
parent: appServiceTripviewer
name: 'logs'
properties: {
httpLogs: {
fileSystem: {
retentionInMb: 50
retentionInDays: 7
enabled: true
}
}
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep
resource acrPullRoleAssignmentTripviewer 'Microsoft.Authorization/roleAssignments@2020-08-01-preview' = {
name: guid(resourceGroup().id, containerRegistry.id, 'tripviewer', acrPullRoleDefinitionId)
scope: containerRegistry
properties: {
roleDefinitionId: acrPullRoleDefinitionId
principalId: appServiceTripviewer.identity.principalId
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites?tabs=bicep
resource appServiceApiPoi 'Microsoft.Web/sites@2021-02-01' = {
name: '${resourcesPrefix}poi'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
linuxFxVersion: 'DOCKER|${containerRegistryLoginServer}/devopsoh/api-poi:${apiPoiBaseImageTag}'
healthCheckPath: '/api/healthcheck/poi'
appSettings: [
{
name: 'SQL_USER'
value: sqlServerAdminLogin
}
{
name: 'SQL_PASSWORD'
value: sqlServerAdminPassword
//value: '@Microsoft.KeyVault(VaultName=${keyVault.name};SecretName=SQL-PASSWORD)' // for Key Vault integration
}
{
name: 'SQL_SERVER'
value: sqlServerFqdn
}
{
name: 'SQL_DBNAME'
value: sqlDatabaseName
}
{
name: 'WEBSITES_PORT'
value: '8080'
}
{
name: 'DOCKER_REGISTRY_SERVER_URL'
value: 'https://${containerRegistryLoginServer}'
}
{
name: 'DOCKER_REGISTRY_SERVER_USERNAME'
value: containerRegistryAdminUsername
}
{
name: 'DOCKER_REGISTRY_SERVER_PASSWORD'
value: containerRegistryAdminPassword
//value: '@Microsoft.KeyVault(VaultName=${keyVault.name};SecretName=DOCKER-REGISTRY-SERVER-PASSWORD)' // for Key Vault integration
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsightsInstrumentationKey
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: appInsightsConnectionString
}
]
alwaysOn: true
}
httpsOnly: true
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-logs?tabs=bicep
resource appServiceApiPoiExtension 'Microsoft.Web/sites/config@2021-02-01' = {
parent: appServiceApiPoi
name: 'logs'
properties: {
httpLogs: {
fileSystem: {
retentionInMb: 50
retentionInDays: 7
enabled: true
}
}
}
}
// Prepared for Key Vault integration
// resource keyVaultAccessPolicyApiPoi 'Microsoft.KeyVault/vaults/accessPolicies@2021-06-01-preview' = {
// name: 'add'
// parent: keyVault
// properties: {
// accessPolicies: [
// {
// tenantId: appServiceApiPoi.identity.tenantId
// objectId: appServiceApiPoi.identity.principalId
// permissions: {
// secrets: [
// 'get'
// 'list'
// 'set'
// ]
// }
// }
// ]
// }
// }
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/slots?tabs=bicep
resource appServiceApiPoiStaging 'Microsoft.Web/sites/slots@2021-02-01' = {
parent: appServiceApiPoi
name: 'staging'
identity: {
type: 'SystemAssigned'
}
location: location
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
linuxFxVersion: 'DOCKER|${containerRegistryLoginServer}/devopsoh/api-poi:${apiPoiBaseImageTag}'
healthCheckPath: '/api/healthcheck/poi'
appSettings: [
{
name: 'SQL_USER'
value: sqlServerAdminLogin
}
{
name: 'SQL_PASSWORD'
value: sqlServerAdminPassword
//value: '@Microsoft.KeyVault(VaultName=${keyVault.name};SecretName=SQL-PASSWORD)' // for Key Vault integration
}
{
name: 'SQL_SERVER'
value: sqlServerFqdn
}
{
name: 'SQL_DBNAME'
value: sqlDatabaseName
}
{
name: 'WEBSITES_PORT'
value: '8080'
}
{
name: 'DOCKER_REGISTRY_SERVER_URL'
value: 'https://${containerRegistryLoginServer}'
}
{
name: 'DOCKER_REGISTRY_SERVER_USERNAME'
value: containerRegistryAdminUsername
}
{
name: 'DOCKER_REGISTRY_SERVER_PASSWORD'
value: containerRegistryAdminPassword
//value: '@Microsoft.KeyVault(VaultName=${keyVault.name};SecretName=DOCKER-REGISTRY-SERVER-PASSWORD)' // for Key Vault integration
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsightsStagingInstrumentationKey
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: appInsightsStagingConnectionString
}
]
alwaysOn: true
}
httpsOnly: true
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-logs?tabs=bicep
resource appServiceApiPoiStagingExtension 'Microsoft.Web/sites/slots/config@2021-02-01' = {
parent: appServiceApiPoiStaging
name: 'logs'
properties: {
httpLogs: {
fileSystem: {
retentionInMb: 50
retentionInDays: 7
enabled: true
}
}
}
}
// Prepared for Key Vault integration
// resource keyVaultAccessPolicyApiPoiStaging 'Microsoft.KeyVault/vaults/accessPolicies@2021-06-01-preview' = {
// name: 'add'
// parent: keyVault
// properties: {
// accessPolicies: [
// {
// tenantId: appServiceApiPoiStaging.identity.tenantId
// objectId: appServiceApiPoiStaging.identity.principalId
// permissions: {
// secrets: [
// 'get'
// 'list'
// 'set'
// ]
// }
// }
// ]
// }
// }
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites?tabs=bicep
resource appServiceApiTrips 'Microsoft.Web/sites@2021-02-01' = {
name: '${resourcesPrefix}trips'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
linuxFxVersion: 'DOCKER|${containerRegistryLoginServer}/devopsoh/api-trips:${apiTripsBaseImageTag}'
healthCheckPath: '/api/healthcheck/trips'
appSettings: [
{
name: 'SQL_USER'
value: sqlServerAdminLogin
}
{
name: 'SQL_PASSWORD'
value: sqlServerAdminPassword
}
{
name: 'SQL_SERVER'
value: sqlServerFqdn
}
{
name: 'SQL_DBNAME'
value: sqlDatabaseName
}
{
name: 'DOCKER_REGISTRY_SERVER_URL'
value: 'https://${containerRegistryLoginServer}'
}
{
name: 'DOCKER_REGISTRY_SERVER_USERNAME'
value: containerRegistryAdminUsername
}
{
name: 'DOCKER_REGISTRY_SERVER_PASSWORD'
value: containerRegistryAdminPassword
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsightsInstrumentationKey
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: appInsightsConnectionString
}
]
alwaysOn: true
}
httpsOnly: true
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-logs?tabs=bicep
resource appServiceApiTripsExtension 'Microsoft.Web/sites/config@2021-02-01' = {
parent: appServiceApiTrips
name: 'logs'
properties: {
httpLogs: {
fileSystem: {
retentionInMb: 50
retentionInDays: 7
enabled: true
}
}
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/slots?tabs=bicep
resource appServiceApiTripsStaging 'Microsoft.Web/sites/slots@2021-02-01' = {
parent: appServiceApiTrips
name: 'staging'
identity: {
type: 'SystemAssigned'
}
location: location
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
linuxFxVersion: 'DOCKER|${containerRegistryLoginServer}/devopsoh/api-trips:${apiTripsBaseImageTag}'
healthCheckPath: '/api/healthcheck/trips'
appSettings: [
{
name: 'SQL_USER'
value: sqlServerAdminLogin
}
{
name: 'SQL_PASSWORD'
value: sqlServerAdminPassword
}
{
name: 'SQL_SERVER'
value: sqlServerFqdn
}
{
name: 'SQL_DBNAME'
value: sqlDatabaseName
}
{
name: 'DOCKER_REGISTRY_SERVER_URL'
value: 'https://${containerRegistryLoginServer}'
}
{
name: 'DOCKER_REGISTRY_SERVER_USERNAME'
value: containerRegistryAdminUsername
}
{
name: 'DOCKER_REGISTRY_SERVER_PASSWORD'
value: containerRegistryAdminPassword
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsightsStagingInstrumentationKey
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: appInsightsStagingConnectionString
}
]
alwaysOn: true
}
httpsOnly: true
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-logs?tabs=bicep
resource appServiceApiTripsStagingExtension 'Microsoft.Web/sites/slots/config@2021-02-01' = {
parent: appServiceApiTripsStaging
name: 'logs'
properties: {
httpLogs: {
fileSystem: {
retentionInMb: 50
retentionInDays: 7
enabled: true
}
}
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites?tabs=bicep
resource appServiceApiUserJava 'Microsoft.Web/sites@2021-02-01' = {
name: '${resourcesPrefix}userjava'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
linuxFxVersion: 'DOCKER|${containerRegistryLoginServer}/devopsoh/api-user-java:${apiUserJavaBaseImageTag}'
healthCheckPath: '/api/healthcheck/user-java'
appSettings: [
{
name: 'SQL_USER'
value: sqlServerAdminLogin
}
{
name: 'SQL_PASSWORD'
value: sqlServerAdminPassword
}
{
name: 'SQL_SERVER'
value: sqlServerFqdn
}
{
name: 'SQL_DBNAME'
value: sqlDatabaseName
}
{
name: 'DOCKER_REGISTRY_SERVER_URL'
value: 'https://${containerRegistryLoginServer}'
}
{
name: 'DOCKER_REGISTRY_SERVER_USERNAME'
value: containerRegistryAdminUsername
}
{
name: 'DOCKER_REGISTRY_SERVER_PASSWORD'
value: containerRegistryAdminPassword
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsightsInstrumentationKey
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: appInsightsConnectionString
}
]
alwaysOn: true
}
httpsOnly: true
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-logs?tabs=bicep
resource appServiceApiUserJavaExtension 'Microsoft.Web/sites/config@2021-02-01' = {
parent: appServiceApiUserJava
name: 'logs'
properties: {
httpLogs: {
fileSystem: {
retentionInMb: 50
retentionInDays: 7
enabled: true
}
}
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/slots?tabs=bicep
resource appServiceApiUserJavaStaging 'Microsoft.Web/sites/slots@2021-02-01' = {
parent: appServiceApiUserJava
name: 'staging'
identity: {
type: 'SystemAssigned'
}
location: location
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
linuxFxVersion: 'DOCKER|${containerRegistryLoginServer}/devopsoh/api-user-java:${apiUserJavaBaseImageTag}'
healthCheckPath: '/api/healthcheck/user-java'
appSettings: [
{
name: 'SQL_USER'
value: sqlServerAdminLogin
}
{
name: 'SQL_PASSWORD'
value: sqlServerAdminPassword
}
{
name: 'SQL_SERVER'
value: sqlServerFqdn
}
{
name: 'SQL_DBNAME'
value: sqlDatabaseName
}
{
name: 'DOCKER_REGISTRY_SERVER_URL'
value: 'https://${containerRegistryLoginServer}'
}
{
name: 'DOCKER_REGISTRY_SERVER_USERNAME'
value: containerRegistryAdminUsername
}
{
name: 'DOCKER_REGISTRY_SERVER_PASSWORD'
value: containerRegistryAdminPassword
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsightsStagingInstrumentationKey
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: appInsightsStagingConnectionString
}
]
alwaysOn: true
}
httpsOnly: true
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-logs?tabs=bicep
resource appServiceApiUserJavaStagingExtension 'Microsoft.Web/sites/slots/config@2021-02-01' = {
parent: appServiceApiUserJavaStaging
name: 'logs'
properties: {
httpLogs: {
fileSystem: {
retentionInMb: 50
retentionInDays: 7
enabled: true
}
}
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites?tabs=bicep
resource appServiceApiUserprofile 'Microsoft.Web/sites@2021-02-01' = {
name: '${resourcesPrefix}userprofile'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
linuxFxVersion: 'DOCKER|${containerRegistryLoginServer}/devopsoh/api-userprofile:${apiUserprofileBaseImageTag}'
healthCheckPath: '/api/healthcheck/user'
appSettings: [
{
name: 'SQL_USER'
value: sqlServerAdminLogin
}
{
name: 'SQL_PASSWORD'
value: sqlServerAdminPassword
}
{
name: 'SQL_SERVER'
value: sqlServerFqdn
}
{
name: 'SQL_DBNAME'
value: sqlDatabaseName
}
{
name: 'DOCKER_REGISTRY_SERVER_URL'
value: 'https://${containerRegistryLoginServer}'
}
{
name: 'DOCKER_REGISTRY_SERVER_USERNAME'
value: containerRegistryAdminUsername
}
{
name: 'DOCKER_REGISTRY_SERVER_PASSWORD'
value: containerRegistryAdminPassword
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsightsInstrumentationKey
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: appInsightsConnectionString
}
]
alwaysOn: true
}
httpsOnly: true
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-logs?tabs=bicep
resource appServiceApiUserprofileExtension 'Microsoft.Web/sites/config@2021-02-01' = {
parent: appServiceApiUserprofile
name: 'logs'
properties: {
httpLogs: {
fileSystem: {
retentionInMb: 50
retentionInDays: 7
enabled: true
}
}
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/slots?tabs=bicep
resource appServiceApiUserprofileStaging 'Microsoft.Web/sites/slots@2021-02-01' = {
parent: appServiceApiUserprofile
name: 'staging'
identity: {
type: 'SystemAssigned'
}
location: location
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
linuxFxVersion: 'DOCKER|${containerRegistryLoginServer}/devopsoh/api-userprofile:${apiUserprofileBaseImageTag}'
healthCheckPath: '/api/healthcheck/user'
appSettings: [
{
name: 'SQL_USER'
value: sqlServerAdminLogin
}
{
name: 'SQL_PASSWORD'
value: sqlServerAdminPassword
}
{
name: 'SQL_SERVER'
value: sqlServerFqdn
}
{
name: 'SQL_DBNAME'
value: sqlDatabaseName
}
{
name: 'DOCKER_REGISTRY_SERVER_URL'
value: 'https://${containerRegistryLoginServer}'
}
{
name: 'DOCKER_REGISTRY_SERVER_USERNAME'
value: containerRegistryAdminUsername
}
{
name: 'DOCKER_REGISTRY_SERVER_PASSWORD'
value: containerRegistryAdminPassword
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: appInsightsStagingInstrumentationKey
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: appInsightsStagingConnectionString
}
]
alwaysOn: true
}
httpsOnly: true
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.web/sites/config-logs?tabs=bicep
resource appServiceApiUserprofileStagingExtension 'Microsoft.Web/sites/slots/config@2021-02-01' = {
parent: appServiceApiUserprofileStaging
name: 'logs'
properties: {
httpLogs: {
fileSystem: {
retentionInMb: 50
retentionInDays: 7
enabled: true
}
}
}
}
output appServiceApiPoiHostname string = appServiceApiPoi.properties.defaultHostName
output appServiceApiTripsHostname string = appServiceApiTrips.properties.defaultHostName
output appServiceApiUserJavaHostname string = appServiceApiUserJava.properties.defaultHostName
output appServiceApiUserprofileHostname string = appServiceApiUserprofile.properties.defaultHostName

147
iac/bicep/apps.bicep Normal file
View File

@ -0,0 +1,147 @@
param resourcesPrefix string
param sqlServerFqdn string
param sqlServerName string
param sqlServerAdminPassword string
param containerRegistryLoginServer string
param containerRegistryName string
param userAssignedManagedIdentityId string
param userAssignedManagedIdentityPrincipalId string
var location = resourceGroup().location
var varfile = json(loadTextContent('./variables.json'))
// https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles
// Contributor
var contributorRoleDefinitionId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
resource sqlServer 'Microsoft.Sql/servers@2021-02-01-preview' existing = {
name: sqlServerName
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep
resource sqlContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2020-08-01-preview' = {
name: guid(resourceGroup().id, sqlServer.id, userAssignedManagedIdentityId, contributorRoleDefinitionId)
scope: sqlServer
properties: {
roleDefinitionId: contributorRoleDefinitionId
principalId: userAssignedManagedIdentityPrincipalId
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.resources/deploymentscripts?tabs=bicep
resource dataInit 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
name: '${resourcesPrefix}dataInit'
location: location
kind: 'AzureCLI'
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${userAssignedManagedIdentityId}': {}
}
}
properties: {
azCliVersion: '2.33.1'
cleanupPreference: 'Always'
containerSettings: {
containerGroupName: '${resourcesPrefix}datainit'
}
scriptContent: loadTextContent('datainit.sh')
environmentVariables: [
{
name: 'SQL_SERVER_NAME'
value: sqlServerName
}
{
name: 'SQL_SERVER_FQDN'
value: sqlServerFqdn
}
{
name: 'SQL_ADMIN_LOGIN'
value: varfile.sqlServerAdminLogin
}
{
name: 'SQL_ADMIN_PASSWORD'
secureValue: sqlServerAdminPassword
}
{
name: 'SQL_DB_NAME'
value: 'mydrivingDB'
}
{
name: 'RESOURCE_GROUP'
value: resourceGroup().name
}
{
name: 'TEAM_REPO'
value: varfile.publicTeamRepo
}
{
name: 'TEAM_REPO_BRANCH'
value: varfile.publicTeamRepoBranch
}
]
retentionInterval: 'PT1H'
timeout: 'PT15M'
}
dependsOn: [
sqlContributorRoleAssignment
]
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.containerregistry/registries?tabs=bicep
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2021-09-01' existing = {
name: containerRegistryName
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep
resource acrContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2020-08-01-preview' = {
name: guid(resourceGroup().id, containerRegistry.id, userAssignedManagedIdentityId, contributorRoleDefinitionId)
scope: containerRegistry
properties: {
roleDefinitionId: contributorRoleDefinitionId
principalId: userAssignedManagedIdentityPrincipalId
}
}
//https://docs.microsoft.com/en-us/azure/templates/microsoft.resources/deploymentscripts?tabs=bicep
resource dockerBuild 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
name: '${resourcesPrefix}dockerBuild'
location: location
kind: 'AzureCLI'
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${userAssignedManagedIdentityId}': {}
}
}
properties: {
azCliVersion: '2.33.1'
cleanupPreference: 'Always'
containerSettings: {
containerGroupName: '${resourcesPrefix}dockerdbuild'
}
scriptContent: loadTextContent('dockerbuild.sh')
environmentVariables: [
{
name: 'CONTAINER_REGISTRY'
value: containerRegistryLoginServer
}
{
name: 'BASE_IMAGE_TAG'
value: varfile.baseImageTag
}
{
name: 'TEAM_REPO'
value: varfile.publicTeamRepo
}
{
name: 'TEAM_REPO_BRANCH'
value: varfile.publicTeamRepoBranch
}
]
retentionInterval: 'P1D'
}
dependsOn: [
acrContributorRoleAssignment
]
}

View File

@ -0,0 +1,28 @@
{
"analyzers": {
"core": {
"enabled": true,
"verbose": true,
"rules": {
"no-hardcoded-env-urls": {
"level": "error"
},
"no-unused-params": {
"level": "error"
},
"no-unused-vars": {
"level": "error"
},
"prefer-interpolation": {
"level": "error"
},
"secure-parameter-default": {
"level": "error"
},
"simplify-interpolation": {
"level": "error"
}
}
}
}
}

View File

@ -0,0 +1,138 @@
param resourcesPrefix string
param sqlServerAdminLogin string
@secure()
param sqlServerAdminPassword string
param sqlServerFqdn string
param sqlDatabaseName string
param containerRegistryLoginServer string
param containerRegistryAdminUsername string
@secure()
param containerRegistryAdminPassword string
param appServiceApiPoiHostname string
param appServiceApiTripsHostname string
param appServiceApiUserJavaHostname string
param appServiceApiUserprofileHostname string
param logAnalyticsWorkspaceId string
@secure()
param logAnalyticsWorkspaceKey string
// param containerRegistryName string
// param userAssignedManagedIdentityId string
// param userAssignedManagedIdentityPrincipalId string
// https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles
// AcrPull
// var acrPullRoleDefinitionId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')
// resource containerRegistry 'Microsoft.ContainerRegistry/registries@2021-09-01' existing = {
// name: containerRegistryName
// }
// https://docs.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?tabs=bicep
// resource acrPullRoleAssignmentSimulator 'Microsoft.Authorization/roleAssignments@2020-08-01-preview' = {
// name: guid(resourceGroup().id, containerRegistry.id, 'simulator', acrPullRoleDefinitionId)
// scope: containerRegistry
// properties: {
// roleDefinitionId: acrPullRoleDefinitionId
// principalId: userAssignedManagedIdentityPrincipalId
// }
// }
// https://docs.microsoft.com/en-us/azure/templates/microsoft.containerinstance/containergroups?tabs=bicep
resource containerGroup 'Microsoft.ContainerInstance/containerGroups@2021-09-01' = {
name: '${resourcesPrefix}simulator'
location: resourceGroup().location
// identity: {
// type: 'UserAssigned'
// userAssignedIdentities: {
// '${userAssignedManagedIdentityId}': {}
// }
// }
properties: {
containers: [
{
name: 'simulator'
properties: {
environmentVariables: [
{
name: 'SQL_SERVER'
value: sqlServerFqdn
}
{
name: 'SQL_USER'
value: sqlServerAdminLogin
}
{
name: 'SQL_PASSWORD'
secureValue: sqlServerAdminPassword
}
{
name: 'SQL_DBNAME'
value: sqlDatabaseName
}
{
name: 'TEAM_NAME'
value: resourcesPrefix
}
{
name: 'USER_ROOT_URL'
value: 'https://${appServiceApiUserprofileHostname}'
}
{
name: 'USER_JAVA_ROOT_URL'
value: 'https://${appServiceApiUserJavaHostname}'
}
{
name: 'TRIPS_ROOT_URL'
value: 'https://${appServiceApiTripsHostname}'
}
{
name: 'POI_ROOT_URL'
value: 'https://${appServiceApiPoiHostname}'
}
]
image: '${containerRegistryLoginServer}/devopsoh/simulator:latest'
ports: [
{
port: 8080
protocol: 'TCP'
}
]
resources: {
requests: {
cpu: 1
memoryInGB: 2
}
}
}
}
]
imageRegistryCredentials: [
{
password: containerRegistryAdminPassword
server: containerRegistryLoginServer
username: containerRegistryAdminUsername
}
]
ipAddress: {
dnsNameLabel: '${resourcesPrefix}simulator'
ports: [
{
port: 8080
protocol: 'TCP'
}
]
type: 'Public'
}
osType: 'Linux'
diagnostics: {
logAnalytics: {
logType: 'ContainerInsights'
workspaceId: logAnalyticsWorkspaceId
workspaceKey: logAnalyticsWorkspaceKey
}
}
}
// dependsOn: [
// acrPullRoleAssignmentSimulator
// ]
}

View File

@ -0,0 +1,20 @@
param resourcesPrefix string
var location = resourceGroup().location
// https://docs.microsoft.com/en-us/azure/templates/microsoft.containerregistry/registries?tabs=bicep
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2021-09-01' = {
name: '${resourcesPrefix}cr'
location: location
sku: {
name: 'Standard'
}
properties: {
adminUserEnabled: true
}
}
output containerRegistryLoginServer string = containerRegistry.properties.loginServer
output containerRegistryAdminUsername string = containerRegistry.listCredentials().username
output containerRegistryAdminPassword string = containerRegistry.listCredentials().passwords[0].value
output containerRegistryName string = containerRegistry.name

34
iac/bicep/datainit.sh Normal file
View File

@ -0,0 +1,34 @@
#!/bin/bash
cd ~/
export ACCEPT_EULA="Y"
MSSQL_VERSION="17.8.1.1-1"
curl -O "https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/msodbcsql17_${MSSQL_VERSION}_amd64.apk"
curl -O "https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/mssql-tools_${MSSQL_VERSION}_amd64.apk"
apk add --allow-untrusted msodbcsql17_${MSSQL_VERSION}_amd64.apk
apk add --allow-untrusted mssql-tools_${MSSQL_VERSION}_amd64.apk
apk update && apk add bind-tools
export PATH="$PATH:/opt/mssql-tools/bin"
echo "MSSQL_VERSION: ${MSSQL_VERSION}" 2>&1 | tee "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/vars.txt"
echo "RESOURCE_GROUP: ${RESOURCE_GROUP}" 2>&1 | tee -a "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/vars.txt"
echo "TEAM_REPO: ${TEAM_REPO}" 2>&1 | tee -a "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/vars.txt"
echo "TEAM_REPO_BRANCH: ${TEAM_REPO_BRANCH}" 2>&1 | tee -a "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/vars.txt"
echo "SQL_SERVER_NAME: ${SQL_SERVER_NAME}" 2>&1 | tee -a "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/vars.txt"
echo "SQL_ADMIN_LOGIN: ${SQL_ADMIN_LOGIN}" 2>&1 | tee -a "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/vars.txt"
echo "SQL_SERVER_FQDN: ${SQL_SERVER_FQDN}" 2>&1 | tee -a "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/vars.txt"
echo "SQL_DB_NAME: ${SQL_DB_NAME}" 2>&1 | tee -a "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/vars.txt"
MYIP="$(dig +short myip.opendns.com @resolver1.opendns.com -4)"
az sql server firewall-rule create --resource-group ${RESOURCE_GROUP} --server ${SQL_SERVER_NAME} --name dataInit --start-ip-address ${MYIP} --end-ip-address ${MYIP} 2>&1 | tee "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/sqlFwCreate.txt"
git clone "${TEAM_REPO}" --branch "${TEAM_REPO_BRANCH}" ~/openhack
cd ~/openhack/support/datainit
sqlcmd -U ${SQL_ADMIN_LOGIN} -P ${SQL_ADMIN_PASSWORD} -S ${SQL_SERVER_FQDN} -d ${SQL_DB_NAME} -i ./MYDrivingDB.sql -e 2>&1 | tee "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/sqlCmd.txt"
bash ./sql_data_init.sh -s ${SQL_SERVER_FQDN} -u ${SQL_ADMIN_LOGIN} -p ${SQL_ADMIN_PASSWORD} -d ${SQL_DB_NAME} 2>&1 | tee "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/dataInit.txt"
az sql server firewall-rule delete --resource-group ${RESOURCE_GROUP} --server ${SQL_SERVER_NAME} --name dataInit 2>&1 | tee "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/sqlFwDelete.txt"

130
iac/bicep/deploy.sh Normal file
View File

@ -0,0 +1,130 @@
#!/bin/bash
declare UNIQUER=""
declare LOCATION=""
declare RESOURCES_PREFIX=""
declare -r USAGE_HELP="Usage: ./deploy.sh -l <LOCATION> [-u <UNIQUER> -r <RESOURCES_PREFIX>]"
declare -r BUILD_ID="${RANDOM:0:5}"
_error() {
echo "##[error] $@" 2>&1
}
if [ $# -eq 0 ]; then
_error "${USAGE_HELP}"
exit 1
fi
# Initialize parameters specified from command line
while getopts ":l:u:r:" arg; do
case "${arg}" in
l) # Process -l (LOCATION)
LOCATION="${OPTARG}"
;;
u) # Process -u (UNIQUER)
UNIQUER="${OPTARG}"
;;
r) # Process -r (RESOURCES_PREFIX)
RESOURCES_PREFIX="${OPTARG}"
;;
\?)
_error "Invalid options found: -${OPTARG}."
_error "${USAGE_HELP}" 2>&1
exit 1
;;
esac
done
shift $((OPTIND - 1))
if [ ${#LOCATION} -eq 0 ]; then
_error "Required LOCATION parameter is not set!"
_error "${USAGE_HELP}" 2>&1
exit 1
fi
# Check for programs
if ! [ -x "$(command -v az)" ]; then
_error "az is not installed!"
exit 1
elif ! [ -x "$(command -v jq)" ]; then
_error "jq is not installed!"
exit 1
elif ! [ -x "$(command -v pwsh)" ]; then
_error "pwsh is not installed!"
exit 1
fi
azure_login() {
_azuresp_json=$(cat azuresp.json)
export ARM_CLIENT_ID=$(echo "${_azuresp_json}" | jq -r ".clientId")
export ARM_CLIENT_SECRET=$(echo "${_azuresp_json}" | jq -r ".clientSecret")
export ARM_SUBSCRIPTION_ID=$(echo "${_azuresp_json}" | jq -r ".subscriptionId")
export ARM_TENANT_ID=$(echo "${_azuresp_json}" | jq -r ".tenantId")
az login --service-principal --username "${ARM_CLIENT_ID}" --password "${ARM_CLIENT_SECRET}" --tenant "${ARM_TENANT_ID}"
az account set --subscription "${ARM_SUBSCRIPTION_ID}"
}
azure_logout() {
az logout
az cache purge
az account clear
}
lint_bicep() {
az bicep build --file main.bicep
rm main.json
}
validate_bicep() {
if [ ${#RESOURCES_PREFIX} -gt 0 ]; then
az deployment sub validate --name "${RESOURCES_PREFIX}-${BUILD_ID}" --template-file main.bicep --location "${LOCATION}" --parameters resourcesPrefix="${RESOURCES_PREFIX}"
elif [[ ${#RESOURCES_PREFIX} -eq 0 && ${#UNIQUER} -gt 0 ]]; then
az deployment sub validate --name "${UNIQUER}-${BUILD_ID}" --template-file main.bicep --location "${LOCATION}" --parameters uniquer="${UNIQUER}"
else
az deployment sub validate --name "${BUILD_ID}" --template-file main.bicep --location "${LOCATION}"
fi
}
preview_bicep() {
if [ ${#RESOURCES_PREFIX} -gt 0 ]; then
az deployment sub what-if --name "${RESOURCES_PREFIX}-${BUILD_ID}" --template-file main.bicep --location "${LOCATION}" --parameters resourcesPrefix="${RESOURCES_PREFIX}"
elif [[ ${#RESOURCES_PREFIX} -eq 0 && ${#UNIQUER} -gt 0 ]]; then
az deployment sub what-if --name "${UNIQUER}-${BUILD_ID}" --template-file main.bicep --location "${LOCATION}" --parameters uniquer="${UNIQUER}"
else
az deployment sub what-if --name "${BUILD_ID}" --template-file main.bicep --location "${LOCATION}"
fi
}
deploy_bicep() {
if [ ${#RESOURCES_PREFIX} -gt 0 ]; then
_deployment_output=$(az deployment sub create --name "${RESOURCES_PREFIX}-${BUILD_ID}" --template-file main.bicep --location "${LOCATION}" --parameters resourcesPrefix="${RESOURCES_PREFIX}")
elif [[ ${#RESOURCES_PREFIX} -eq 0 && ${#UNIQUER} -gt 0 ]]; then
_deployment_output=$(az deployment sub create --name "${UNIQUER}-${BUILD_ID}" --template-file main.bicep --location "${LOCATION}" --parameters uniquer=${UNIQUER})
else
_deployment_output=$(az deployment sub create --name "${BUILD_ID}" --template-file main.bicep --location "${LOCATION}")
fi
echo "${_deployment_output}"
}
test_deploy() {
local _hostnames="${1}"
sleep 30
pwsh -Command ./smokeTest.ps1 -HostNames "${_hostnames}"
}
azure_login
lint_bicep
validate_bicep
preview_bicep
deployment_output=$(deploy_bicep)
echo "${deployment_output}"
# hostnames=$(echo "${deployment_output}" | jq -r -c '.properties.outputs | map(.value) | join(",")')
# test_deploy "${hostnames}"
azure_logout
echo "Build ID: ${BUILD_ID}"

22
iac/bicep/dockerbuild.sh Normal file
View File

@ -0,0 +1,22 @@
#!/bin/bash
cd ~/
git clone "${TEAM_REPO}" --branch "${TEAM_REPO_BRANCH}" ~/openhack
cd ~/openhack/support/simulator
az acr build --image devopsoh/simulator:latest --registry "${CONTAINER_REGISTRY}" --file Dockerfile . 2>&1 | tee "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/simulator.txt"
cd ~/openhack/support/tripviewer
az acr build --image devopsoh/tripviewer:latest --registry ${CONTAINER_REGISTRY} --file Dockerfile . 2>&1 | tee "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/tripviewer.txt"
cd ~/openhack/apis/poi/web
az acr build --image devopsoh/api-poi:${BASE_IMAGE_TAG} --registry ${CONTAINER_REGISTRY} --build-arg build_version=${BASE_IMAGE_TAG} --file Dockerfile . 2>&1 | tee "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/poi.txt"
cd ~/openhack/apis/trips
az acr build --image devopsoh/api-trips:${BASE_IMAGE_TAG} --registry ${CONTAINER_REGISTRY} --build-arg build_version=${BASE_IMAGE_TAG} --file Dockerfile . 2>&1 | tee "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/trips.txt"
cd ~/openhack/apis/user-java
az acr build --image devopsoh/api-user-java:${BASE_IMAGE_TAG} --registry ${CONTAINER_REGISTRY} --build-arg build_version=${BASE_IMAGE_TAG} --file Dockerfile . 2>&1 | tee "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/userjava.txt"
cd ~/openhack/apis/userprofile
az acr build --image devopsoh/api-userprofile:${BASE_IMAGE_TAG} --registry ${CONTAINER_REGISTRY} --build-arg build_version=${BASE_IMAGE_TAG} --file Dockerfile . > "${AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY}/userprofile.txt"

55
iac/bicep/keyVault.bicep Normal file
View File

@ -0,0 +1,55 @@
// Key Vault bootstap for further challenges - not used in the beginning.
param resourcesPrefix string
param location string = resourceGroup().location
param sqlServerAdminLogin string
param sqlServerId string
@secure()
param sqlServerAdminPassword string
@secure()
param containerRegistryAdminPassword string
// https://docs.microsoft.com/en-us/azure/templates/microsoft.keyvault/vaults?tabs=bicep
resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' = {
name: '${resourcesPrefix}kv'
location: location
properties: {
sku: {
name: 'standard'
family: 'A'
}
tenantId: subscription().tenantId
accessPolicies: []
softDeleteRetentionInDays: 7
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.keyvault/vaults/secrets?tabs=bicep
resource sqlPassword 'Microsoft.KeyVault/vaults/secrets@2021-06-01-preview' = {
parent: keyVault
name: 'SQL-PASSWORD'
tags: {
CredentialId: sqlServerAdminLogin
ProviderAddress: sqlServerId
ValidityPeriodDays: '60'
}
properties: {
attributes: {
enabled: true
//exp: '' // needs to be int - timestamp in seconds
}
value: sqlServerAdminPassword
}
}
resource dockerRegistryServerPassword 'Microsoft.KeyVault/vaults/secrets@2021-06-01-preview' = {
parent: keyVault
name: 'DOCKER-REGISTRY-SERVER-PASSWORD'
properties: {
value: containerRegistryAdminPassword
}
}
output name string = keyVault.name

View File

@ -0,0 +1,85 @@
param resourcesPrefix string
var location = resourceGroup().location
// https://docs.microsoft.com/en-us/azure/templates/microsoft.operationalinsights/workspaces?tabs=bicep
resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' = {
name: '${resourcesPrefix}log'
location: location
properties: {
sku: {
name: 'PerGB2018'
}
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.operationsmanagement/solutions?tabs=bicep
resource logAnalyticsSolutionContainers 'Microsoft.OperationsManagement/solutions@2015-11-01-preview' = {
name: 'Containers(${logAnalyticsWorkspace.name})'
location: location
plan: {
name: 'Containers(${logAnalyticsWorkspace.name})'
product: 'OMSGallery/Containers'
publisher: 'Microsoft'
promotionCode: '' // this is ignored, but has to be present
}
properties: {
workspaceResourceId: logAnalyticsWorkspace.id
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.operationsmanagement/solutions?tabs=bicep
resource logAnalyticsSolutionSQLAssessment 'Microsoft.OperationsManagement/solutions@2015-11-01-preview' = {
name: 'SQLAssessment(${logAnalyticsWorkspace.name})'
location: location
plan: {
name: 'SQLAssessment(${logAnalyticsWorkspace.name})'
product: 'OMSGallery/SQLAssessment'
publisher: 'Microsoft'
promotionCode: '' // this is ignored, but has to be present
}
properties: {
workspaceResourceId: logAnalyticsWorkspace.id
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.operationsmanagement/solutions?tabs=bicep
resource logAnalyticsSolutionAzureSQLAnalytics 'Microsoft.OperationsManagement/solutions@2015-11-01-preview' = {
name: 'AzureSQLAnalytics(${logAnalyticsWorkspace.name})'
location: location
plan: {
name: 'AzureSQLAnalytics(${logAnalyticsWorkspace.name})'
product: 'OMSGallery/AzureSQLAnalytics'
publisher: 'Microsoft'
promotionCode: '' // this is ignored, but has to be present
}
properties: {
workspaceResourceId: logAnalyticsWorkspace.id
}
}
// resource logAnalyticsSolutionContainerInsights 'Microsoft.OperationsManagement/solutions@2015-11-01-preview' = {
// name: 'ContainerInsights(${logAnalyticsWorkspace.name})'
// location: location
// plan: {
// name: 'ContainerInsights(${logAnalyticsWorkspace.name})'
// product: 'OMSGallery/ContainerInsights'
// publisher: 'Microsoft'
// promotionCode: '' // this is ignored, but has to be present
// }
// properties: {
// workspaceResourceId: logAnalyticsWorkspace.id
// }
// }
output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name
output logAnalyticsWorkspaceId string = logAnalyticsWorkspace.properties.customerId
output logAnalyticsWorkspaceKey string = logAnalyticsWorkspace.listKeys().primarySharedKey

193
iac/bicep/main.bicep Normal file
View File

@ -0,0 +1,193 @@
targetScope = 'subscription'
param uniquer string = uniqueString(newGuid())
param location string = deployment().location
param resourcesPrefix string = ''
param apiPoiBaseImageTag string = ''
param apiTripsBaseImageTag string = ''
param apiUserJavaBaseImageTag string = ''
param apiUserprofileBaseImageTag string = ''
param sqlServerAdminPassword string = ''
var varfile = json(loadTextContent('./variables.json'))
var resourcesPrefixCalculated = empty(resourcesPrefix) ? '${varfile.namePrefix}${uniquer}' : resourcesPrefix
var resourceGroupName = '${resourcesPrefixCalculated}rg'
var apiPoiBaseImageTagCalculated = empty(apiPoiBaseImageTag) ? varfile.baseImageTag : apiPoiBaseImageTag
var apiTripsBaseImageTagCalculated = empty(apiTripsBaseImageTag) ? varfile.baseImageTag : apiTripsBaseImageTag
var apiUserJavaBaseImageTagCalculated = empty(apiUserJavaBaseImageTag) ? varfile.baseImageTag : apiUserJavaBaseImageTag
var apiUserprofileBaseImageTagCalculated = empty(apiUserprofileBaseImageTag) ? varfile.baseImageTag : apiUserprofileBaseImageTag
var sqlServerAdminPasswordCalculated = empty(sqlServerAdminPassword) ? varfile.sqlServerAdminPassword : sqlServerAdminPassword
module openhackResourceGroup './resourceGroup.bicep' = {
name: '${resourcesPrefixCalculated}-resourceGroupDeployment'
params: {
resourceGroupName: resourceGroupName
location: location
}
}
module managedIdentity './managedIdentity.bicep' = {
name: 'managedIdentityDeployment'
params: {
resourcesPrefix: resourcesPrefixCalculated
}
scope: resourceGroup(resourceGroupName)
dependsOn: [
openhackResourceGroup
]
}
module containerRegistry './containerRegistry.bicep' = {
name: 'containerRegistryDeployment'
params: {
resourcesPrefix: resourcesPrefixCalculated
}
scope: resourceGroup(resourceGroupName)
dependsOn: [
openhackResourceGroup
managedIdentity
]
}
module sqlServer './sqlServer.bicep' = {
name: 'sqlServerDeployment'
params: {
resourcesPrefix: resourcesPrefixCalculated
sqlServerAdminPassword: sqlServerAdminPasswordCalculated
logAnalyticsWorkspaceName: logAnalytics.outputs.logAnalyticsWorkspaceName
}
scope: resourceGroup(resourceGroupName)
dependsOn: [
openhackResourceGroup
managedIdentity
logAnalytics
]
}
module appInsights './appInsights.bicep' = {
name: 'appInsightsDeployment'
params: {
resourcesPrefix: resourcesPrefixCalculated
}
scope: resourceGroup(resourceGroupName)
dependsOn: [
openhackResourceGroup
]
}
module appService './appService.bicep' = {
name: 'appServiceDeployment'
params: {
resourcesPrefix: resourcesPrefixCalculated
sqlServerFqdn: sqlServer.outputs.sqlServerFqdn
sqlServerAdminLogin: sqlServer.outputs.sqlServerAdminLogin
sqlServerAdminPassword: sqlServerAdminPasswordCalculated
sqlDatabaseName: sqlServer.outputs.sqlDatabaseName
containerRegistryLoginServer: containerRegistry.outputs.containerRegistryLoginServer
containerRegistryName: containerRegistry.outputs.containerRegistryName
// userAssignedManagedIdentityId: managedIdentity.outputs.userAssignedManagedIdentityId
// userAssignedManagedIdentityPrincipalId: managedIdentity.outputs.userAssignedManagedIdentityPrincipalId
containerRegistryAdminUsername: containerRegistry.outputs.containerRegistryAdminUsername
containerRegistryAdminPassword: containerRegistry.outputs.containerRegistryAdminPassword
keyVaultName: keyVault.outputs.name
appInsightsInstrumentationKey: appInsights.outputs.appInsightsInstrumentationKey
appInsightsConnectionString: appInsights.outputs.appInsightsConnectionString
appInsightsStagingInstrumentationKey: appInsights.outputs.appInsightsStagingInstrumentationKey
appInsightsStagingConnectionString: appInsights.outputs.appInsightsStagingConnectionString
apiPoiBaseImageTag: apiPoiBaseImageTagCalculated
apiTripsBaseImageTag: apiTripsBaseImageTagCalculated
apiUserJavaBaseImageTag: apiUserJavaBaseImageTagCalculated
apiUserprofileBaseImageTag: apiUserprofileBaseImageTagCalculated
}
scope: resourceGroup(resourceGroupName)
dependsOn: [
containerRegistry
sqlServer
apps
appInsights
]
}
module apps './apps.bicep' = {
name: 'appsDeployment'
params: {
resourcesPrefix: resourcesPrefixCalculated
sqlServerFqdn: sqlServer.outputs.sqlServerFqdn
sqlServerName: sqlServer.outputs.sqlServerName
sqlServerAdminPassword: sqlServerAdminPasswordCalculated
containerRegistryLoginServer: containerRegistry.outputs.containerRegistryLoginServer
containerRegistryName: containerRegistry.outputs.containerRegistryName
userAssignedManagedIdentityId: managedIdentity.outputs.userAssignedManagedIdentityId
userAssignedManagedIdentityPrincipalId: managedIdentity.outputs.userAssignedManagedIdentityPrincipalId
}
scope: resourceGroup(resourceGroupName)
dependsOn: [
sqlServer
containerRegistry
managedIdentity
]
}
module logAnalytics './logAnalytics.bicep' = {
name: 'logAnalyticsDeployment'
params: {
resourcesPrefix: resourcesPrefixCalculated
}
scope: resourceGroup(resourceGroupName)
dependsOn: [
openhackResourceGroup
]
}
module containerGroup './containerGroup.bicep' = {
name: 'containerGroupDeployment'
params: {
resourcesPrefix: resourcesPrefixCalculated
sqlServerFqdn: sqlServer.outputs.sqlServerFqdn
sqlServerAdminLogin: sqlServer.outputs.sqlServerAdminLogin
sqlServerAdminPassword: sqlServerAdminPasswordCalculated
sqlDatabaseName: sqlServer.outputs.sqlDatabaseName
containerRegistryLoginServer: containerRegistry.outputs.containerRegistryLoginServer
// containerRegistryName: containerRegistry.outputs.containerRegistryName
containerRegistryAdminUsername: containerRegistry.outputs.containerRegistryAdminUsername
containerRegistryAdminPassword: containerRegistry.outputs.containerRegistryAdminPassword
appServiceApiPoiHostname: appService.outputs.appServiceApiPoiHostname
appServiceApiTripsHostname: appService.outputs.appServiceApiTripsHostname
appServiceApiUserJavaHostname: appService.outputs.appServiceApiUserJavaHostname
appServiceApiUserprofileHostname: appService.outputs.appServiceApiUserprofileHostname
logAnalyticsWorkspaceId: logAnalytics.outputs.logAnalyticsWorkspaceId
logAnalyticsWorkspaceKey: logAnalytics.outputs.logAnalyticsWorkspaceKey
// userAssignedManagedIdentityId: managedIdentity.outputs.userAssignedManagedIdentityId
// userAssignedManagedIdentityPrincipalId: managedIdentity.outputs.userAssignedManagedIdentityPrincipalId
}
scope: resourceGroup(resourceGroupName)
dependsOn: [
containerRegistry
sqlServer
appService
apps
logAnalytics
]
}
module keyVault './keyVault.bicep' = {
name: 'keyVaultDeployment'
params: {
resourcesPrefix: resourcesPrefixCalculated
containerRegistryAdminPassword: containerRegistry.outputs.containerRegistryAdminPassword
sqlServerAdminLogin: sqlServer.outputs.sqlServerAdminLogin
sqlServerAdminPassword: sqlServerAdminPasswordCalculated
sqlServerId: sqlServer.outputs.sqlServerId
}
scope: resourceGroup(resourceGroupName)
dependsOn: [
openhackResourceGroup
]
}
output appServiceApiPoiHealthcheck string = '${appService.outputs.appServiceApiPoiHostname}/api/healthcheck/poi'
output appServiceApiTripsHealthcheck string = '${appService.outputs.appServiceApiTripsHostname}/api/healthcheck/trips'
output appServiceApiUserJavaHealthcheck string = '${appService.outputs.appServiceApiUserJavaHostname}/api/healthcheck/user-java'
output appServiceApiUserprofileHealthcheck string = '${appService.outputs.appServiceApiUserprofileHostname}/api/healthcheck/user'

View File

@ -0,0 +1,12 @@
param resourcesPrefix string
var location = resourceGroup().location
// https://docs.microsoft.com/en-us/azure/templates/microsoft.managedidentity/userassignedidentities?tabs=bicep
resource userAssignedManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
name: '${resourcesPrefix}uami'
location: location
}
output userAssignedManagedIdentityId string = userAssignedManagedIdentity.id
output userAssignedManagedIdentityPrincipalId string = userAssignedManagedIdentity.properties.principalId

View File

@ -0,0 +1,10 @@
targetScope = 'subscription'
param resourceGroupName string
param location string
// https://docs.microsoft.com/en-us/azure/templates/microsoft.resources/resourcegroups?tabs=bicep
resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: resourceGroupName
location: location
}

31
iac/bicep/smokeTest.ps1 Normal file
View File

@ -0,0 +1,31 @@
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string[]] $HostNames = @()
)
if (!(Get-Module -Name Pester)) {
Write-Host "Pester module does not exist. Installing ..."
try {
Install-Module Pester -AllowClobber -Force -Confirm:$False -SkipPublisherCheck
}
catch [Exception] {
$_.message
exit
}
}
Import-Module Pester
$container = New-PesterContainer `
-Path 'appService.Test.ps1' `
-Data @{ HostNames = $HostNames }
$config = New-PesterConfiguration
$config.Run.PassThru = $true
$config.Run.Container = $container
$config.TestResult.Enabled = $true
$config.TestResult.OutputFormat = 'NUnitXml'
$config.TestResult.OutputPath = 'testResultsNunit.xml'
$p = Invoke-Pester -Configuration $config
$p | Export-JUnitReport -Path 'testResultsJunit.xml'

120
iac/bicep/sqlServer.bicep Normal file
View File

@ -0,0 +1,120 @@
param resourcesPrefix string
param logAnalyticsWorkspaceName string
param sqlServerAdminPassword string
var location = resourceGroup().location
var varfile = json(loadTextContent('./variables.json'))
// https://docs.microsoft.com/en-us/azure/templates/microsoft.sql/servers?tabs=bicep
resource sqlServer 'Microsoft.Sql/servers@2021-05-01-preview' = {
name: '${resourcesPrefix}sql'
location: location
properties: {
administratorLogin: varfile.sqlServerAdminLogin
administratorLoginPassword: sqlServerAdminPassword
minimalTlsVersion: '1.2'
version: '12.0'
}
}
resource sqlFirewallRuleAzure 'Microsoft.Sql/servers/firewallRules@2021-05-01-preview' = {
parent: sqlServer
name: 'AzureAccess'
properties: {
endIpAddress: '0.0.0.0'
startIpAddress: '0.0.0.0'
}
}
// https://docs.microsoft.com/en-us/azure/templates/microsoft.sql/servers/databases?tabs=bicep
resource sqlDatabase 'Microsoft.Sql/servers/databases@2021-05-01-preview' = {
parent: sqlServer
name: 'mydrivingDB'
location: location
sku: {
name: 'S0'
}
properties: {
collation: 'SQL_Latin1_General_CP1_CI_AS'
}
}
resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' existing = {
name: logAnalyticsWorkspaceName
}
// https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/resource-manager-diagnostic-settings#diagnostic-setting-for-azure-sql-database
// https://docs.microsoft.com/en-us/azure/templates/microsoft.insights/diagnosticsettings?tabs=bicep
resource sqlDatabaseDiagnostic 'microsoft.insights/diagnosticSettings@2021-05-01-preview' = {
name: 'sqlDbDiag'
scope: sqlDatabase
properties: {
workspaceId: logAnalyticsWorkspace.id
logs: [
{
category: 'SQLInsights'
enabled: true
}
{
category: 'AutomaticTuning'
enabled: true
}
{
category: 'QueryStoreRuntimeStatistics'
enabled: true
}
{
category: 'QueryStoreWaitStatistics'
enabled: true
}
{
category: 'Errors'
enabled: true
}
{
category: 'DatabaseWaitStatistics'
enabled: true
}
{
category: 'Timeouts'
enabled: true
}
{
category: 'Blocks'
enabled: true
}
{
category: 'Deadlocks'
enabled: true
}
{
category: 'DevOpsOperationsAudit'
enabled: true
}
{
category: 'SQLSecurityAuditEvents'
enabled: true
}
]
metrics: [
{
category: 'Basic'
enabled: true
}
{
category: 'InstanceAndAppAdvanced'
enabled: true
}
{
category: 'WorkloadManagement'
enabled: true
}
]
}
}
output sqlServerAdminLogin string = varfile.sqlServerAdminLogin
output sqlServerFqdn string = sqlServer.properties.fullyQualifiedDomainName
output sqlDatabaseName string = sqlDatabase.name
output sqlServerName string = sqlServer.name
output sqlServerId string = sqlServer.id

9
iac/bicep/variables.json Normal file
View File

@ -0,0 +1,9 @@
{
"namePrefix": "devopsoh",
"baseImageTag": "changeme",
"bingMapsKey": "Ar6iuHZYgX1BrfJs6SRJaXWbpU_HKdoe7G-OO9b2kl3rWvcawYx235GGx5FPM76O",
"sqlServerAdminLogin": "demousersa",
"sqlServerAdminPassword": "demo!P@55w0rd123",
"publicTeamRepo": "https://github.com/Microsoft-OpenHack/devops-artifacts",
"publicTeamRepoBranch": "main"
}