Building Landing Zones with CARML
A landing zone provides a foundation for deploying workloads in Azure while adhering to organizational policies and standards. These days lot of companies are investing in building up LZ to provide to their future workloads standardization, consistency, security, governance, compliancy and more. Let’s see some possible approaches on how to build an enterprise landing zone using Bicep.
To create complex infrastructures with Bicep, there are mainly two approaches I’ve seen so far:
- build your own bicep modules.
- use the Common Azure Resource Modules Library ( aka CARML https://aka.ms/carml), a library of mature bicep modules curated by Microsoft.
This repo ALZ-Bicep is an example on how I normally end up when I create my own bicep modules to encapsulate part of my deployments. Basically by having two levels modules and orchestrations.
- One or multiple modules for the networking, one modules per supporting support services, application modules, etc…
- The modules normally contains a set of resource definitions.
- Modules are then called in the right sequence by bicep orchestration files.
This setup works like a charm but over time gives it might give the feeling you are writing again and again the same modules.

Let’s now looks on how we could approach an hypothetical landing zone project with CARML.
The main objective of CARML is to offer you reusable building blocks, allowing you to concentrate on what truly matters. CARML expedites solution development, reduces testing time, facilitates seamless integration, and ensures uniformity across your infrastructure deployments. In the CARML modules concepts like RBAC, Logs, Metrics, Locks and child resources are heavily integrated and fully parametrized giving you the possibility to cover multiple setup without the need to maintain multiple module instances for different use cases.
So how can we structure our Enterprise-Scale landing zone templates with CARML? We could have:
- One orchestrator per subscription (Management, Connectivity, Identity, Sandbox, etc..) plus one orchestrator for the management group creation and subscription placement. Basically one orchestrator per design areas for Enterprise-scale landing zones.
- Multiple bicep modules to assemble the CARML modules in a reusable way. In this way I can version chunks of the architecture.
- A multitude of the CARML modules curated by Microsoft. Each CARML module is tied to a specific resource type (virtualNetwork, ipGroup, routeTable, etc..) and grouped by resource providers (Microsoft.Network).

This approach allows to reduce the number of level-2 modules to be developed because we rely on the quality of the CARML however introduces more moving parts, questions on how to version and upgrade the different modules, and additional questions about how to securely access to the shared modules.
The most effective way to share and consume the bicep modules is via a Bicep registry (private or public). By using a Bicep private registry you can:
- leverage the Azure RBAC and provide access to the proper identities by assigning push and pull permission to the ACR.
- reference your modules with an intuitive syntax (e.g. module modNetworkWatcher ‘br/networking:watcher:1.0.epsilon’ ={} )
- reduce the external dependencies.
When we deal with this 3 layers approach, the orchestrations are normally saved on the customer repository together with the parametrization, the CICD and other support artifacts. The second level modules are subjected to changes depending on the customer needs therefore it makes sense save in the customer repo and then publish them to a private ACR hosted by the customer.
What about the CARML modules? Should we use a private repo, a partner repo (to offer additional services on top of CARML) or a public repo (hosted by Microsoft)?
The following image illustrate three options.

What is the best choice? Well, it depends on your security requirements, the versioning strategy, the deprecation strategy and more.
- For sure the use of the public registry is the simplest and the cheapest solution. If that external dependency works for you, you can start quickly. If you need to deviate to the CARML you can build your own version and push to the customer registry. Unfortunately at the time of writing a limited amount of modules is available.
- Publishing the CARML on the customer private registry makes the security tighter but you have to put in place a procedure to maintain the CARML, intake new version and make sure we have a deprecation strategy. That’s not an easy procedure, the cloud is moving fast, new services are popping up at the same pace of deprecations.
- A better solution might be to delegate the maintenance of a registry to a partner and use the Azure Lighthouse to grant access to the partner registry. The partner will take care of introducing new features when needed, upgrades, deprecations, and more. Peace of mind guaranteed with a fully managed service.
By leveraging modularization with Bicep and Bicep Registry, you can improve code reuse, simplify infrastructure management, foster collaboration, and benefit from the ecosystem and best practices established by the community. It offers a more efficient and scalable approach to building and managing infrastructure as code solutions as landing zones.
Photo by Venti Views on Unsplash