---
title: "Deploy development virtual machines on Azure"
description: "Deploy development virtual machines on Azure with Terraform. Automate setup with multiple OS options, SSH access, and Ansible integration for seamless configurations."
url: "https://docs.itrsgroup.com/docs/geneos/7.11.0/collection/cloud-native-deployments/deploying-via-terraform/instance-provisioning/azure-instance-provisioning/index.html"
---
This page details the Terraform configuration for deploying development virtual machines (VMs) on Microsoft Azure with multiple operating system options and automated Netprobe deployment. This environment creates development VMs on Azure with:

- Multiple OS choices (Ubuntu 22.04/24.04 LTS, RHEL 8, and RHEL 9)
- Ansible deployment automation
- SSH key authentication
- Configurable VM specifications
- Resource tagging for organization

## Template files

The environment contains the following Terraform configuration files:

- `main.tf` — the main configuration that provisions VM instances and triggers the Ansible deployment
- `variables.tf` — variable definitions for all configurable parameters
- `outputs.tf` — output definitions for deployment information
- `providers.tf` — Azure provider configuration
- `versions.tf` — Terraform and provider version constraints
- `terraform.tfvars.[os].example` — configuration file for your operating system

## Prerequisites

1. [Terraform](https://www.terraform.io/downloads) version 1.0 or higher installed

2. [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) version 2.0 or higher installed  

3. Azure authentication configured:

   ```bash
   # Method 1: Interactive login
   az login
   
   # Method 2: Service principal
   az login --service-principal \
     --username <app-id> \
     --password <password> \
     --tenant <tenant-id>
   
   # Method 3: Environment variables
   export ARM_CLIENT_ID="your-client-id"
   export ARM_CLIENT_SECRET="your-client-secret"
   export ARM_SUBSCRIPTION_ID="your-subscription-id"
   export ARM_TENANT_ID="your-tenant-id"
   ```

4. Azure subscription with appropriate permissions:
   - Contributor role or equivalent permissions on the target Resource Group
   - Access to create virtual machines, networks, and associated resources

5. SSH key pair for VM access

   ```bash
   # Generate SSH key pair if not already available
   ssh-keygen -t rsa -b 4096 -f ../../../../../resources/id_rsa
   ```

6. Existing Azure resources (Prerequisites):
   - Resource Group - Must exist before deployment
   - Virtual Network with subnet - VMs will be deployed to existing subnet
   - Network Security Group - Will be associated with VM network interfaces

## Deployment setup

1. Copy the example configuration.

   ```bash
   # For Ubuntu 22.04 (default)
   cp terraform.tfvars.example terraform.tfvars
   
   # For Ubuntu 24.04
   cp terraform.tfvars.ubuntu24.example terraform.tfvars
   
   # For RHEL 8
   cp terraform.tfvars.rhel8.example terraform.tfvars
   
   # For RHEL 9
   cp terraform.tfvars.rhel9.example terraform.tfvars
   ```

2. Update the `terraform.tfvars` [configuration file](#configuration-files) with your Azure resource IDs and preferences.

   ```bash
   nano terraform.tfvars
   ```

3. [Deploy](#terraform-commands) the infrastructure.

   ```bash
   terraform init
   terraform plan
   terraform apply
   ```

## Authentication overview

This deployment requires two types of authentication:

1. Terraform authentication (infrastructure creation) to allow Terraform to create virtual machines, networks, and cloud resources. For Azure, you need to configure the Azure CLI or service principal. Select only one method:

   - Interactive login — makes use of the Azure CLI interactive login.

      ```bash
      az login
      ```

   - Service principal — makes use of a service principal for automated deployments.

      ```bash
      az login --service-principal \
        --username <app-id> \
        --password <password> \
        --tenant <tenant-id>
      ```

   - Environment variables — makes use of environment variables for authentication.

      ```bash
      export ARM_CLIENT_ID="your-client-id"
      export ARM_CLIENT_SECRET="your-client-secret"
      export ARM_SUBSCRIPTION_ID="your-subscription-id"
      export ARM_TENANT_ID="your-tenant-id"
      ```

2. Application authentication (cloud storage access) to allow applications running on virtual machines to download the deployment resources from the respective cloud storage. This is configured in the `netprobe.yml` file for each environment. Refer to [Azure authentication](https://docs.itrsgroup.com/docs/geneos/7.11.0/collection/cloud-native-deployments/deploying-via-terraform/ansible-configuration/index.html#azure) for detailed authentication configuration.

## Identity configuration

### User assigned identity for Azure storage access

VMs can be configured with user assigned identities for secure access to the Azure Blob Storage without storing credentials.

```hcl
# In terraform.tfvars
identity_ids = [
  "/subscriptions/your-subscription-id/resourceGroups/your-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/your-identity"
]
```

The user assigned identity must have the `Storage Blob Data Reader` role assigned on the storage account or container used for deployment resources.

Run the following Azure CLI commands to create the identity:

```bash
# Create User Assigned Identity
az identity create \
  --name "geneos-cloud-managed-identity" \
  --resource-group "your-resource-group"

# Get identity resource ID
az identity show \
  --name "geneos-cloud-managed-identity" \
  --resource-group "your-resource-group" \
  --query "id" -o tsv

# Assign Storage Blob Data Reader role to identity
az role assignment create \
  --role "Storage Blob Data Reader" \
  --assignee-object-id $(az identity show --name "geneos-cloud-managed-identity" --resource-group "your-resource-group" --query "principalId" -o tsv) \
  --assignee-principal-type "ServicePrincipal" \
  --scope "/subscriptions/your-subscription-id/resourceGroups/your-resource-group/providers/Microsoft.Storage/storageAccounts/your-storage-account"
```

## Configuration files

Select the appropriate configuration file for your operating system:

| Operating system | Configuration file |
|-------|-------|
| Ubuntu 22.04 LTS (default) | `terraform.tfvars.example` |
| Ubuntu 24.04 LTS | `terraform.tfvars.ubuntu24.example` |
| RHEL 8 | `terraform.tfvars.rhel8.example` |
| RHEL 9 | `terraform.tfvars.rhel9.example` |

In the selected configuration file, configure the parameters outlined below.

### Azure account configuration

| Parameter | Description | Default | Required |
|-------|-------|-------|-------|
| `subscription_id` | Azure subscription ID where resources will be deployed |  | Yes |

### Deployment configuration

| Parameter | Description | Default | Required |
|-------|-------|-------|-------|
| `resource_group_name` | Name of the existing Azure resource group for resource deployment |  | Yes |
| `deployment_count` | Number of identical VM deployments to create | 1 | Yes |
| `tags` | Resource tags to assign to all created resources | {} | No |

### Network configuration  

| Parameter | Description | Default | Required |
|-------|-------|-------|-------|
| `vnet_subnet_id` | ID of the existing VNet subnet where VMs will be deployed |  | Yes |
| `nsg_id` | ID of the existing Network Security Group to associate with NICs |  | Yes |

### Public IP configuration

| Parameter | Description | Default | Required |
|-------|-------|-------|-------|
| `public_ip_name` | Base name for Public IP Address resources |  | Yes |
| `public_ip_sku` | SKU of the Public IP Address (Standard, Basic) | "Standard" | Yes |
| `public_ip_type` | Allocation method for Public IP Address (Static, Dynamic) | "Static" | Yes |
| `public_ip_zones` | Availability zones for the Public IP Address | ["1"] | Yes |

### Network interface configuration

| Parameter | Description | Default | Required |
|-------|-------|-------|-------|
| `nic_name` | Base name for Network Interface resources | | Yes |

### Virtual machine configuration

Virtual machine configurations are based on the [Netprobe system requirements](https://docs.itrsgroup.com/docs/geneos/7.11.0/collection/netprobe/installation/quickstart-linux-and-other-platforms/index.html#system-requirements). The default VM size and OS disk type follow the [ITRS Azure virtual machine image](https://portal.azure.com/#view/Microsoft_Azure_Compute/VmSmartDefaultsBlade/marketplaceId/itrsgroupltd1620310702149.itrs-geneos-azure-monitoringitrs-geneos-azuremon-byol/telemetryId/3ee0a00b-a9c1-4ae2-93f1-8be0cff0fd16) specifications.

| Parameter | Description | Default | Required |
|-------|-------|-------|-------|
| `vm_name` | Base name for Virtual Machine resources | | Yes |
| `vm_size` | Size/type of the Virtual Machine | "Standard_D2s_v3" | Yes |
| `vm_zones` | Availability zones for the Virtual Machine | ["1"] | Yes |
| `vm_os_disk_type` | OS disk type | "Premium_LRS" | Yes |

### Virtual machine image configuration

| Parameter | Description | Default | Required |
|-------|-------|-------|-------|
| `vm_image_publisher` | Publisher of the VM image |  | Yes |
| `vm_image_offer` | Image offer for the Virtual Machine | | Yes |
| `vm_image_sku` | Image SKU for the Virtual Machine | | Yes |
| `vm_image_version` | Image version for the Virtual Machine | "latest" | Yes |

### SSH access configuration

| Parameter | Description | Default | Required |
|-------|-------|-------|-------|
| `ssh_user` | SSH username for VM access | | Yes |
| `ssh_public_key_path` | Path to SSH public key file | | Yes |
| `disable_password_auth` | Disable password authentication (SSH keys only) | true | Yes |
| `vm_admin_password` | Admin password for the Virtual Machine (used as fallback) | "" | No |

### Ansible deployment configuration

| Parameter | Description | Default | Required |
|-------|-------|-------|-------|
| `ansible_playbook_path` | Path to Ansible playbook for deployment | "../../../../ansible/netprobe.yml" | Yes |
| `ansible_operation` | [Deployment operation](https://docs.itrsgroup.com/docs/geneos/7.11.0/collection/cloud-native-deployments/deploying-via-terraform/ansible-configuration/index.html#ansible-supported-operations)  | "install" | Yes |
| `ansible_ssh_common_args` | SSH common arguments for Ansible connections | "-o ControlMaster=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" | Yes |
| `additional_args` | Additional Ansible playbook arguments | "" | No |

## Resources created

The following Azure infrastructure resources will be created:

| Resource | Description |
|-----------|-------------|
| Public IP Address | Static IP for external access |
| Network Interface | Connected to existing VNet subnet and NSG |
| Virtual Machine | Linux VM with SSH access and selected OS |
| Ansible Deployment | Automated Netprobe service installation |

## Outputs

The following outputs will be available after deployment:

| Output | Description |
|--------|-------------|
| `external_ip` | Public IP address of the virtual machine |
| `internal_ip` | Private IP address of the virtual machine |
| `vm_name` | Name of the virtual machine |
| `resource_group_name` | Resource group containing the resources |
| `operating_system` | Operating system version selected |
| `ssh_user` | SSH username for the operating system |
| `deployment_summary` | Summary of all deployed resources |

## Ansible integration

Ansible playbooks are automatically executed after the creation of the virtual machine. These are used to:

- Configure the Netprobe service.
- Set up monitoring connections to the Gateway.
- Apply environment-specific settings.
- Install the required dependencies.

## Troubleshooting

You can run the given commands if you encounter the following issues:

| Issue type | Command |
|------------|---------|
| Authentication issues | ```bash
# Check current Azure identity
az account show
# List available subscriptions
az account list
# Set subscription
az account set --subscription "your-subscription-id"
# Check permissions
az role assignment list --assignee $(az account show --query user.name -o tsv)
``` |
| Resource group and network issues | ```bash
# Check resource group exists
az group show --name "your-resource-group"
# List VNets in resource group
az network vnet list --resource-group "your-resource-group"
# List subnets in VNet
az network vnet subnet list --resource-group "your-resource-group" --vnet-name "your-vnet"
# Check NSG exists
az network nsg show --resource-group "your-resource-group" --name "your-nsg"
``` |
| Instance issues | ```bash
# Check VM status
az vm list --resource-group "your-resource-group"
# Get VM details
az vm show --resource-group "your-resource-group" --name "your-vm"
# Check via Terraform
terraform show
terraform state list
``` |
| Image issues | ```bash
# List available Ubuntu images
az vm image list --publisher Canonical --offer 0001-com-ubuntu-server-jammy --all
# List available RHEL images
az vm image list --publisher RedHat --offer RHEL --all
``` |
| SSH connection issues | ```bash
# Check public IP
az network public-ip show --resource-group "your-resource-group" --name "your-public-ip"
# Check NSG rules
az network nsg rule list --resource-group "your-resource-group" --nsg-name "your-nsg"
# Test SSH connection
ssh -i ../../../../../resources/id_rsa netprobe_user@<public-ip>
``` |
| Ansible deployment issues | ```bash
# Check Ansible logs in Terraform output
terraform apply -auto-approve
# Manual Ansible execution
ansible-playbook -i <public-ip>, ../../../../ansible/netprobe.yml \
--private-key ../../../../../resources/id_rsa \
--user netprobe_user \
--extra-vars "operation=install"
``` |

## Terraform commands

Run the following Terraform commands to deploy the infrastructure.

| Command | Command |
|-----------|-------------|
| Initialize Terraform | ```bash
terraform init
``` |
| Plan the deployment | ```bash
terraform plan -var-file="terraform.tfvars"
``` |
| Apply the deployment | ```bash
terraform apply -var-file="terraform.tfvars"
``` |
| Show the deployment options | ```bash
terraform output
``` |
| Destroy the deployment | ```bash
terraform destroy -var-file="terraform.tfvars"
``` |

## Netprobe configuration

The `netprobe.yml` file contains Ansible configuration for Netprobe deployment. For general configuration structure and available parameters, refer to [Ansible configuration](https://docs.itrsgroup.com/docs/geneos/7.11.0/collection/cloud-native-deployments/deploying-via-terraform/ansible-configuration/index.html).

Update the following environment-specific settings in `netprobe.yml` file for your Azure development environment:

### SSH configuration

```yaml
# SSH connection configuration (required)
ansible_ssh_private_key_file: "../../../../resources/id_rsa"
ansible_ssh_common_args: "-o ControlMaster=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
```

### Bootstrap configuration

```yaml
# Set to false for dev environments (minimal bootstrap)
perform_bootstrap: false

# Azure CLI installation command if perform_bootstrap is true
additional_bootstrap: "{{ python_path }} -m pip install --upgrade msrestazure && ansible-galaxy collection install azure.azcollection --force && {{ python_path }} -m pip install -r ~/.ansible/collections/ansible_collections/azure/azcollection/requirements.txt"
```

### Cloud provider configuration

```yaml
resources:
  # Azure Blob Storage configuration (update with your credentials)
  source:
    azure:
      resource_group: resource_group
      storage_account_name: storage_account_name
      account_key: account_key
  # Cloud storage container
  container: geneos
  # Resource paths
  path: netprobe.tar.gz
  setupfile:
    path: netprobe.setup_template.xml
```

### Gateway connection

```yaml
env_vars:
  # Gateway information (configure for your setup)
  GATEWAY_HOST: "0.0.0.0"
  GATEWAY_PORT: "7039"
```

### Netprobe connection

```yaml
env_vars:
  # Netprobe information
  SERVICE_PARAM: "-port 7036 -setup {{ workspace_dir }}/{{ resources.setupfile.path | basename }}"
```

