diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5194d54 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +### VisualStudioCode ### +.vscode/* +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide \ No newline at end of file diff --git a/bicep-examples/consuming-modules/README.md b/bicep-examples/consuming-modules/README.md new file mode 100644 index 0000000..c514cf2 --- /dev/null +++ b/bicep-examples/consuming-modules/README.md @@ -0,0 +1,96 @@ +# Consuming Bicep Modules - What are my options? + +## [Blog post](https://rios.engineer/consuming-bicep-modules-what-are-my-options/) + +## Introduction + +If you're new to Bicep understanding the different ways to consume modules can be beneficial to accelerating your adoption. This example will showcase the different methods, the benefits and why taking a combination approach can be desirable. + +Please review the blog post to get an understanding on the pros & cons of each consumption method. These are based on real world experiences using all methods, straight from the battlefield. + +## Public Bicep Registry + +The public registry can be consumed directly from anywhere with ease and has quick adoption with no start up overhead as the modules are centrally stored by the team. + +```javascript +module public_registry 'br/public:compute/function-app:2.0.1' = { + name: 'public_registry_example' + params: { + name: 'example-func-001' + location: 'uksouth' + storageAccountName: 'stsomestorageaccount001' + storageAccountResourceGroup: 'rg-some-rg-here' + } +} +``` + +## Prviate Registry + +Creating your own Azure Container Registry can be a great way to consume Bicep modules for internal use only. + +This may be required if you have heavy customisations, want central control and standards for your teams to use. However, it comes with much larger overhead for maintenance and versioning, communication and updates are key to keep up with the pace of Azure! + +Example (the Azure URI is just for illustration purposes): + +```javascript +module private_registry 'br:crbicepprod.azurecr.io/bicep/modules/logging:2023-09-29' = { + name: 'private_registry_example' + params: { + parLogAnalyticsWorkspaceLocation: 'uksouth' + parAutomationAccountLocation: 'uksouth' + parLogAnalyticsWorkspaceName: 'example-uks-ala-prod' + parLogAnalyticsWorkspaceSkuName: 'PerGB2018' + parLogAnalyticsWorkspaceSolutions: [ + 'AgentHealthAssessment' + 'AntiMalware' + 'ChangeTracking' + 'Security' + 'SecurityInsights' + 'SQLAdvancedThreatProtection' + 'SQLVulnerabilityAssessment' + 'SQLAssessment' + 'Updates' + 'VMInsights' + ] + parAutomationAccountName: 'example-uks-aa-prod' + parAutomationAccountUseManagedIdentity: true + parTelemetryOptOut: false + parTags: { + Env: 'Example' + } + } +} +``` + +## Inline Bicep Modules + +Lastly, consuming modules locally is another approach. This method is great for getting started, it's easy to see how everything flows together (visually at least) and enables you to customise modules. + +With this method you can write your own modules within a `\modules` folder and call on them in your `main.bicep` to load in. + +The benefit here is customisation, flexibility & you can take advantage of [CARML (Common Azure Resource Library)](https://github.com/Azure/ResourceModules) where a lot of the Azure Bicep coding has been done for you, copying the modules to the modules folder gives you a lot of deployment velocity straight away, with minimal startup overhead. + +```javascript +// Rios Engineer - Inline Bicep Module Example +module inline_module 'modules/inline/customModule.bicep' = { + name: 'inline_module_example' + params:{ + location: 'uksouth' + tags: { + Env: 'Example' + } + storageName: 'stsomestoragename001' + storagePleBlobName: 'someblobname' + storagePleFileName: 'somefilename' + storageSkuName: 'Standard_LRS' + subnetId: 'subnetId' + virtualNetworkId: 'vnetId' + } +} +``` + +## Azure Verified Modules + +[AVM](https://azure.github.io/Azure-Verified-Modules/faq/#what-is-happening-to-existing-initiatives-like-carml-and-tfvm) + +This is still in development at the time of writing. However, there is a new initiative by the IaC teams at Microsoft to present what good Infrastructure-as-Code looks like. The idea here will be these modules will accelerate teams to deploy with Bicep, using best practice & aligned to the Well-Architected Framework. diff --git a/bicep-examples/consuming-modules/modules.bicep b/bicep-examples/consuming-modules/modules.bicep new file mode 100644 index 0000000..5d11c41 --- /dev/null +++ b/bicep-examples/consuming-modules/modules.bicep @@ -0,0 +1,56 @@ +// Rios Engineer - Public Bicep Registry Example +module public_registry 'br/public:compute/function-app:2.0.1' = { + name: 'public_registry_example' + params: { + name: 'example-func-001' + location: 'uksouth' + storageAccountName: 'stsomestorageaccount001' + storageAccountResourceGroup: 'rg-some-rg-here' + } +} + +// Rios Engineer - Private Bicep Registry Example +module private_registry 'br:crbicepprod.azurecr.io/bicep/modules/logging:2023-09-29' = { + name: 'private_registry_example' + params: { + parLogAnalyticsWorkspaceLocation: 'uksouth' + parAutomationAccountLocation: 'uksouth' + parLogAnalyticsWorkspaceName: 'example-uks-ala-prod' + parLogAnalyticsWorkspaceSkuName: 'PerGB2018' + parLogAnalyticsWorkspaceSolutions: [ + 'AgentHealthAssessment' + 'AntiMalware' + 'ChangeTracking' + 'Security' + 'SecurityInsights' + 'SQLAdvancedThreatProtection' + 'SQLVulnerabilityAssessment' + 'SQLAssessment' + 'Updates' + 'VMInsights' + ] + parAutomationAccountName: 'example-uks-aa-prod' + parAutomationAccountUseManagedIdentity: true + parTelemetryOptOut: false + parTags: { + Env: 'Example' + } + } +} + +// Rios Engineer - Inline Bicep Module Example +module inline_module 'modules/inline/customModule.bicep' = { + name: 'inline_module_example' + params:{ + location: 'uksouth' + tags: { + Env: 'Example' + } + storageName: 'stsomestoragename001' + storagePleBlobName: 'someblobname' + storagePleFileName: 'somefilename' + storageSkuName: 'Standard_LRS' + subnetId: 'subnetId' + virtualNetworkId: 'vnetId' + } +} diff --git a/bicep-examples/consuming-modules/modules/inline/customModule.bicep b/bicep-examples/consuming-modules/modules/inline/customModule.bicep new file mode 100644 index 0000000..9508229 --- /dev/null +++ b/bicep-examples/consuming-modules/modules/inline/customModule.bicep @@ -0,0 +1,224 @@ +targetScope = 'resourceGroup' + +// Creates a storage account, private endpoints and DNS zones +@description('Azure region of the deployment') +param location string + +@description('Tags to add to the resources') +param tags object + +@description('Name of the storage account') +param storageName string + +@description('Name of the storage blob private link endpoint') +param storagePleBlobName string + +@description('Name of the storage file private link endpoint') +param storagePleFileName string + +@description('Resource ID of the subnet') +param subnetId string + +@description('Resource ID of the virtual network') +param virtualNetworkId string + +@allowed([ + 'Standard_LRS' + 'Standard_ZRS' + 'Standard_GRS' + 'Standard_GZRS' + 'Standard_RAGRS' + 'Standard_RAGZRS' + 'Premium_LRS' + 'Premium_ZRS' +]) + +@description('Storage SKU') +param storageSkuName string + +var storageNameCleaned = replace(storageName, '-', '') + +var blobPrivateDnsZoneName = 'privatelink.blob.${environment().suffixes.storage}' + +var filePrivateDnsZoneName = 'privatelink.file.${environment().suffixes.storage}' + +resource storage 'Microsoft.Storage/storageAccounts@2021-09-01' = { + name: storageNameCleaned + location: location + tags: tags + sku: { + name: storageSkuName + } + kind: 'StorageV2' + properties: { + accessTier: 'Hot' + allowBlobPublicAccess: false + allowCrossTenantReplication: false + allowSharedKeyAccess: true + encryption: { + keySource: 'Microsoft.Storage' + requireInfrastructureEncryption: false + services: { + blob: { + enabled: true + keyType: 'Account' + } + file: { + enabled: true + keyType: 'Account' + } + queue: { + enabled: true + keyType: 'Service' + } + table: { + enabled: true + keyType: 'Service' + } + } + } + isHnsEnabled: false + isNfsV3Enabled: false + keyPolicy: { + keyExpirationPeriodInDays: 7 + } + largeFileSharesState: 'Disabled' + minimumTlsVersion: 'TLS1_2' + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + } + supportsHttpsTrafficOnly: true + } +} + +resource storage_blob 'Microsoft.Storage/storageAccounts/blobServices@2021-04-01' = { + name: 'default' + parent: storage + properties: { + deleteRetentionPolicy: { + enabled: true + days: 7 + } + containerDeleteRetentionPolicy: { + enabled: true + days: 7 + } + } +} + +resource storagePrivateEndpointBlob 'Microsoft.Network/privateEndpoints@2022-01-01' = { + name: storagePleBlobName + location: location + tags: tags + properties: { + privateLinkServiceConnections: [ + { + name: storagePleBlobName + properties: { + groupIds: [ + 'blob' + ] + privateLinkServiceId: storage.id + privateLinkServiceConnectionState: { + status: 'Approved' + description: 'Auto-Approved' + actionsRequired: 'None' + } + } + } + ] + subnet: { + id: subnetId + } + } +} + +resource storagePrivateEndpointFile 'Microsoft.Network/privateEndpoints@2022-01-01' = { + name: storagePleFileName + location: location + tags: tags + properties: { + privateLinkServiceConnections: [ + { + name: storagePleFileName + properties: { + groupIds: [ + 'file' + ] + privateLinkServiceId: storage.id + privateLinkServiceConnectionState: { + status: 'Approved' + description: 'Auto-Approved' + actionsRequired: 'None' + } + } + } + ] + subnet: { + id: subnetId + } + } +} + +resource blobPrivateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: blobPrivateDnsZoneName + location: 'global' +} + +resource privateEndpointDns 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2022-01-01' = { + name: '${storagePrivateEndpointBlob.name}/blob-PrivateDnsZoneGroup' + properties:{ + privateDnsZoneConfigs: [ + { + name: blobPrivateDnsZoneName + properties:{ + privateDnsZoneId: blobPrivateDnsZone.id + } + } + ] + } +} + +resource blobPrivateDnsZoneVnetLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { + name: '${blobPrivateDnsZone.name}/${uniqueString(storage.id)}' + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: virtualNetworkId + } + } +} + +resource filePrivateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: filePrivateDnsZoneName + location: 'global' +} + +resource filePrivateEndpointDns 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2022-01-01' = { + name: '${storagePrivateEndpointFile.name}/flie-PrivateDnsZoneGroup' + properties:{ + privateDnsZoneConfigs: [ + { + name: filePrivateDnsZoneName + properties:{ + privateDnsZoneId: filePrivateDnsZone.id + } + } + ] + } +} + +resource filePrivateDnsZoneVnetLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { + name: '${filePrivateDnsZone.name}/${uniqueString(storage.id)}' + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: virtualNetworkId + } + } +} + +output storageId string = storage.id