Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/reusable-apply-infrastructure.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ jobs:
with:
scope: subscription
subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
template: ./infrastructure/websiteDeploy.bicep
template: ./infrastructure/website.bicep
deploymentName: deploy-${{ inputs.application }}
parameters: "resourceGroupSuffix=${{ env.GITHUB_REF_NAME_SLUG }} application=${{ inputs.application }}"
parameters: >-
./infrastructure/dotnet.bicepparam
resourceGroupSuffix=${{ env.GITHUB_REF_NAME_SLUG }}
region: westeurope

- name: Comment Website FQDNs on Pull Requests
Expand Down
34 changes: 34 additions & 0 deletions infrastructure/dotnet.bicepparam
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using './website.bicep'

param resourceGroupSuffix = 'main'
param application = 'dotnet'
param hostnames = [
{
dnsZoneName: 'xprtz.nl'
hostname: ''
}
{
dnsZoneName: 'xprtz.nl'
hostname: 'www'
}
{
dnsZoneName: 'xprtz.cloud'
hostname: ''
}
{
dnsZoneName: 'xprtz.cloud'
hostname: 'www'
}
{
dnsZoneName: 'xprtz.net'
hostname: ''
}
{
dnsZoneName: 'xprtz.net'
hostname: 'www'
}
]
param imageHostname = {
dnsZoneName: 'xprtz.nl'
hostname: 'images'
}
38 changes: 17 additions & 21 deletions infrastructure/modules/dns.bicep
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { domainsType, validationTokenType } from '../types.bicep'
import { hostnameType, validationTokenType } from '../types.bicep'

@description('The dns record details')
param hostname hostnameType
@description('The ID of the Front Door endpoint to link the DNS records to.')
param frontDoorEndpointId string
param origin string
param domains domainsType[]
param validationTokens validationTokenType[]
param deployApexRecord bool = true

var cnames = filter(domains, domain => domain.subDomain != '')
@description('The frontdoor hostname to be used for the DNS CNAME records.')
param frontDoorHostname string
@description('The validation token for DNS verification.')
param validationToken validationTokenType

resource dnsZone 'Microsoft.Network/dnsZones@2023-07-01-preview' existing = {
name: domains[0].rootDomain
name: hostname.dnsZoneName
}

resource apexRecord 'Microsoft.Network/dnszones/A@2023-07-01-preview' = if(deployApexRecord) {
resource apexRecord 'Microsoft.Network/dnszones/A@2023-07-01-preview' = if (empty(hostname.hostname)) {
parent: dnsZone
name: '@'
properties: {
Expand All @@ -23,25 +24,20 @@ resource apexRecord 'Microsoft.Network/dnszones/A@2023-07-01-preview' = if(deplo
}
}

@batchSize(1)
resource cnameRecord 'Microsoft.Network/dnsZones/CNAME@2023-07-01-preview' = [for domain in cnames: {
resource cnameRecord 'Microsoft.Network/dnsZones/CNAME@2023-07-01-preview' = if (!empty(hostname.hostname)) {
parent: dnsZone
name: domain.subDomain
name: hostname.hostname
properties: {
TTL: 3600
CNAMERecord: {
cname: origin
cname: frontDoorHostname
}
}
dependsOn: [
apexRecord
]
}]
}

@batchSize(1)
resource validationTxtRecord 'Microsoft.Network/dnsZones/TXT@2023-07-01-preview' = [for validationToken in validationTokens: {
resource validationTxtRecordApex 'Microsoft.Network/dnsZones/TXT@2023-07-01-preview' = {
parent: dnsZone
name: '_dnsauth.${validationToken.domain.subDomain}'
name: empty(hostname.hostname) ? '_dnsauth' : '_dnsauth.${hostname.hostname}'
properties: {
TTL: 3600
TXTRecords: [
Expand All @@ -52,4 +48,4 @@ resource validationTxtRecord 'Microsoft.Network/dnsZones/TXT@2023-07-01-preview'
}
]
}
}]
}
2 changes: 1 addition & 1 deletion infrastructure/modules/frontdoor-images.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -324,5 +324,5 @@ resource frontDoorCustomDomain 'Microsoft.Cdn/profiles/customDomains@2024-02-01'
}

