Spin Up Secure VM in Azure with Bicep

How To Deploy VM with Azure Bicep

A Hands-On Guide

Tired of manually configuring your Azure infrastructure? Want a faster, more reliable, and secure way to deploy Linux VMs? Look no further than Azure Bicep! This powerful declarative language lets you define your Azure resources in code, automating deployments and ensuring consistency across environments.

In this blog post, we'll walk through a practical example of deploying a secure Linux VM in Azure using Bicep. We'll cover everything from setting up your environment to deploying the Bicep template and verifying your deployment.

Why Choose Bicep?

Azure Bicep offers several advantages over traditional methods like the Azure portal or ARM templates:

  • Automation: Say goodbye to tedious manual steps. Bicep lets you define your infrastructure in code, automating deployments and reducing the risk of errors.
  • Consistency: Ensure your deployments are identical across different environments, eliminating inconsistencies that can lead to unexpected behavior.
  • Security: Bicep empowers you to implement security best practices from the start, including network isolation, access control, and disk encryption.
  • Collaboration: Share and collaborate on your infrastructure deployments with ease, making it simpler for teams to work together.

Getting Started

Before we dive into the Bicep code, let's set up our environment:

  1. Azure Subscription: Make sure you have an active Azure subscription.
  2. Azure CLI: Install the Azure CLI to interact with Azure resources from your command line.
  3. Bicep Extension: Install the Bicep extension for Visual Studio Code to get syntax highlighting, code completion, and other helpful features.

The Bicep Template

Now, let's create our Bicep template to deploy a secure Linux VM:

param resourceGroupName string = 'myResourceGroup'
param location string = 'swedencentral'
param vmName string = 'myVM'
param adminUsername string = 'azureuser'
param adminPassword string = 'P@$$wOrd1'
param vmSize string = 'Standard_B2s'

resource 'Microsoft.Compute/virtualMachines' 'myVM' = {
  location: location
  name: vmName
  properties: {
    storageProfile: {
      imageReference: {
        offer: 'UbuntuServer'
        publisher: 'Canonical'
        sku: '18.04-LTS'
        version: 'Latest'
      }
    }
    hardwareProfile: {
      vmSize: vmSize
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: resourceId('Microsoft.Network/networkInterfaces', 'myNetworkInterface')
        }
      ]
    }
    osProfile: {
      adminUsername: adminUsername
      adminPassword: adminPassword
    }
    storageProfile: {
      osDisk: {
        caching: 'ReadWrite'
        diskSizeGiB: 128
        storageAccountType: 'Standard_LRS'
      }
    }
  }
}

resource 'Microsoft.Network/networkInterfaces' 'myNetworkInterface' = {
  location: location
  name: 'myNetworkInterface'
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          subnet: {
            id: resourceId('Microsoft.Network/virtualNetworks/subnets', 'myVNet', 'mySubnet')
          }
        }
      }
    ]
  }
}

resource 'Microsoft.Network/networkSecurityGroups' 'myNSG' = {
  location: location
  name: 'myNSG'
  properties: {
    securityRules: [
      {
        name: 'allowSSH'
        properties: {
          access: 'Allow'
          direction: 'Inbound'
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '22'
          sourceAddressPrefix: '*'
          destinationAddressPrefix: '*'
          priority: 100
        }
      }
      {
        name: 'allowHTTPS'
        properties: {
          access: 'Allow'
          direction: 'Inbound'
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '443'
          sourceAddressPrefix: '*'
          destinationAddressPrefix: '*'
          priority: 110
        }
      }
    ]
  }
}

resource 'Microsoft.Network/virtualNetworks' 'myVNet' = {
  location: location
  name: 'myVNet'
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
    subnets: [
      {
        name: 'mySubnet'
        properties: {
          addressPrefix: '10.0.1.0/24'
          networkSecurityGroup: {
            id: resourceId('Microsoft.Network/networkSecurityGroups', 'myNSG')
          }
        }
      }
    ]
  }
}

Deploying the Template

  1. Save the Bicep code: Save the code as a .bicep file (e.g., main.bicep).
  2. Create a resource group: Use the Azure CLI to create a resource group where you'll deploy your VM:
az group create -n myResourceGroup -l swedencentral
  1. Deploy the template: Deploy the Bicep template using the Azure CLI:
az deployment group create -g myResourceGroup -n myDeployment -f main.bicep

Verifying the Deployment

Once the deployment is complete, you can verify that your VM is running:

  1. Check the Azure portal: Go to the Azure Portal and navigate to your resource group. You should see your new VM listed.
  2. Connect to the VM: Use SSH to connect to your VM and verify that it's working as expected.

Conclusion

Congratulations! You've successfully deployed a secure Linux VM in Azure using Bicep. This hands-on guide has shown you the power and simplicity of Bicep for automating your infrastructure deployments. By embracing Bicep. you can significantly reduce the time and effort required to build and manage your Azure resources while ensuring consistency and security. Start exploring Bicep today on GitHub and unlock the full potential of your Azure deployments!