Logo

dev-resources.site

for different kinds of informations.

Conditional deployment in Azure Bicep

Published at
10/31/2024
Categories
azure
iac
bicep
cloud
Author
omiossec
Categories
4 categories in total
azure
open
iac
open
bicep
open
cloud
open
Author
8 person written this
omiossec
open
Conditional deployment in Azure Bicep

Modularity is a key when designing and coding Infrastructure as Code. You need to generalize and be flexible to reuse the code with different types of environments and situations.

Imagine a situation where you need to deploy resources in different Azure regions and environments (prod and dev). Each region and each environment has its specificities, some resources can be deployed in one but not the other, and some properties can change between regions or environments.

Letโ€™s take a simple but concrete case: you need to deploy a VNET with two subnets. But in a production environment, you want to have a NAT Gateway, and in North Europe and France Central, one of the subnets should be private. Nat Gateway and private subnet aren't needed in dev, but you still need to deploy two subnets.

Creating a Bicep file deploying a Nat Gateway with its public IP, a VNET, and two subnets with the NAT Gateway ID, one of which is a private subnet (defaultOutboundAccess: false in Bicep).
But how can we deploy or not a resource based on one parameter?

Bicep has two options.

The first one is conditional deployment. You must add an if and an expression before the resource definition to use it.

resource logicalName 'resource@2023-07-01' = if (condition) {
  xxxxxx
} 
Enter fullscreen mode Exit fullscreen mode

If the expression โ€œConditionโ€ is true, Bicep will deploy the resource, if not the resource is not deployed.

Here, we must deploy a Nat Gateway if prod environments only exist in North Europe and France Central.

The condition looks like

param environment string  

environment == 'prod' && (location == 'francecentral' || location == 'northeurope')
Enter fullscreen mode Exit fullscreen mode

We will need to use the condition on several resources, so it is wise to put it in a variable. It simplifies the code, especially here, with the complex evaluation using several logical operators see

var natGateWayDeployBool = environment == 'prod' && (location == 'francecentral' || location == 'northeurope')
Enter fullscreen mode Exit fullscreen mode

Resources can be deployed using:

var natGateWayDeployBool = environment == 'prod' && (location == 'francecentral' || location == 'northeurope')

resource publicip 'Microsoft.Network/publicIPAddresses@2024-01-01' = if (natGateWayDeployBool) {
  name: publicipname
  location: location
  sku: {
    name: 'Standard'
  }
  properties: {
    publicIPAddressVersion: 'IPv4'
    publicIPAllocationMethod: 'Static'
    idleTimeoutInMinutes: 4
  }
}


