Building Azure Bicep Reusable Components with Private Registry

In this article, we are going to learn how to reuse the Bicep Infrastructure as Code with your team and other teams across the Organization.

Introduction

Azure Bicep is a Domain Specific Language (DSL) for deploying Azure resources declaratively. It provides concise syntax and a high-level abstraction over Azure Resource Manager (ARM) templates. Reusability in the Bicep can be achieved through modules.

Example of a Module used in one Business Unit

A Module in Bicep is a reusable component that can take inputs as Bicep Parameters; it does the job and finally can return Output values

Let’s say, you are part of a Business Unit and you are responsible for developing Re-usable Bicep Components that could be used within your Business Unit (say BU1).

Bicep module

As shown above, you create the below three Bicep Modules (they are just .bicep files).

AppService.Bicep (App Service Module)

resource azbicepasp1 'Microsoft.Web/serverfarms@2022-03-01' = {
  name: 'azbicep-dev-eus-asp1'
  location: resourceGroup().location
  sku: {
    name: 'S1'
    capacity: 1
  }
}

resource azbicepas 'Microsoft.Web/sites@2022-03-01' = {
  name: 'azbicep-dev-eus-wapp1'
  location: resourceGroup().location
  properties: {
    serverFarmId: resourceId('Microsoft.Web/serverfarms', 'azbicep-dev-eus-asp1')
  }
  dependsOn: [
    azbicepasp1
  ]
}

(Storage.Bicep) Storage Account Module

param pStorageAccountName string

param pLocation string

resource storageaccount 'Microsoft.Storage/storageAccounts@2021-02-01' = {
  name: pStorageAccountName
  location: pLocation
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
  }
}

output StorageAccountId string = storageaccount.id

(Database.Bicep) Database Module

param pSQLServer string

param pAdministratorLogin string

@secure()

param pAdministratorLoginPassword string

param pLocation string = resourceGroup().location

resource sqlServer 'Microsoft.Sql/servers@2014-04-01' = {
  name: pSQLServer
  location: pLocation
  properties: {
    administratorLogin: pAdministratorLogin
    administratorLoginPassword: pAdministratorLoginPassword
  }
}
resource sqlServerDatabase 'Microsoft.Sql/servers/databases@2014-04-01' = {
  parent: sqlServer
  name: 'database1'
  location: pLocation
  properties: {
    collation: 'SQL_Latin1_General_CP1_CI_AS'
    edition: 'Basic'
    maxSizeBytes: '2147483648'
    requestedServiceObjectiveName: 'Basic'
  }
}

Once the bicep modules are ready, they can be invoked by another Bicep file by passing the appropriate input Parameters as shown below.

Main.Bicep

param Env string = 'dev'
param pAppServicePlan string
param pAppService string
param pSQLServer string = 'azbicep-dev-eus-sqlserver'
param pAdministratorLogin string
param pLocation string = resourceGroup().location
param pSKUName string = (Env == 'dev')? 'F1' : 'S2'
param pSKUCapacity int = (Env == 'dev')? 1 : 2

resource KeyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = {
  name: 'azbicep-dev-eus-kv1'
}
module AppServicePlan '2.AppServicePlan.bicep' = {
  name: 'AppServicePlan'
  params: {
    pAppService: pAppService
    pAppServicePlan: pAppServicePlan
    pInstrumentationKey: AppInsights.outputs.oInstrumentationKey
    pLocation: pLocation
    pSKUName: pSKUName
    pSKUCapacity: pSKUCapacity
    pEnv: Env
  }
}
module SqlDatabase '3.SQLDatabase.bicep' = {
  name: 'SQLDatabase'
  params: {
    pSQLServer: pSQLServer
    pAdministratorLogin: pAdministratorLogin
    pAdministratorLoginPassword: KeyVault.getSecret('sqladminpassword')
    pLocation: pLocation
  }
}

Example of Bicep Modules used in another Business Unit

As shown below, another team working for Business Unit 2 might also implement a similar design where they also create these modules which is nothing by duplicate work. Below is how it would look.

 Business Unit

Let’s now understand how to refactor the code in such a way that you have one set of reusable components that are accessible by all the Business Units across the organization.

Below is the ideal design for refactoring the reusable components.

Reusable components

Bicep supports the above design by letting the Bicep Developers publish the Modules to a Private Registry in Azure as of this writing. Microsoft Azure team has plans to support the publishing of Modules to Docker Hub in the future.

Below are the advantages of publishing the modules to a Container Registry.

  1. Centralized Repository: A container registry provides a centralized location to store and manage your modules. This makes it easier for teams to access, share, and collaborate on reusable infrastructure components.
  2. Versioning: Container registries typically support versioning of modules. This enables you to manage different versions of your modules, facilitating backward compatibility and ensuring that deployments are predictable and reliable. In our example, BU1 and BU2 can have their own versions of modules if required.
  3. Security: Container registries offer security features such as access control and encryption to protect your modules from unauthorized access and tampering. You can control who has access to the modules stored in the registry, ensuring that only authorized users can deploy them.
  4. Integration with CI/CD Pipelines: Container registries integrate seamlessly with continuous integration and continuous deployment (CI/CD) pipelines, enabling automated testing, building, and deployment of modules. You can configure your CI/CD pipeline to automatically publish updated versions of modules to the registry, streamlining the development and deployment process.

Overall, publishing modules to a container registry offers a robust and secure way to manage, share, and deploy reusable infrastructure components, enhancing collaboration, scalability, and reliability in your cloud deployments.

Working with Private Registries in Azure for publishing the Bicep modules needs infrastructure. Below is how the Private Registries are organized and used.

Private Registries

Next Steps

  1. Creating an Azure Container Registry (ACR) & Enabling Authentication for ACR.
  2. Developing Bicep modules &publishing each module.
  3. Invoking each module by referring to the ACR Repository.

Summary

In this article, we explored creating Bicep modules for common infrastructure components like App Service, Storage Account, and Database. These modules can then be invoked in a main Bicep file by passing appropriate parameters.

However, duplicating module creation across business units leads to redundancy. To address this, in the next set of articles, we will discuss leveraging private registries in Azure for sharing modules organization-wide. Publishing modules to a container registry offers several advantages, including centralized repository management, versioning, security features, and seamless organization of the Infrastructure as code.

In summary, leveraging private registries in Azure enhances collaboration, scalability, and reliability in managing and sharing reusable infrastructure components across an organization.

Thanks for reading, and good luck in organizing your code.