output frontDoorCustomDomainValidationToken string = frontDoorCustomDomain.properties.validationProperties.validationToken
output frontDoorCustomDomainHost string = frontDoorEndpoint.properties.hostName
output frontDoorHostname string = frontDoorEndpoint.properties.hostName
output frontDoorEndpointId string = frontDoorEndpoint.id
56 changes: 31 additions & 25 deletions infrastructure/modules/frontdoor.bicep
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { domainsType } from '../types.bicep'
import { hostnameType, validationTokenType } from '../types.bicep'

@description('The name of the Front Door profile to use for the CDN.')
param frontDoorProfileName string
@description('The hostname of the origin for the Front Door.')
param frontDoorOriginHost string
@description('The name of the application, used to prefix resource names.')
param application string
param domains domainsType[]
@description('List of hostnames to be configured for the Front Door.')
param hostnames hostnameType[]

var frontDoorOriginName = 'afd-origin-${application}'
var frontDoorEndpointName = 'fde-${application}-${uniqueString(resourceGroup().id)}'
var frontDoorOriginGroupName = 'xprtz-website-${application}'
var frontDoorRouteName = 'inbound'

resource dnsZone 'Microsoft.Network/dnsZones@2018-05-01' existing = {
name: domains[0].rootDomain
}
resource dnsZones 'Microsoft.Network/dnsZones@2018-05-01' existing = [for hostname in hostnames: {
name: hostname.dnsZoneName
}]

resource frontDoorProfile 'Microsoft.Cdn/profiles@2024-02-01' existing = {
name: frontDoorProfileName
Expand All @@ -24,7 +28,6 @@ resource frontDoorEndpoint 'Microsoft.Cdn/profiles/afdEndpoints@2024-02-01' = {
location: 'global'
properties: {
enabledState: 'Enabled'

}
}

Expand Down Expand Up @@ -58,14 +61,32 @@ resource frontDoorOrigin 'Microsoft.Cdn/profiles/originGroups/origins@2024-02-01
}
}

var domainNames = [for hostname in hostnames: empty(hostname.hostname) ? hostname.dnsZoneName : '${hostname.hostname}.${hostname.dnsZoneName}']

@batchSize(1)
resource frontDoorCustomDomains 'Microsoft.Cdn/profiles/customDomains@2024-02-01' = [for (domainName, index) in domainNames: {
name: replace(domainName, '.', '-')
parent: frontDoorProfile
properties: {
hostName: domainName
tlsSettings: {
certificateType: 'ManagedCertificate'
minimumTlsVersion: 'TLS12'
}
azureDnsZone: {
id: dnsZones[index].id
}
}
}]

