Skip to content

Commit

Permalink
Module Consumption Example
Browse files Browse the repository at this point in the history
Module consumption example code & readme.
  • Loading branch information
riosengineer committed Sep 29, 2023
1 parent 5b0eea1 commit ddb0dbd
Show file tree
Hide file tree
Showing 4 changed files with 388 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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
96 changes: 96 additions & 0 deletions bicep-examples/consuming-modules/README.md
Original file line number Diff line number Diff line change
@@ -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.
56 changes: 56 additions & 0 deletions bicep-examples/consuming-modules/modules.bicep
Original file line number Diff line number Diff line change
@@ -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'
}
}
224 changes: 224 additions & 0 deletions bicep-examples/consuming-modules/modules/inline/customModule.bicep
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit ddb0dbd

Please sign in to comment.