Azure Infrastructure as Code �Framework
Presented by George Kopf
gkopf@Princeton.edu
© 2023 Princeton University OIT
Presentation Overview
2
Newer tools for cloud environments:
Native (Azure, AWS, GCP, OCI)
Newer tools for cloud environments:
Native (Azure, AWS, GCP, OCI)
Newer tools for cloud environments:
Native (Azure, AWS, GCP, OCI)
© 2023 Princeton University OIT
Infrastructure as Code
- Isn’t that an oxymoron?
- - No. Those oxy-things have horns and don’t call me a moron.
3
© 2023 Princeton University OIT
Infrastructure as Code
4
Software that executes system commands!
Established tools for Linux and Windows:
Puppet, Chef, Ansible
Native tools for cloud environments:
Azure (CLI, PowerShell, ARM, Bicep)
AWS (Cloud Formation)
Terraform for cross-platform code.
© 2023 Princeton University OIT
Infrastructure as Code (IAC)
5
© 2023 Princeton University OIT
The Framework
- I find it ironic that there are so many different ways to standardize.
6
© 2023 Princeton University OIT
Framework
7
© 2023 Princeton University OIT
Framework
8
A standard coding structure and approach.
Many existing frameworks for software development.
Spring, Struts, Grail, Ruby, Django
A pseudo-framework for IAC
© 2023 Princeton University OIT
Roles – Profiles - Components
9
© 2023 Princeton University OIT
10
Modules
Naming Conventions
Parameterization
Templates
Coding styles
Code Dependencies
Folder Structure
Segmentation
Encapsulation
Language
Tool Selection
© 2023 Princeton University OIT
The Journey
- It’s not the destination that’s important.
- - It’s all of the dead ends, rabbit holes and ditches you get to explore on the way.
11
© 2023 Princeton University OIT
Early steps on the wrong road.
Terraform: Lagging Azure releases. Overkill since we are focused one cloud provider.
Azure CLI: Low level code with minimal abstraction and reusability.
PowerShell: Difficult to extend. Coded ourselves into a corner.
ARM Templates: Giant JSON files with giant JSON parameter files.
We based our first iteration on the Puppet IAC Framework
12
© 2023 Princeton University OIT
Why Bicep?
Microsoft Domain Specific Language
13
© 2023 Princeton University OIT
Each pipeline is organized around a discreet service.
Resource Group
14
Virtual Network and Subnets
Container App Environment
App Gateway
Container Registry
Applications
Log Analytics Workspace
API Manager
GraphQL Service
Each Service has:
One Pipeline
One or more Configuration files
One or more Modules
Key Vault
© 2023 Princeton University OIT
A picture is worth a thousand words.
15
main.bicep
DevOps Trigger
Pipeline YAML
env.bicepparam
main.bicep
Microsoft Public Bicep Registry
Princeton Private Bicep Registry
Instantiated Azure Resources
common variables
YAML Templates
© 2023 Princeton University OIT
Adopted Microsoft Conventions
Our repositories follow the naming convention and folder structure of Microsoft.
GitHub repository of Microsoft modules: https://github.com/Azure/ResourceModules/tree/main/modules
16
© 2023 Princeton University OIT
Public vs. Private Bicep Registry
Utilizing Microsoft’s Bicep Registry whenever possible.
GitHub repository of https://github.com/Azure/bicep-registry-modules/tree/main/modules
…/network/virtual-network/main.bicep
17
© 2023 Princeton University OIT
The Destination
“Would you tell me, please, which way I ought to go from here?” asked Alice
“That depends a good deal on where you want to get to,” said the Cat.
“I don’t much care where—” said Alice.
“Then it doesn’t matter which way you go,” said the Cat.
18
© 2023 Princeton University OIT
Pipeline
19
main.bicep
DevOps Trigger
Pipeline YAML
env.bicepparam
main.bicep
Microsoft Public Bicep Registry
Princeton Private Bicep Registry
Instantiated Azure Resources
common variables
YAML Templates
© 2023 Princeton University OIT
YAML Pipelines
20
All pipelines run the same steps:
© 2023 Princeton University OIT
Pipelines – Azure DevOps YAML file
21
az deployment sub create
--location "$(Location)"
--template-file "$(BicepTemplate)"
--parameters "$(BicepParam)"
parameters:
- name: env_param
displayName: Environment
type: string
values:
- "sbx"
- "dev"
- "qap"
- "prd"
default: "sbx“
variables:
- name: ModuleDirectoryName
value: 'AppGateway’
- name: location
value: ’eastus'
- name: BicepTemplate
value: '$(System.DefaultWorkingDirectory)/${{ variables.ModuleDirectoryName }}/Components/main.bicep'
- name: BicepParam
value: '$(System.DefaultWorkingDirectory)/${{ variables.ModuleDirectoryName }}/Configuration/${{parameters.env_param}}.bicepparam'
© 2023 Princeton University OIT
Pipelines – Azure DevOps YAML Templates
22
variables:
- name: ModuleDirectoryName
value: 'AppGateway’
. . .
- template: templates/commonVars.yml@Utilities
�stages:
- ${{ if eq(parameters.bicepLinter, true) }}:
- template: templates/bicepLinter.yml@Utilities
- ${{ if eq(parameters.generateReadMe, true) }}:
- template: templates/generateReadMeInline.yml@Utilities
- ${{ if eq(parameters.runWhatIf, true) }}:
- template: templates/validateAndWhatIf.yml@Utilities
parameters:
validationTimeout: 1
- ${{ if eq(parameters.runDeploy, true) }}:
- template: templates/deployBicep.yml@Utilities
© 2023 Princeton University OIT
Bicep Registries
23
env.bicepparam
main.bicep
DevOps Trigger
Pipeline YAML
env.bicepparam
main.bicep
Microsoft Public Bicep Registry
Princeton Private Bicep Registry
Instantiated Azure Resources
common variables
YAML Templates
© 2023 Princeton University OIT
Reusable Components
The Princeton Bicep Registry contains custom code modules. To fill the gaps from what is available in the Microsoft Bicep Registry.
24
module common ‘br:puoitabr.azurecr.io/common/sis:v0.1' = { …
or
module appGatewayKeyVault 'br/public:avm/security/keyvault:1.0.2' = { …
This is where our reusable components are stored.
Princeton’s Bicep Registry
Microsoft’s Bicep Registry
Microsoft Public Bicep Registry
Princeton Private Bicep Registry
© 2023 Princeton University OIT
These bicep modules call a Microsoft resource
25
// Create the application gateway
resource applicationGateway 'Microsoft.Network/applicationGateways@2023-02-01' = {
name: appGatewayName
location: location
tags: tags
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${appGatewayIdentityId}':{}
}
}
properties: {
sku: sku
enableHttp2: false
autoscaleConfiguration: . . .
© 2023 Princeton University OIT
26
properties: {
sku: sku
enableHttp2: false
autoscaleConfiguration: autoscaleConfiguration
gatewayIPConfigurations:[
{
name: gatewayIPConfigurationsName
properties: {
subnet: {
id: gatewayIPConfigurationsSnetId
}
}
}
]
frontendIPConfigurations: [
{
name: frontendIPConfigurationsName
� properties: {
privateIPAllocationMethod: 'Dynamic'
publicIPAddress: {
id: publicIpAddressId
}
}
}
]
frontendPorts: frontendPorts
backendAddressPools: backendAddressPools
backendHttpSettingsCollection: beHttpSettingsCollection
httpListeners: httpsListeners
sslCertificates: appGatewaySslCerts
urlPathMaps: urlPathMaps
requestRoutingRules: requestRoutingRules
rewriteRuleSets: rewriteRuleSets
probes: probes
}
}
This architecture provides a layer of abstraction between our Bicep pipelines and the Microsoft resource procedures.
In this layer we can hardcode standards and prefill immutable parameters.
© 2023 Princeton University OIT
main.bicep
27
main.bicep
DevOps Trigger
Pipeline YAML
env.bicepparam
main.bicep
Microsoft Public Bicep Registry
Princeton Private Bicep Registry
Instantiated Azure Resources
common variables
YAML Templates
© 2023 Princeton University OIT
Configuration aka: bicepparam file
28
using '../Components/main.bicep'
// Environment Variables
param subscriptionId = readEnvironmentVariable('SUBSCRIPTIONID','error')
// Global Parameters
param dataClassification = 'restricted'
// Resource Group Parameters
param resourceGroupName = '${env}-sas-shared-infrastructure-rg'
// App Gateway Parameters
param appGatewayIdPredicate = '/subscriptions/${subscriptionId}/resourceGroups/
${resourceGroupName}/providers/Microsoft.Network/
applicationGateways/${appGatewayName}'
param appGatewayFrontendPorts = [
{
name: 'port_80'
id: '${appGatewayIdPredicate}/frontendPorts/port_80'
properties: {
port: 80
}
}
{
name: 'port_443'
id: '${appGatewayIdPredicate}/frontendPorts/port_443'
properties: {
port: 443
} . . .
© 2023 Princeton University OIT
main.bicep
29
// Create App Gateway
module appGateway ‘br:puoitabr.azurecr.io/network/app-gateway:v0.1' = {
dependsOn: [ common, publicIp, appGatewaySnet, appGatewayManagedIdentity]
scope: resourceGroup(resourceGroupName)
name: appGatewayName
params: {
appGatewayName: appGatewayName
appGatewayIdentityId: appGatewayManagedIdentity.outputs.id
location: location
tags: tags
sku: sku
autoscaleConfiguration: appGatewayAutoscaleConfiguration
publicIpAddressId: publicIp.outputs.id
gatewayIPConfigurationsName: appGatewayIPConfigurationsName
gatewayIPConfigurationsSnetId: appGatewaySnet.id
frontendIPConfigurationsName: appGatewayFrontendIPConfigurationsName
frontendPorts: appGatewayFrontendPorts
backendAddressPools: union(appGatewayBackendAddressPools, appGatewayBackendAddressPoolsTigerSpeed)
backendHttpSettingsCollection: union(appGatewayBackendHttpSettingsCollection,
appGatewayBackendHttpSettingsCollectionTigerSpeed)
httpsListeners: union(appGatewayHttpsListeners, appGatewayHttpsListenersTigerSpeed)
appGatewaySslCerts: union(appGatewaySslCerts, appGatewaySslCertsTigerSpeed)
urlPathMaps: union(appGatewayUrlPathMaps, appGatewayUrlPathMapsTigerSpeed)
requestRoutingRules: union(appGatewayRequestRoutingRules, appGatewayRequestRoutingRulesTigerSpeed)
probes: union(appGatewayProbes, appGatewayProbesTigerSpeed)
rewriteRuleSets: union(appGatewayRewriteRuleSets, appGatewayRewriteRuleSetsTigerSpeed)
}
}
Calling our local Bicep Registry
Referencing the Configuration
(sbx.bicepparam file)
© 2023 Princeton University OIT
30
env.bicepparam
In a nutshell
main.bicep
DevOps Trigger
Pipeline YAML
env.bicepparam
main.bicep
Microsoft Public Bicep Registry
Princeton Private Bicep Registry
Instantiated Azure Resources
common variables
YAML Templates
© 2023 Princeton University OIT
31
Take Aways
Infrastructure as Code
© 2023 Princeton University OIT
32
Take Aways
Coding Framework
© 2023 Princeton University OIT
33
Questions?
© 2023 Princeton University OIT