resource frontDoorRoute 'Microsoft.Cdn/profiles/afdEndpoints/routes@2024-02-01' = {
name: frontDoorRouteName
parent: frontDoorEndpoint
dependsOn: [
frontDoorOrigin
]
properties: {
customDomains: [for (domain, index) in domains: {
customDomains: [for (hostname, index) in hostnames: {
id: frontDoorCustomDomains[index].id
}]
originGroup: {
Expand All @@ -84,24 +105,9 @@ resource frontDoorRoute 'Microsoft.Cdn/profiles/afdEndpoints/routes@2024-02-01'
}
}

resource frontDoorCustomDomains 'Microsoft.Cdn/profiles/customDomains@2024-02-01' = [for (domain, index) in domains: {
name: replace(domain.fullDomain, '.', '-')
parent: frontDoorProfile
properties: {
hostName: domain.fullDomain
tlsSettings: {
certificateType: 'ManagedCertificate'
minimumTlsVersion: 'TLS12'
}
azureDnsZone: {
id: dnsZone.id
}
}
}]

output frontDoorCustomDomainValidationTokens array = [for (domain, index) in domains: {
domain: domain
output frontDoorCustomDomainValidationTokens validationTokenType[] = [for (hostname, index) in hostnames: {
hostname: hostname
validationToken: frontDoorCustomDomains[index].properties.validationProperties.validationToken
}]
output frontDoorCustomDomainHost string = frontDoorEndpoint.properties.hostName
output frontDoorHostname string = frontDoorEndpoint.properties.hostName
output frontDoorEndpointId string = frontDoorEndpoint.id
3 changes: 2 additions & 1 deletion infrastructure/shared-values.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
},
"resourceGroups": {
"infrastructure": "rg-xprtzbv-infrastructure"
}
},
"frontDoorProfileName": "afd-xprtzbv-websites"
}
9 changes: 4 additions & 5 deletions infrastructure/types.bicep
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
@export()
type domainsType = {
rootDomain: string
subDomain: string
fullDomain: string
type hostnameType = {
dnsZoneName: string
hostname: string
}

@export()
type validationTokenType = {
domain: domainsType
hostname: hostnameType
validationToken: string
}
93 changes: 93 additions & 0 deletions infrastructure/website.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { hostnameType } from './types.bicep'

targetScope = 'subscription'

@description('The suffix for the resource group, typically \'main\' for production or a specific identifier for non-production environments.')
param resourceGroupSuffix string
@description('The name of the application, used to prefix resource names.')
param application string
@description('List of hostnames to be configured for the website.')
param hostnames hostnameType[]
@description('Hostname for the images domain, used for static content.')
param imageHostname hostnameType

var isProd = endsWith(resourceGroupSuffix, 'main')

var sharedValues = json(loadTextContent('shared-values.json'))
var infrastructureResourceGroup = resourceGroup(
sharedValues.subscriptionIds.xprtz,
sharedValues.resourceGroups.infrastructure
)

var resourceGroupPrefix = 'rg-xprtzbv-website-${application}'
var resourceGroupName = isProd ? resourceGroupPrefix : '${resourceGroupPrefix}-${resourceGroupSuffix}'
resource websiteResourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = {
location: deployment().location
name: resourceGroupName
}

module storageAccountModule 'modules/storageAccount.bicep' = {
scope: websiteResourceGroup
name: 'storageAccountDeploy-${application}'
params: {
app: application
}
}

module frontDoorSettings 'modules/frontdoor.bicep' = if (isProd) {
scope: infrastructureResourceGroup
name: 'frontDoorSettingsDeploy-${application}'
params: {
frontDoorOriginHost: storageAccountModule.outputs.storageAccountHost
frontDoorProfileName: sharedValues.frontDoorProfileName
application: application
hostnames: hostnames
}
}

@batchSize(1)
module dnsSettings 'modules/dns.bicep' = [for hostname in hostnames: if (isProd) {
scope: infrastructureResourceGroup
name: 'dnsSettingsDeploy-${hostname.hostname}-${hostname.dnsZoneName}-${application}'
params: {
hostname: hostname
frontDoorEndpointId: frontDoorSettings!.outputs.frontDoorEndpointId
frontDoorHostname: frontDoorSettings!.outputs.frontDoorHostname
validationToken: filter(
frontDoorSettings!.outputs.frontDoorCustomDomainValidationTokens,
validation => validation.hostname.hostname == hostname.hostname && validation.hostname.dnsZoneName == hostname.dnsZoneName
)[0]
Comment thread
mvdevries marked this conversation as resolved.
}
}
]

module imagesFrontDoorSettings 'modules/frontdoor-images.bicep' = if (isProd) {
scope: infrastructureResourceGroup
name: 'imagesFrontDoorSettingsDeploy-${application}'
params: {
storageAccountName: storageAccountModule!.outputs.storageAccountName
storageAccountResourceGroup: websiteResourceGroup.name
frontDoorProfileName: sharedValues.frontDoorProfileName
application: application
rootDomain: imageHostname.dnsZoneName
subDomain: imageHostname.hostname
}
}

module imagesDnsSettings 'modules/dns.bicep' = if (isProd) {
scope: infrastructureResourceGroup
name: 'imagesDnsSettingsDeploy-${application}'
params: {
hostname: imageHostname
frontDoorEndpointId: imagesFrontDoorSettings!.outputs.frontDoorEndpointId
frontDoorHostname: imagesFrontDoorSettings!.outputs.frontDoorHostname
validationToken: {
hostname: imageHostname
validationToken: imagesFrontDoorSettings!.outputs.frontDoorCustomDomainValidationToken
}
}
}

output storageAccountName string = storageAccountModule.outputs.storageAccountName
output resourceGroupName string = websiteResourceGroup.name
output applicationFqdn string = isProd ? 'https://${hostnames[0].dnsZoneName}/' : storageAccountModule.outputs.storageAccountFqdn
Loading