resource natgateway 'Microsoft.Network/natGateways@2024-01-01' =  if (natGateWayDeployBool)  {
  name: natGatewayName
  location: location
  sku: {
    name: 'Standard'
  }
  properties: {
    idleTimeoutInMinutes: 4
    publicIpAddresses: [
      {
        id: publicip.id
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

The Nat Gateway and its Public IP are deployed only if the environment is prod and the location is North Europe and France Central.

Now, how to deal with subnets?

In production, in North Europe and France Central subnet looks like this:

resource subnet1 'Microsoft.Network/virtualNetworks/subnets@2024-03-01' = {
  parent: vnet
  name: subnet1Name
  properties: {
    addressPrefix: subnet1Prefix
    natGateway: {
      id: natgateway.id
    }
  }
}

resource subnet2 'Microsoft.Network/virtualNetworks/subnets@2024-03-01' = {
  parent: vnet
  name: subnet2Name

  properties: {
    addressPrefix: subnet2Prefix
    defaultOutboundAccess: false
    natGateway: {
      id: natgateway.id
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

But for production in West Europe, we should remove the natGateway reference. For the dev environment, we should not have the natGatteway reference, and the defaultOutboundAccess property should be true.

First, letโ€™s create a variable for the defaultOutboundAccess property it should be false for production and true for dev. The value should be false for the dev environment so we could use an ! (logical NOT in Bicep)

var defaultOutboundAccessBool = !(environment == 'prod')
Enter fullscreen mode Exit fullscreen mode

The second subnet looks like:

resource subnet2 'Microsoft.Network/virtualNetworks/subnets@2024-03-01' = {
  parent: vnet
  name: subnet2Name

  properties: {
    addressPrefix: subnet2Prefix
    defaultOutboundAccess: defaultOutboundAccessBool 
    natGateway: {
      id: natgateway.id
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

We also need to remove the NatGateway Reference for dev and West Europe. The natGateWayDeployBool will be useful here.
If expression is not available inside a resource, only at the resource level, only the conditional expression ?: is permitted.

The form is simple
condition ? true-value : false-value

The natGateway property isn't a simple string, it asks for an expression, but you can use an expression with ?:

natGateway: (natGateWayDeployBool ? { id: natgateway.id } : null)

The subnet resources:

resource subnet1 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' =  {
  parent: vnet
  name: subnet1Name
  properties: {
    addressPrefix: subnet1Prefix
    natGateway: (natGateWayDeployBool ?  { id: natgateway.id } : null)
  }
}

resource subnet2 'Microsoft. Network/virtualNetworks/subnets@2024-01-01' = {
  parent: vnet
  name: subnet2Name

  properties: {
    addressPrefix: subnet2Prefix
    defaultOutboundAccess: defaultOutboundAccessBool 
    natGateway: (natGateWayDeployBool ?  { id: natgateway.id  } : null)
  }
}
Enter fullscreen mode Exit fullscreen mode

This is a simple example of what you can do with conditional deployment in Azure Bicep.

The full bicep code

param location string = resourceGroup().location

@description('VNet name')
param vnetName string 

@description('Vnet Address space')
param vnetAddressPrefix string 

@description('Subnet1 Prefix')
param subnet1Prefix string 

@description('Subnet1 Name')
param subnet1Name string  

@description('Subnet2 Prefix')
param subnet2Prefix string  

@description('Subnet2 Name')
param subnet2Name string 


@description('Environment Type')
@allowed([
  'dev'
  'prod'
])
param environment string  


@description('Public IP Nqme')
param publicipname string  = 'pibIPNqt'


@description('Nat Gateway Name')
param natGatewayName string   = 'NattGw'

var natGateWayDeployBool = environment == 'prod' && (location == 'francecentral' || location == 'northeurope')

var defaultOutboundAccessBool = !(environment == 'prod')


resource publicip 'Microsoft.Network/publicIPAddresses@2024-01-01' = if (natGateWayDeployBool) {
  name: publicipname
  location: location
  sku: {
    name: 'Standard'
  }
  properties: {
    publicIPAddressVersion: 'IPv4'
    publicIPAllocationMethod: 'Static'
    idleTimeoutInMinutes: 4
  }
}


resource natgateway 'Microsoft.Network/natGateways@2024-01-01' =  if (natGateWayDeployBool)  {
  name: natGatewayName
  location: location
  sku: {
    name: 'Standard'
  }
  properties: {
    idleTimeoutInMinutes: 4
    publicIpAddresses: [
      {
        id: publicip.id
      }
    ]
  }
}



resource vnet 'Microsoft.Network/virtualNetworks@2024-01-01' = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        vnetAddressPrefix
      ]
    }

  }
}


resource subnet1 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' =  {
  parent: vnet
  name: subnet1Name
  properties: {
    addressPrefix: subnet1Prefix
    natGateway: (natGateWayDeployBool ?  { id: natgateway.id } : null)
  }
}


resource subnet2 'Microsoft.Network/virtualNetworks/subnets@2024-01-01' = {
  parent: vnet
  name: subnet2Name

  properties: {
    addressPrefix: subnet2Prefix
    defaultOutboundAccess: defaultOutboundAccessBool 
    natGateway: (natGateWayDeployBool ?  { id: natgateway.id  } : null)
  }
}
Enter fullscreen mode Exit fullscreen mode
iac Article's
30 articles in total
Favicon
Customize VPCs with CloudFormation Conditions
Favicon
Provision EKS Cluster with Terraform, Terragrunt & GitHub Actions
Favicon
Terraform - Mastering Idempotency Violations - Handling Resource Conflicts and Failures in Azure
Favicon
OpenTofu - Infrastructure configuration management
Favicon
Goliat Shield: Your first line of defense
Favicon
Using CloudFormation to deploy a web app with HA
Favicon
KCL + Crossplane: A Declarative Language for Deploying Complex Infrastructure on AWS with Kubernetes.
Favicon
Terraform Remote Backend: How to Manage Terraform State File for Easier Collaboration across Teams
Favicon
Let's Talk Infrastructure as Code (IaC) ๐Ÿš€
Favicon
Conditional deployment in Azure Bicep
Favicon
Learning Ansible, Proxmox and LXC, Part 1
Favicon
Create your K3S lab on Google Cloud
Favicon
Mastering Multi-Cloud Infrastructure with Terraform: A Game-Changer for Modern IT
Favicon
The KISS Principle: Why Simplicity is Key in Dev and DevOps (and How to Implement It)
Favicon
user-defined type in Azure Bicep, an introduction
Favicon
You Are Not Saved By IaC
Favicon
Terraform Tactics: A Guide to Mastering Terraform Commands for DevOps
Favicon
Infrastructure as Code with Terraform
Favicon
What is Infrastructure as Code (IaC) and Why It's Transforming DevOps
Favicon
Managing Infrastructure as Code at Amazon: Tools, Strategies, and Practices
Favicon
Automating AWS Cost and Usage Report with CloudFormation
Favicon
Crossplane + AWS Overview for Managing Infrastructure as Code (IaC) with Kubernetes
Favicon
How IaC can streamline the Infrastructure & Configuration
Favicon
Secure Terraform Solution for Government Agencies
Favicon
IAC - Azure WebApp creation
Favicon
Terraform pipeline (IaC for AWS)
Favicon
Terraform
Favicon
ARM Template: Azure SQL Server
Favicon
9 Ways to Spin Up an EKS Cluster - Way 3 - eksctl
Favicon
What is Infrastructure as Code (IaC)?

Featured ones: