├── lesson-02 ├── install_azure_cli_windows.ps1 ├── install_azure_cli_mac.sh ├── install_azure_powershell_mac.sh └── install_azure_powershell_windows.ps1 ├── lesson-13 ├── bicepconfig.json ├── main.parameters.json ├── main.bicep └── modules │ ├── storage-account.bicep │ └── storage-role-assignments.bicep ├── lesson-06 ├── example.yml ├── nsg-security-rules.json ├── example.json └── main.bicep ├── lesson-09 ├── arm-ttk-commands.ps1 └── azure-pipeline.yml ├── lesson-04 ├── powershell.ps1 ├── commands.sh ├── main.bicep └── azure-pipeline.yml ├── lesson-05 ├── main.parameters.json ├── commands.sh ├── main.bicep └── data-types.bicep ├── lesson-07 ├── main.parameters.json ├── modules │ └── storage-account.bicep └── main.bicep ├── lesson-08 ├── main.parameters.json ├── modules │ ├── storage-role-assignments.bicep │ └── storage-account.bicep └── main.bicep ├── lesson-03 └── main.bicep ├── lesson-12 ├── modules │ ├── app-service-plan.bicep │ ├── application-insights.bicep │ ├── storage-account.bicep │ └── function-app.bicep ├── main.parameters.json ├── compute.bicep └── main.bicep └── README.md /lesson-02/install_azure_cli_windows.ps1: -------------------------------------------------------------------------------- 1 | 2 | # install the AzureCLI package 3 | winget install -e --id Microsoft.AzureCLI -------------------------------------------------------------------------------- /lesson-13/bicepconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "experimentalFeaturesEnabled": { 3 | "userDefinedTypes": true, 4 | "extensibility": true 5 | } 6 | } -------------------------------------------------------------------------------- /lesson-06/example.yml: -------------------------------------------------------------------------------- 1 | name: John Smith 2 | contact: 3 | home: 1012355532 4 | office: 5002586256 5 | address: 6 | street: 23 Tornado Alley 7 | -------------------------------------------------------------------------------- /lesson-02/install_azure_cli_mac.sh: -------------------------------------------------------------------------------- 1 | # install homebrew here https://brew.sh/ 2 | 3 | # install the azure-cli package 4 | brew update && brew install azure-cli -------------------------------------------------------------------------------- /lesson-09/arm-ttk-commands.ps1: -------------------------------------------------------------------------------- 1 | Test-AzTemplate -TemplatePath " 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /lesson-03/main.bicep: -------------------------------------------------------------------------------- 1 | 2 | resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { 3 | name: 'stbicepcoursedev' 4 | location: 'westeurope' 5 | sku: { 6 | name: 'Standard_LRS' 7 | } 8 | kind: 'StorageV2' 9 | properties: { 10 | minimumTlsVersion: 'TLS1_2' 11 | supportsHttpsTrafficOnly: true 12 | } 13 | } 14 | 15 | resource auditStorageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { 16 | name: 'stauditcoursedev' 17 | location: 'westeurope' 18 | sku: { 19 | name: 'Standard_LRS' 20 | } 21 | kind: 'StorageV2' 22 | properties: { 23 | minimumTlsVersion: 'TLS1_2' 24 | supportsHttpsTrafficOnly: true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lesson-04/main.bicep: -------------------------------------------------------------------------------- 1 | 2 | resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { 3 | name: 'stbicepcoursedev' 4 | location: 'westeurope' 5 | sku: { 6 | name: 'Standard_LRS' 7 | } 8 | kind: 'StorageV2' 9 | properties: { 10 | minimumTlsVersion: 'TLS1_2' 11 | supportsHttpsTrafficOnly: true 12 | } 13 | } 14 | 15 | resource auditStorageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { 16 | name: 'stauditcoursedev' 17 | location: 'westeurope' 18 | sku: { 19 | name: 'Standard_LRS' 20 | } 21 | kind: 'StorageV2' 22 | properties: { 23 | minimumTlsVersion: 'TLS1_2' 24 | supportsHttpsTrafficOnly: true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lesson-12/modules/app-service-plan.bicep: -------------------------------------------------------------------------------- 1 | 2 | @description('Location for the resources') 3 | param location string 4 | 5 | @description('Tags for all resources') 6 | param tags object = {} 7 | 8 | @description('The name of the app service plan resource') 9 | param appServicePlanName string 10 | 11 | @allowed([ 12 | 'S1' 13 | 'B1' 14 | ]) 15 | param appServicePlanSku string = 'B1' 16 | 17 | resource appServicePlan 'Microsoft.Web/serverfarms@2022-09-01' = { 18 | name: appServicePlanName 19 | location: location 20 | tags: tags 21 | sku: { 22 | name: appServicePlanSku 23 | } 24 | } 25 | 26 | output appServicePlanName string = appServicePlan.name 27 | output appServicePlanId string = appServicePlan.id 28 | -------------------------------------------------------------------------------- /lesson-12/modules/application-insights.bicep: -------------------------------------------------------------------------------- 1 | 2 | @description('Location for the resources') 3 | param location string 4 | 5 | @description('Tags for all resources') 6 | param tags object = {} 7 | 8 | @description('The name of the application insights resource') 9 | param applicationInsightsName string 10 | 11 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { 12 | name: applicationInsightsName 13 | tags: tags 14 | location: location 15 | kind: 'web' 16 | properties: { 17 | Application_Type: 'web' 18 | Request_Source: 'rest' 19 | } 20 | } 21 | 22 | output applicationInsightsName string = applicationInsights.name 23 | output applicationInsightsId string = applicationInsights.id 24 | -------------------------------------------------------------------------------- /lesson-04/azure-pipeline.yml: -------------------------------------------------------------------------------- 1 | 2 | trigger: 3 | - main 4 | 5 | pool: 6 | vmImage: ubuntu-latest 7 | 8 | jobs: 9 | 10 | - job: deploy_infra 11 | displayName: 'Deploy Infra' 12 | steps: 13 | 14 | - task: AzureResourceManagerTemplateDeployment@3 15 | displayName: 'Deploy main.bicep' 16 | inputs: 17 | deploymentScope: 'Resource Group' 18 | azureResourceManagerConnection: 19 | subscriptionId: 20 | action: 'Create Or Update Resource Group' 21 | resourceGroupName: 22 | location: 'West Europe' 23 | templateLocation: 'Linked artifact' 24 | csmFile: 'main.bicep' 25 | deploymentMode: 'Incremental' -------------------------------------------------------------------------------- /lesson-13/main.bicep: -------------------------------------------------------------------------------- 1 | @description('Location for the resources') 2 | param location string = resourceGroup().location 3 | 4 | type storageAccountSkuType = 'Standard_LRS' | 'Standard_GRS' 5 | 6 | type storageAccountConfigType = { 7 | @minLength(3) 8 | @maxLength(24) 9 | name: string 10 | sku: storageAccountSkuType 11 | } 12 | 13 | param storageAccountConfig storageAccountConfigType 14 | 15 | 16 | resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { 17 | name: storageAccountConfig.name 18 | location: location 19 | sku: { 20 | name: storageAccountConfig.sku 21 | } 22 | kind: 'StorageV2' 23 | properties: { 24 | minimumTlsVersion: 'TLS1_2' 25 | supportsHttpsTrafficOnly: true 26 | } 27 | } 28 | 29 | 30 | output storageAccountName string = storageAccount.name 31 | output storageAccountId string = storageAccount.id 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome! 2 | 3 | This is the helper repository for the [Master Azure Bicep: Explore Advanced Features and Techniques](https://www.udemy.com/course/master-azure-bicep) course on Udemy. 4 | 5 | This repository contains the solutions for each lesson. 6 | 7 | - **Lesson 1:** Introduction to Azure Bicep 8 | - **Lesson 2:** Setting up the environment 9 | - **Lesson 3:** Creating your first Azure Bicep template 10 | - **Lesson 4:** Deploying resources with Azure Bicep 11 | - **Lesson 5:** Variables, parameters and outputs 12 | - **Lesson 6:** Bicep functions 13 | - **Lesson 7:** Working with modules in Azure Bicep 14 | - **Lesson 8:** Advanced Bicep concepts (loops, conditional deployments, existing resources) 15 | - **Lesson 9:** Testing and validating Azure Bicep templates 16 | - **Lesson 12:** Real-world Project – deploying a function app with logging 17 | - **Lesson 13:** Preview features 18 | - **Lesson 14:** Review and Next Steps 19 | -------------------------------------------------------------------------------- /lesson-12/main.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "tags": { 6 | "value": { 7 | "environment": "dev", 8 | ***REMOVED*** 9 | } 10 | }, 11 | "storageAccountName": { 12 | "value": "stbicepcoursedev" 13 | }, 14 | "storageAccountSku": { 15 | "value": "Standard_LRS" 16 | }, 17 | "appServicePlanName": { 18 | "value": "app-bicep-course-dev" 19 | }, 20 | "appServicePlanSku": { 21 | "value": "B1" 22 | }, 23 | "functionAppName": { 24 | "value": "func-bicep-course-dev" 25 | }, 26 | "applicationInsightsName": { 27 | "value": "appi-bicep-course-dev" 28 | }, 29 | "apiKey": { 30 | "value": "secret-value" 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /lesson-05/main.bicep: -------------------------------------------------------------------------------- 1 | 2 | @description('Location for the resources') 3 | param location string = resourceGroup().location 4 | 5 | @minLength(3) 6 | @maxLength(24) 7 | @description('The name of the storage account') 8 | param storageAccountName string 9 | 10 | @description('Name of the SKU') 11 | @allowed([ 12 | 'Standard_GRS' 13 | 'Standard_LRS' 14 | ]) 15 | param storageAccountSku string 16 | 17 | @description('Restrict storage account to only HTTPS traffic') 18 | param supportsHttpsTrafficOnly bool = true 19 | 20 | var storageAccountKind = 'StorageV2' 21 | 22 | resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { 23 | name: storageAccountName 24 | location: location 25 | sku: { 26 | name: storageAccountSku 27 | } 28 | kind: storageAccountKind 29 | properties: { 30 | minimumTlsVersion: 'TLS1_2' 31 | supportsHttpsTrafficOnly: supportsHttpsTrafficOnly 32 | } 33 | } 34 | 35 | output storageAccountName string = storageAccount.name 36 | output storageAccountId string = storageAccount.id 37 | -------------------------------------------------------------------------------- /lesson-07/modules/storage-account.bicep: -------------------------------------------------------------------------------- 1 | 2 | @description('Location for the resources') 3 | param location string 4 | 5 | @minLength(3) 6 | @maxLength(24) 7 | @description('The name of the storage account') 8 | param storageAccountName string 9 | 10 | @description('Name of the SKU') 11 | @allowed([ 12 | 'Standard_GRS' 13 | 'Standard_LRS' 14 | ]) 15 | param storageAccountSku string = 'Standard_LRS' 16 | 17 | @description('The type of storage account') 18 | @allowed([ 19 | 'BlobStorage' 20 | 'BlockBlobStorage' 21 | 'FileStorage' 22 | 'StorageV2' 23 | ]) 24 | param storageAccountKind string = 'StorageV2' 25 | 26 | 27 | resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { 28 | name: storageAccountName 29 | location: location 30 | sku: { 31 | name: storageAccountSku 32 | } 33 | kind: storageAccountKind 34 | properties: { 35 | minimumTlsVersion: 'TLS1_2' 36 | supportsHttpsTrafficOnly: true 37 | } 38 | } 39 | 40 | output storageAccountName string = storageAccount.name 41 | output storageAccountId string = storageAccount.id 42 | -------------------------------------------------------------------------------- /lesson-08/modules/storage-role-assignments.bicep: -------------------------------------------------------------------------------- 1 | 2 | @description('Names of the storage account for role assignments') 3 | param storageAccountNames array 4 | 5 | @description('ID of the AD group for role assignment') 6 | param adGroupId string 7 | 8 | @description('ID of the RBAC role definition') 9 | param roleAssignmentId string 10 | 11 | resource role 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { 12 | name: roleAssignmentId 13 | } 14 | 15 | resource storageAccounts 'Microsoft.Storage/storageAccounts@2022-09-01' existing = [for storageAccountName in storageAccountNames: { 16 | name: storageAccountName 17 | }] 18 | 19 | // note - this module should assign one role assignment and the loop be handled in main.bicep 20 | // this was for demostration purposes of indexed loops 21 | resource storageAccountRoleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for i in range(0, length((storageAccountNames))): { 22 | name: guid(storageAccounts[i].name, role.id, adGroupId) 23 | scope: storageAccounts[i] 24 | properties: { 25 | roleDefinitionId: role.id 26 | principalId: adGroupId 27 | } 28 | }] 29 | -------------------------------------------------------------------------------- /lesson-05/data-types.bicep: -------------------------------------------------------------------------------- 1 | 2 | // secure parameters 3 | 4 | @secure() 5 | param password string 6 | 7 | // strings 8 | 9 | var exampleString = 'string-example' 10 | var exampleStringTwo = 'another-${exampleString}' 11 | var multilineString = ''' 12 | demo''' 13 | 14 | // integers 15 | 16 | var exampleInteger = 100323 17 | 18 | // booleans 19 | 20 | var exampleBoolean = true 21 | var exampleBooleanTwo = false 22 | 23 | // arrays 24 | 25 | var array = [ 26 | 'value1' 27 | 'value2' 28 | ] 29 | 30 | var arrayValue = array[0] 31 | 32 | var mixedArray = [ 33 | 'value1' 34 | 2 35 | 'value3' 36 | ] 37 | 38 | var joinedArray = union(array, mixedArray) 39 | 40 | // objects 41 | 42 | var object = { 43 | name: 'Dylan' 44 | number: 07812312312 45 | postcode: 'SE00000' 46 | } 47 | 48 | var tags = { 49 | environment: 'dev' 50 | owner: '***REMOVED***' 51 | } 52 | 53 | var environment = tags.environment 54 | 55 | var joinedObjects = union(object, tags) 56 | 57 | var storageAccountConfig = { 58 | sku: 'Standard_LRS' 59 | kind: 'StorageV2' 60 | } 61 | 62 | var nestedObject = { 63 | value: { 64 | value: 1 65 | } 66 | value2: [ 67 | 'value' 68 | ] 69 | } 70 | 71 | var nestedOjectValue = nestedObject.value2[0] 72 | -------------------------------------------------------------------------------- /lesson-07/main.bicep: -------------------------------------------------------------------------------- 1 | 2 | @description('Location for the resources') 3 | param location string = resourceGroup().location 4 | 5 | @minLength(3) 6 | @maxLength(23) 7 | @description('The name of the storage account') 8 | param storageAccountName string 9 | 10 | @minLength(3) 11 | @maxLength(24) 12 | @description('The name of the audit storage account') 13 | param auditStorageAccountName string 14 | 15 | @description('Name of the SKU') 16 | @allowed([ 17 | 'Standard_GRS' 18 | 'Standard_LRS' 19 | ]) 20 | param storageAccountSku string 21 | 22 | module storageAccount 'modules/storage-account.bicep' = { 23 | name: storageAccountName 24 | params: { 25 | location: location 26 | storageAccountName: storageAccountName 27 | storageAccountSku: storageAccountSku 28 | } 29 | } 30 | 31 | module auditStorageAccount 'modules/storage-account.bicep' = { 32 | name: auditStorageAccountName 33 | params: { 34 | location: location 35 | storageAccountName: auditStorageAccountName 36 | storageAccountSku: storageAccountSku 37 | } 38 | } 39 | 40 | output storageAccountName string = storageAccount.outputs.storageAccountName 41 | output storageAccountId string = storageAccount.outputs.storageAccountId 42 | 43 | output auditStorageAccountName string = auditStorageAccount.outputs.storageAccountName 44 | output auditStorageAccountId string = auditStorageAccount.outputs.storageAccountId 45 | -------------------------------------------------------------------------------- /lesson-09/azure-pipeline.yml: -------------------------------------------------------------------------------- 1 | 2 | trigger: 3 | - main 4 | 5 | pool: 6 | vmImage: ubuntu-latest 7 | 8 | jobs: 9 | 10 | - job: validate_infra 11 | displayName: 'Validate Infra' 12 | steps: 13 | 14 | - task: AzureResourceManagerTemplateDeployment@3 15 | displayName: 'Validate main.bicep' 16 | inputs: 17 | deploymentScope: 'Resource Group' 18 | azureResourceManagerConnection: 19 | subscriptionId: 20 | action: 'Create Or Update Resource Group' 21 | resourceGroupName: 22 | location: 'West Europe' 23 | templateLocation: 'Linked artifact' 24 | csmFile: 'main.bicep' 25 | deploymentMode: 'Validation' 26 | 27 | - job: deploy_infra 28 | displayName: 'Deploy Infra' 29 | dependsOn: validate_infra 30 | steps: 31 | 32 | - task: AzureResourceManagerTemplateDeployment@3 33 | displayName: 'Deploy main.bicep' 34 | inputs: 35 | deploymentScope: 'Resource Group' 36 | azureResourceManagerConnection: 37 | subscriptionId: 38 | action: 'Create Or Update Resource Group' 39 | resourceGroupName: 40 | location: 'West Europe' 41 | templateLocation: 'Linked artifact' 42 | csmFile: 'main.bicep' 43 | deploymentMode: 'Incremental' -------------------------------------------------------------------------------- /lesson-08/modules/storage-account.bicep: -------------------------------------------------------------------------------- 1 | 2 | @description('Location for the resources') 3 | param location string 4 | 5 | @minLength(3) 6 | @maxLength(24) 7 | @description('The name of the storage account') 8 | param storageAccountName string 9 | 10 | @description('Name of the SKU') 11 | @allowed([ 12 | 'Standard_GRS' 13 | 'Standard_LRS' 14 | ]) 15 | param storageAccountSku string = 'Standard_LRS' 16 | 17 | @description('The type of storage account') 18 | @allowed([ 19 | 'BlobStorage' 20 | 'BlockBlobStorage' 21 | 'FileStorage' 22 | 'StorageV2' 23 | ]) 24 | param storageAccountKind string = 'StorageV2' 25 | 26 | @description('The names of containers for creation') 27 | param containerNames array = [] 28 | 29 | 30 | resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { 31 | name: storageAccountName 32 | location: location 33 | sku: { 34 | name: storageAccountSku 35 | } 36 | kind: storageAccountKind 37 | properties: { 38 | minimumTlsVersion: 'TLS1_2' 39 | supportsHttpsTrafficOnly: true 40 | } 41 | } 42 | 43 | resource blobServices 'Microsoft.Storage/storageAccounts/blobServices@2021-02-01' = { 44 | name: 'default' 45 | parent: storageAccount 46 | } 47 | 48 | resource containers 'Microsoft.Storage/storageAccounts/blobServices/containers@2021-02-01' = [ for containerName in containerNames : { 49 | name: containerName 50 | parent: blobServices 51 | properties: { 52 | publicAccess: 'None' 53 | } 54 | }] 55 | 56 | output storageAccountName string = storageAccount.name 57 | output storageAccountId string = storageAccount.id 58 | -------------------------------------------------------------------------------- /lesson-13/modules/storage-account.bicep: -------------------------------------------------------------------------------- 1 | 2 | @description('Location for the resources') 3 | param location string 4 | 5 | @minLength(3) 6 | @maxLength(24) 7 | @description('The name of the storage account') 8 | param storageAccountName string 9 | 10 | @description('Name of the SKU') 11 | @allowed([ 12 | 'Standard_GRS' 13 | 'Standard_LRS' 14 | ]) 15 | param storageAccountSku string = 'Standard_LRS' 16 | 17 | @description('The type of storage account') 18 | @allowed([ 19 | 'BlobStorage' 20 | 'BlockBlobStorage' 21 | 'FileStorage' 22 | 'StorageV2' 23 | ]) 24 | param storageAccountKind string = 'StorageV2' 25 | 26 | @description('The names of containers for creation') 27 | param containerNames array = [] 28 | 29 | 30 | resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { 31 | name: storageAccountName 32 | location: location 33 | sku: { 34 | name: storageAccountSku 35 | } 36 | kind: storageAccountKind 37 | properties: { 38 | minimumTlsVersion: 'TLS1_2' 39 | supportsHttpsTrafficOnly: true 40 | } 41 | } 42 | 43 | resource blobServices 'Microsoft.Storage/storageAccounts/blobServices@2021-02-01' = { 44 | name: 'default' 45 | parent: storageAccount 46 | } 47 | 48 | resource containers 'Microsoft.Storage/storageAccounts/blobServices/containers@2021-02-01' = [ for containerName in containerNames : { 49 | name: containerName 50 | parent: blobServices 51 | properties: { 52 | publicAccess: 'None' 53 | } 54 | }] 55 | 56 | output storageAccountName string = storageAccount.name 57 | output storageAccountId string = storageAccount.id 58 | -------------------------------------------------------------------------------- /lesson-13/modules/storage-role-assignments.bicep: -------------------------------------------------------------------------------- 1 | 2 | // Test this module 3 | 4 | // TODO make this a module for RBAC and give the role ID into it 5 | 6 | @description('Names of the storage account for role assignments') 7 | param storageAccountNames array 8 | 9 | @description('ID of the AD group for role assignment') 10 | param adGroupId string 11 | 12 | @description('ID of the RBAC role definition') 13 | param roleAssignmentId string 14 | 15 | resource role 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { 16 | name: roleAssignmentId 17 | } 18 | 19 | // var storageBlobDataReader2 = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1') 20 | 21 | resource storageAccounts 'Microsoft.Storage/storageAccounts@2022-09-01' existing = [for storageAccountName in storageAccountNames: { 22 | name: storageAccountName 23 | }] 24 | 25 | // use an object with account name and role mapping? 26 | 27 | // firstly try loop over the array of existing accounts, show them the error 28 | 29 | // resource storageAccountRoleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for storageAccount in storageAccounts: { 30 | // name: storageAccount.name 31 | // scope: storageAccount 32 | // properties: { 33 | // roleDefinitionId: storageBlobDataReader.id 34 | // principalId: adGroupPrincipalId 35 | // } 36 | // }] 37 | 38 | resource storageAccountRoleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for i in range(0, length((storageAccountNames))): { 39 | name: guid(storageAccounts[i].name, role.id, adGroupId) 40 | scope: storageAccounts[i] 41 | properties: { 42 | roleDefinitionId: role.id 43 | principalId: adGroupId 44 | } 45 | }] 46 | 47 | // keyvault secrets? 48 | 49 | -------------------------------------------------------------------------------- /lesson-12/compute.bicep: -------------------------------------------------------------------------------- 1 | @description('Location for the resources') 2 | param location string 3 | 4 | @description('Tags for all resources') 5 | param tags object = {} 6 | 7 | @minLength(3) 8 | @maxLength(24) 9 | @description('The name of the storage account') 10 | param storageAccountName string 11 | 12 | @description('The name of our function app resource') 13 | param functionAppName string 14 | 15 | @description('The name of the app service plan resource') 16 | param appServicePlanName string 17 | 18 | @description('The name of the application insights resource') 19 | param applicationInsightsName string 20 | 21 | @allowed([ 22 | 'S1' 23 | 'B1' 24 | ]) 25 | param appServicePlanSku string 26 | 27 | @secure() 28 | @description('API key for our really interesting API') 29 | param apiKey string 30 | 31 | module appServicePlan 'modules/app-service-plan.bicep' = { 32 | name: 'deploy-${appServicePlanName}' 33 | params: { 34 | appServicePlanName: appServicePlanName 35 | location: location 36 | appServicePlanSku: appServicePlanSku 37 | } 38 | } 39 | 40 | module functionApp 'modules/function-app.bicep' = { 41 | name: 'deploy-${functionAppName}' 42 | params: { 43 | appServicePlanName: appServicePlanName 44 | appSettings: [ 45 | { 46 | name: 'ApiKey' 47 | value: apiKey 48 | } 49 | ] 50 | applicationInsightsName: applicationInsightsName 51 | functionAppName: functionAppName 52 | storageAccountName: storageAccountName 53 | location: location 54 | tags: tags 55 | } 56 | } 57 | 58 | output appServicePlanName string = appServicePlan.outputs.appServicePlanName 59 | output appServicePlanId string = appServicePlan.outputs.appServicePlanId 60 | output functionAppName string = functionApp.outputs.functionAppName 61 | output functionAppId string = functionApp.outputs.functionAppId 62 | -------------------------------------------------------------------------------- /lesson-12/modules/storage-account.bicep: -------------------------------------------------------------------------------- 1 | 2 | 3 | @description('Location for the resources') 4 | param location string 5 | 6 | @description('Tags for all resources') 7 | param tags object = {} 8 | 9 | @minLength(3) 10 | @maxLength(24) 11 | @description('The name of the storage account') 12 | param storageAccountName string 13 | 14 | @description('Name of the SKU') 15 | @allowed([ 16 | 'Standard_GRS' 17 | 'Standard_LRS' 18 | ]) 19 | param storageAccountSku string = 'Standard_LRS' 20 | 21 | @description('The type of storage account') 22 | @allowed([ 23 | 'BlobStorage' 24 | 'StorageV2' 25 | ]) 26 | param storageAccountKind string = 'StorageV2' 27 | 28 | @description('Set storage account SFTP enabled') 29 | param isSftpEnabled bool = false 30 | 31 | @description('The names of containers for creation') 32 | param containerNames array = [] 33 | 34 | 35 | resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { 36 | name: storageAccountName 37 | location: location 38 | tags: tags 39 | sku: { 40 | name: storageAccountSku 41 | } 42 | kind: storageAccountKind 43 | properties: { 44 | minimumTlsVersion: 'TLS1_2' 45 | supportsHttpsTrafficOnly: true 46 | isSftpEnabled: isSftpEnabled 47 | isHnsEnabled: isSftpEnabled ? true : false 48 | } 49 | } 50 | 51 | resource blobServices 'Microsoft.Storage/storageAccounts/blobServices@2021-02-01' = if(!empty(containerNames)) { 52 | name: 'default' 53 | parent: storageAccount 54 | } 55 | 56 | resource containers 'Microsoft.Storage/storageAccounts/blobServices/containers@2021-02-01' = [ for containerName in containerNames : { 57 | name: containerName 58 | parent: blobServices 59 | properties: { 60 | publicAccess: 'None' 61 | } 62 | }] 63 | 64 | output storageAccountName string = storageAccount.name 65 | output storageAccountId string = storageAccount.id 66 | -------------------------------------------------------------------------------- /lesson-12/modules/function-app.bicep: -------------------------------------------------------------------------------- 1 | 2 | @description('Location for the resources') 3 | param location string 4 | 5 | @description('Tags for all resources') 6 | param tags object = {} 7 | 8 | @description('The name of our function app resource') 9 | param functionAppName string 10 | 11 | @description('The name of the app service plan resource') 12 | param appServicePlanName string 13 | 14 | @minLength(3) 15 | @maxLength(24) 16 | @description('The name of the storage account') 17 | param storageAccountName string 18 | 19 | @description('The name of the application insights resource') 20 | param applicationInsightsName string 21 | 22 | @description('App settings for the function app') 23 | param appSettings array 24 | 25 | 26 | resource appServicePlan 'Microsoft.Web/serverfarms@2022-09-01' existing = { 27 | name: appServicePlanName 28 | } 29 | 30 | resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' existing = { 31 | name: storageAccountName 32 | } 33 | 34 | resource appInsights 'Microsoft.Insights/components@2020-02-02' existing = { 35 | name: applicationInsightsName 36 | } 37 | 38 | 39 | var storageAccountConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}' 40 | 41 | var requiredAppSettings = [ 42 | { 43 | name: 'AzureWebJobsStorage' 44 | value: storageAccountConnectionString 45 | } 46 | { 47 | name: 'APPINSIGHTS_INSTRUMENTATIONKEY' 48 | value: appInsights.properties.InstrumentationKey 49 | } 50 | { 51 | name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' 52 | value: appInsights.properties.ConnectionString 53 | } 54 | { 55 | name: 'FUNCTIONS_EXTENSION_VERSION' 56 | value: '~4' 57 | } 58 | { 59 | name: 'FUNCTIONS_WORKER_RUNTIME' 60 | value: 'dotnet' 61 | } 62 | ] 63 | 64 | resource functionApp 'Microsoft.Web/sites@2022-09-01' = { 65 | name: functionAppName 66 | location: location 67 | tags: tags 68 | kind: 'functionapp' 69 | identity: { 70 | type: 'SystemAssigned' 71 | } 72 | properties: { 73 | serverFarmId: appServicePlan.id 74 | httpsOnly: true 75 | siteConfig: { 76 | windowsFxVersion: 'DOTNETCORE|LTS' 77 | alwaysOn: true 78 | appSettings: union(appSettings, requiredAppSettings) 79 | } 80 | } 81 | } 82 | 83 | output functionAppName string = functionApp.name 84 | output functionAppId string = functionApp.id 85 | -------------------------------------------------------------------------------- /lesson-08/main.bicep: -------------------------------------------------------------------------------- 1 | @description('Location for the resources') 2 | param location string = resourceGroup().location 3 | 4 | @minLength(3) 5 | @maxLength(24) 6 | @description('The name of the storage account') 7 | param storageAccountName string 8 | 9 | @minLength(3) 10 | @maxLength(24) 11 | @description('The name of the audit storage account') 12 | param auditStorageAccountName string 13 | 14 | @description('Name of the SKU') 15 | @allowed([ 16 | 'Standard_GRS' 17 | 'Standard_LRS' 18 | ]) 19 | param storageAccountSku string 20 | 21 | @description('ID of the AD group for role assignment') 22 | param adGroupId string 23 | 24 | @description('Deploy the audit storage account') 25 | param deployAuditStorageAccount bool = true 26 | 27 | @description('Deploy the audit storage account containers') 28 | param deployAuditStorageContainers bool = true 29 | 30 | 31 | var storageBlobDataReaderId = '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' 32 | 33 | var auditStorageContainers = [ 34 | 'audit' 35 | 'logs' 36 | ] 37 | 38 | resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { 39 | name: storageAccountName 40 | location: location 41 | sku: { 42 | name: storageAccountSku 43 | } 44 | kind: 'StorageV2' 45 | properties: { 46 | minimumTlsVersion: 'TLS1_2' 47 | supportsHttpsTrafficOnly: true 48 | } 49 | } 50 | 51 | module auditStorageAccount 'modules/storage-account.bicep' = if (deployAuditStorageAccount) { 52 | name: auditStorageAccountName 53 | params: { 54 | location: location 55 | storageAccountName: auditStorageAccountName 56 | storageAccountSku: storageAccountSku 57 | containerNames: deployAuditStorageContainers ? auditStorageContainers : [] 58 | } 59 | } 60 | 61 | var storageAccountNames = deployAuditStorageAccount ? [ 62 | storageAccount.name 63 | auditStorageAccount.outputs.storageAccountName 64 | ] : [ 65 | storageAccount.name 66 | ] 67 | 68 | module roleAssignments 'modules/storage-role-assignments.bicep' = { 69 | name: 'storage-role-assignments' 70 | params: { 71 | adGroupId: adGroupId 72 | roleAssignmentId: storageBlobDataReaderId 73 | storageAccountNames: storageAccountNames 74 | } 75 | } 76 | 77 | output storageAccountName string = storageAccount.name 78 | output storageAccountId string = storageAccount.id 79 | 80 | output auditStorageAccountName string = auditStorageAccount.outputs.storageAccountName 81 | output auditStorageAccountId string = auditStorageAccount.outputs.storageAccountId 82 | -------------------------------------------------------------------------------- /lesson-12/main.bicep: -------------------------------------------------------------------------------- 1 | 2 | @description('Location for the resources') 3 | param location string = resourceGroup().location 4 | 5 | @description('Tags for all resources') 6 | param tags object = {} 7 | 8 | @minLength(3) 9 | @maxLength(24) 10 | @description('The name of the storage account') 11 | param storageAccountName string 12 | 13 | @minLength(3) 14 | @maxLength(24) 15 | @description('The name of the SFTP storage account') 16 | param sftpStorageAccountName string 17 | 18 | @description('The name of the application insights resource') 19 | param applicationInsightsName string 20 | 21 | @description('The name of the app service plan resource') 22 | param appServicePlanName string 23 | 24 | @description('The name of our function app resource') 25 | param functionAppName string 26 | 27 | @description('Name of the SKU') 28 | @allowed([ 29 | 'Standard_GRS' 30 | 'Standard_LRS' 31 | ]) 32 | param storageAccountSku string 33 | 34 | @allowed([ 35 | 'S1' 36 | 'B1' 37 | ]) 38 | param appServicePlanSku string = 'B1' 39 | 40 | @secure() 41 | @description('API key for our really interesting API') 42 | param apiKey string 43 | 44 | 45 | module storageAccount 'modules/storage-account.bicep' = { 46 | name: 'deploy-${storageAccountName}' 47 | params: { 48 | location: location 49 | tags: tags 50 | storageAccountName: storageAccountName 51 | storageAccountSku: storageAccountSku 52 | } 53 | } 54 | 55 | module sftpStorageAccount 'modules/storage-account.bicep' = { 56 | name: 'deploy-${sftpStorageAccountName}' 57 | params: { 58 | location: location 59 | tags: tags 60 | storageAccountName: sftpStorageAccountName 61 | storageAccountSku: storageAccountSku 62 | isSftpEnabled: true 63 | } 64 | } 65 | 66 | module applicationInsights 'modules/application-insights.bicep' = { 67 | name: 'deploy-${applicationInsightsName}' 68 | params: { 69 | applicationInsightsName: applicationInsightsName 70 | location: location 71 | tags: tags 72 | } 73 | } 74 | 75 | module compute 'compute.bicep' = { 76 | name: 'deploy-compute' 77 | params: { 78 | apiKey: apiKey 79 | applicationInsightsName: applicationInsightsName 80 | appServicePlanName: appServicePlanName 81 | functionAppName: functionAppName 82 | appServicePlanSku: appServicePlanSku 83 | location: location 84 | storageAccountName: storageAccountName 85 | tags: tags 86 | } 87 | } 88 | 89 | 90 | output storageAccountName string = storageAccount.outputs.storageAccountName 91 | output applicationInsightsName string = applicationInsights.outputs.applicationInsightsName 92 | output appServicePlanName string = compute.outputs.appServicePlanName 93 | output functionAppName string = compute.outputs.functionAppName 94 | -------------------------------------------------------------------------------- /lesson-06/main.bicep: -------------------------------------------------------------------------------- 1 | 2 | var storageAccountName = 'stbicepcoursedev' 3 | 4 | // scope functions 5 | 6 | var resourceGroupId = resourceGroup().id 7 | var resourceGroupName = resourceGroup().name 8 | var subscriptionName = subscription().displayName 9 | 10 | // resource functions 11 | 12 | var storageAccountId = resourceId('Microsoft.Storage/storageAccounts@2022-09-01', storageAccountName) 13 | 14 | var storageAccount = reference('Microsoft.Storage/storageAccounts@2022-09-01', storageAccountName) 15 | var storageAccountKey = storageAccount.listKeys().keys[0] 16 | var storageAccountPrincipalId = storageAccount.identity.principalId 17 | 18 | var resource = reference('Microsoft.KeyVault', 'kvbicepcoursedev') 19 | var secret = resource.getSecret('secretname') 20 | 21 | // guid functions 22 | 23 | var hashedGuid = guid(resourceGroup().id, storageAccountName) 24 | 25 | // array functions 26 | 27 | var array = [ 28 | 'value1' 29 | 'value2' 30 | ] 31 | 32 | var generatedArray = sys.array(resourceGroupId) 33 | 34 | var joinedArray = concat(array, generatedArray) 35 | var joinedArray2 = union(array, generatedArray) // duplicates ignored 36 | 37 | var firstElement = first(array) 38 | var lastElement = last(array) 39 | 40 | var arrayContains = contains(array, 'value1') 41 | var indexOf = contains(array, 'value1') //-1 if not found 42 | var arrayLength = length(array) 43 | var isArrayEmpty = empty(array) 44 | 45 | // data types conversions 46 | 47 | var boolean = bool('true') 48 | var integer = int('200') 49 | var stringg = string(2) 50 | 51 | // string functions 52 | 53 | var myFirstString = 'mystring${storageAccountName}' 54 | var joinedString = join(array, '-') 55 | var splitString = split(joinedString, '-') 56 | var lowerCase = toLower('HELLO') 57 | var upperCase = toUpper('hello') 58 | var trimmed = trim(' hello ') 59 | var substr = substring(trimmed, 0, 2) 60 | 61 | // numeric functions 62 | 63 | var numArray = [ 64 | 58 65 | 521 66 | 3 67 | ] 68 | 69 | var minimum = min(numArray) 70 | var maximum = max(numArray) 71 | 72 | // loading json files 73 | 74 | var nsgconfig = loadJsonContent('nsg-security-rules.json') 75 | 76 | resource newNSG 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { 77 | name: 'example-nsg' 78 | location: resourceGroup().location 79 | properties: { 80 | securityRules: [ 81 | { 82 | name: 'SSH' 83 | properties: nsgconfig 84 | } 85 | ] 86 | } 87 | } 88 | 89 | // loading yaml files 90 | 91 | var yml = loadYamlContent('example.yml') 92 | 93 | // loading text file functions 94 | 95 | var text = loadTextContent('nsg-security-rules.json') 96 | 97 | // loading files as base64 98 | 99 | var base64 = loadFileAsBase64('nsg-security-rules.json') 100 | 101 | // date functions 102 | 103 | param dateTime string = utcNow('u') 104 | var addNineDays = dateTimeAdd(dateTime, '+P9D') 105 | 106 | param convertedEpoch int = dateTimeToEpoch(dateTimeAdd(utcNow(), 'P1Y')) 107 | var convertedDatetime = dateTimeFromEpoch(convertedEpoch) 108 | 109 | // lambda functions 110 | 111 | var storageAccounts = loadJsonContent('example.json').storageAccounts 112 | 113 | output filteredStorageAccounts array = filter(storageAccounts, storageAccount => storageAccount.sku == 'Standard_GRS') 114 | 115 | output storageAccountNames array = map(storageAccounts, storageAccount => storageAccount.name) 116 | 117 | output storageAccountObject object = toObject(storageAccounts, storageAccount => storageAccount.name, storageAccount => storageAccount) 118 | --------------------------------------------------------------------------------