Bicep is a new (experimental) way for building and deploying infrastructure to Azure. It's a language that compiles down to standard Azure Resource Manager json templates. So instead of handcrafting hundreds (if not thousands) of lines of json, you can code it in Bicep and then let the compiler do the hard work :)
To start with Bicep, you need to install the Bicep CLI tool and ideally the VS Code extension so that you can get Intellisense and code syntax colorization. Side note: not all theme extensions support Bicep yet.
If you want to see a video of me setting it all up and writing my first Bicep program, check out this recording:
Our first Bicep template
For the purpose of this blog, we'll use Bicep to create a SQL Server and SQL database resource on Azure. Create a new directory and add a main.bicep
file:
param subscriptionId string = 'e42acc2b-8462-4fb5-bf0d-d983c0017584'
param kvResourceGroup string = 'identity'
param kvName string = 'cm-identity-kv'
resource kv 'Microsoft.KeyVault/vaults@2019-09-01' existing = {
name: kvName
scope: resourceGroup(subscriptionId, kvResourceGroup )
}
module sql './sql.bicep' = {
name: 'deploySQL'
params: {
administratorLogin: kv.getSecret('sqlAdministratorLogin')
administratorLoginPassword: kv.getSecret('sqlAdministratorLoginPassword')
}
}
In this file, we define a few parameters that mainly point to our KeyVault resource and then we call into the SQL module.
Next, we need to create a new Bicep file for our SQL Server and database. Name the new file sql.bicep
and add the following code:
param serverName string = uniqueString('sql125486asdf2')
param sqlDBName string = 'SampleDB'
param location string = resourceGroup().location
@secure()
param administratorLogin string
@secure()
param administratorLoginPassword string
resource server 'Microsoft.Sql/servers@2019-06-01-preview' = {
name: serverName
location: location
properties: {
administratorLogin: administratorLogin
administratorLoginPassword: administratorLoginPassword
}
}
resource sqlDB 'Microsoft.Sql/servers/databases@2020-08-01-preview' = {
name: '${server.name}/${sqlDBName}'
location: location
sku: {
name: 'Standard'
tier: 'Standard'
}
}
We will use a random name for the SQL Server and we'll inherit some properties (i.e the location) from the Azure resource group we're deploying to. uniqueString()
and resourceGroup()
are built-in Bicep functions. You can find more about Bicep functions here
You'll notice that we also have two uninitialized secure parameters:
- administratorLogin
- administratorLoginPassword
We left them blank for a good reason! We don't want to store secrets in our code as this is a security attack vector. The values for these properties will be passed from the main.bicep
file which will retrieve them from Azure KeyVault making our deployment code secure end-to-end.
Let's build our code:
bicep build main.bicep
This should generate an output file main.json
that contains the compiled ARM template json:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"serverName": {
"type": "string",
"defaultValue": "[uniqueString('sql125486asdf')]"
},
"sqlDBName": {
"type": "string",
"defaultValue": "SampleDB"
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
},
"administratorLogin": {
"type": "string"
},
"administratorLoginPassword": {
"type": "secureString"
}
},
"functions": [],
"resources": [
{
"type": "Microsoft.Sql/servers",
"apiVersion": "2019-06-01-preview",
"name": "[parameters('serverName')]",
"location": "[parameters('location')]",
"properties": {
"administratorLogin": "[parameters('administratorLogin')]",
"administratorLoginPassword": "[parameters('administratorLoginPassword')]"
}
},
{
"type": "Microsoft.Sql/servers/databases",
"apiVersion": "2020-08-01-preview",
"name": "[format('{0}/{1}', parameters('serverName'), parameters('sqlDBName'))]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard",
"tier": "Standard"
},
"dependsOn": [
"[resourceId('Microsoft.Sql/servers', parameters('serverName'))]"
]
}
]
}
Let's add the Sec in DevSecOps
First and foremost, we need to ensure that the account deploying this ARM template has the right enough privilege to do so. You don't want to use a user account as these tend to have elevated permissions and can cause some serious damage. The recommended practice is to use a Service Principal account. You can create these via the Azure Portal, PowerShell or the CLI. In this instance, we'll use the Azure CLI
az login
az ad sp create-for-rbac --role Contributor --scopes /subscriptions/<Your Subscription ID>/resourceGroups/<Your Resource Group Name> --name <Give it a nice name>
Take a note of the output.
For our account to also be able to retrieve the necessary secrets from Azure Key Vault, we need to create a very specific role. You can find more information about how to create this very custom RBAC role here.
Following the above docs, we'll create a new keyvaultrole.json
file and paste the following json:
{
"Name": "Key Vault CM resource manager template deployment operator",
"IsCustom": true,
"Description": "Lets you deploy a resource manager template with the access to the secrets in the Key Vault.",
"Actions": [
"Microsoft.KeyVault/vaults/deploy/action"
],
"NotActions": [],
"DataActions": [],
"NotDataActions": [],
"AssignableScopes": [
"/subscriptions/<Your Subscription ID>/resourceGroups/<Your Resource Group Name>/providers/Microsoft.KeyVault/vaults/<Your Key Vault name>"
]
}
We now need to create this role in our Azure Subscription (if one doesn't exist already) and assign it to our Service Principal. In the Azure CLI, type the following:
az role definition create --role-definition ./keyvaultrole.json
az role assignment create --role "Key Vault CM resource manager template deployment operator" --assignee <your SP client Id> --resource-group bicep-demo
Now that we have an account with the right privileges, we need to sign out (as ourselves) and sign in with the newly created Service Principal account:
az account clear
az login --service-principal -u <Service Principal Id> -p <Service Principal password> --tenant <Azure AD Tenant ID>
az account show
The final step is to configure our Key Vault to allow ARM deployments as well as create the necessary secrets that will be referenced by our Bicep-generated ARM templates
In Key Vault, navigate to the Access Policies tab and ensure that the Azure Resource Manager for template deployment option under Enable Access to: is checked. Make sure to press the Save button if you make any changes:
Finally, we want to check that our Service Principal has been assigned the right role to be able to read secrets from Key Vault. Navigate to the Access Control (IAM) tab and check under Role Assignments to ensure that the script we run earlier worked:
We now have a locked down account and the all the secrets stored in Key Vault. Let's finalize our Bicep/ARM deployment. We can now go ahead and deploy our infrastructure as code using the Azure CLI:
az deployment group create --resource-group bicep-demo --template-file main.bicep
The output will be a bunch of json with information about the deployment like the heavily omitted output below:
{
"id": "/subscriptions/e42acc2d-8462-4fb5-bf0d-d983c0017584/resourceGroups/bicep-demo/providers/Microsoft.Resources/deployments/cmdeployment425show",
"location": null,
...
"provisioningState": "Succeeded",
"templateHash": "18120650064530837360",
"templateLink": null,
"timestamp": "2021-03-02T00:16:56.630918+00:00",
"validatedResources": null
},
"resourceGroup": "bicep-demo",
"tags": null,
"type": "Microsoft.Resources/deployments"
}
Building more elaborate Bicep code
The GitHub repo is thin at the moment and for a moment I thought I was stuck with the tutorial sample code. But then, I came across the glorious Bicep Playground and all was great again. The Playground displays Bicep and compiled json side by side and provides you with a lot of sample code to help you build your own templates. My suspicion is that this is all driven by the Azure ARM Samples repo:
Source Code
This GitHub repo contains all the files and code referenced in this blob post.
Summary
I love Bicep because it makes working with Azure Resources more straightforward and concise. And unlike Pulumi or Terraform, it's native Azure and therefore provides better support for Azure resources. However, there are pros and cons with every tool so choose the one that truly makes you happy (or productive).
Top comments (0)