From db580a61830822374cb97b147331d119ca511e2f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 21:54:04 +0000 Subject: [PATCH 1/3] Initial plan From fab23e2b5f00fdf5a62e3ba77df3e45e7da3901e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 21:58:22 +0000 Subject: [PATCH 2/3] Add Azure VM + Network demo IaC with Bicep - Create main.bicep at subscription scope with resource group - Add network modules (VNet, Subnet, NSG with RDP rule) - Add VM module (Windows Server 2022, Standard_B2s) - Add supporting modules (Public IP, NIC) - Create main.bicepparam with example parameters - Update README.md with comprehensive deployment instructions - Add *.json to .gitignore for Bicep build artifacts Co-authored-by: robpitcher <13648061+robpitcher@users.noreply.github.com> --- .gitignore | 5 +- infra/bicep/README.md | 262 ++++++++++++++++++++++++++++- infra/bicep/main.bicep | 119 +++++++++++++ infra/bicep/main.bicepparam | 25 +++ infra/bicep/modules/nic.bicep | 38 +++++ infra/bicep/modules/nsg.bicep | 34 ++++ infra/bicep/modules/publicip.bicep | 24 +++ infra/bicep/modules/vm.bicep | 73 ++++++++ infra/bicep/modules/vnet.bicep | 48 ++++++ 9 files changed, 626 insertions(+), 2 deletions(-) create mode 100644 infra/bicep/main.bicep create mode 100644 infra/bicep/main.bicepparam create mode 100644 infra/bicep/modules/nic.bicep create mode 100644 infra/bicep/modules/nsg.bicep create mode 100644 infra/bicep/modules/publicip.bicep create mode 100644 infra/bicep/modules/vm.bicep create mode 100644 infra/bicep/modules/vnet.bicep diff --git a/.gitignore b/.gitignore index 291736b..9ad1d68 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,7 @@ override.tf.json .terraformrc terraform.rc -.vscode/settings.json \ No newline at end of file +.vscode/settings.json + +# Bicep build artifacts (ARM JSON templates) +*.json \ No newline at end of file diff --git a/infra/bicep/README.md b/infra/bicep/README.md index 95f4c10..c6d3270 100644 --- a/infra/bicep/README.md +++ b/infra/bicep/README.md @@ -1 +1,261 @@ -# Bicep IaC \ No newline at end of file +# Azure Bicep Demo - VM + Network Infrastructure + +This directory contains Azure Bicep Infrastructure as Code (IaC) for deploying a Windows Server Virtual Machine with associated networking resources. + +## What Gets Deployed + +This Bicep template deploys the following Azure resources: + +- **Resource Group**: Container for all resources +- **Virtual Network (VNet)**: Network with default address space (10.0.0.0/16) +- **Subnet**: Default subnet (10.0.0.0/24) +- **Network Security Group (NSG)**: With RDP access rule (port 3389) +- **Public IP Address**: For external VM access +- **Network Interface (NIC)**: VM network adapter +- **Virtual Machine**: Windows Server 2022 (Standard_B2s - low-cost demo size) +- **Managed OS Disk**: Standard LRS storage + +**Target Region**: Sweden Central + +## Prerequisites + +Before deploying, ensure you have: + +1. **Azure CLI** installed ([Download here](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli)) +2. **Bicep CLI** installed (comes with Azure CLI or [install separately](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/install)) +3. An active **Azure subscription** +4. Appropriate **permissions** to create resources at the subscription level + +## Deployment Instructions + +### Step 1: Login to Azure + +```bash +az login +``` + +### Step 2: Set Your Subscription (if you have multiple) + +```bash +az account set --subscription "Your-Subscription-Name-or-ID" +``` + +### Step 3: Validate the Bicep Template (Optional but Recommended) + +This checks for syntax errors without deploying: + +```bash +cd infra/bicep +bicep build main.bicep +``` + +If successful, you'll see a `main.json` file generated (this is excluded from git). + +### Step 4: Validate Deployment + +Run a validation to ensure the deployment will succeed: + +```bash +az deployment sub validate \ + --location swedencentral \ + --template-file main.bicep \ + --parameters main.bicepparam \ + --parameters adminPassword='YourSecurePassword123!' +``` + +Replace `YourSecurePassword123!` with a strong password that meets Azure VM requirements: +- At least 12 characters +- Contains uppercase, lowercase, numbers, and special characters + +### Step 5: Deploy the Infrastructure + +Deploy to your Azure subscription: + +```bash +az deployment sub create \ + --name demo-vm-deployment \ + --location swedencentral \ + --template-file main.bicep \ + --parameters main.bicepparam \ + --parameters adminPassword='YourSecurePassword123!' +``` + +**Deployment time**: Approximately 5-10 minutes + +### Step 6: Get Deployment Outputs + +After successful deployment, retrieve important information: + +```bash +az deployment sub show \ + --name demo-vm-deployment \ + --query properties.outputs +``` + +This will show: +- Resource Group Name +- VM Name +- Virtual Network Name +- Public IP Address (once allocated) +- VM Resource ID + +## Connecting to Your VM + +### Using Remote Desktop Protocol (RDP) + +1. Get the Public IP address from the deployment outputs or Azure Portal +2. Open Remote Desktop Connection (mstsc.exe on Windows) +3. Enter the Public IP address +4. Use the credentials: + - **Username**: `azureadmin` (or what you specified) + - **Password**: The password you provided during deployment + +**Note**: The Public IP is dynamic (allocated when VM starts). It may change if the VM is deallocated. + +## Customization + +### Modifying Parameters + +You can customize the deployment by editing `main.bicepparam` or providing parameters at the command line: + +```bash +az deployment sub create \ + --name demo-vm-deployment \ + --location swedencentral \ + --template-file main.bicep \ + --parameters resourceGroupName='my-custom-rg' \ + --parameters adminUsername='myadmin' \ + --parameters adminPassword='MySecurePass123!' \ + --parameters vmSize='Standard_B1s' +``` + +### Available Parameters + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `location` | Azure region | `swedencentral` | +| `resourceGroupName` | Resource group name | `rg-demo-vm` | +| `adminUsername` | VM admin username | `azureadmin` | +| `adminPassword` | VM admin password (secure) | *(required)* | +| `vmSize` | VM size/SKU | `Standard_B2s` | +| `vnetAddressPrefix` | VNet address space | `10.0.0.0/16` | +| `subnetAddressPrefix` | Subnet address space | `10.0.0.0/24` | +| `resourcePrefix` | Resource naming prefix | `demo` | + +## Clean Up Resources + +To avoid incurring charges, delete the resource group and all its resources: + +```bash +az group delete --name rg-demo-vm --yes --no-wait +``` + +## Architecture + +``` +┌─────────────────────────────────────────┐ +│ Subscription (Sweden Central) │ +│ │ +│ ┌───────────────────────────────────┐ │ +│ │ Resource Group (rg-demo-vm) │ │ +│ │ │ │ +│ │ ┌────────────────────────────┐ │ │ +│ │ │ Virtual Network │ │ │ +│ │ │ (10.0.0.0/16) │ │ │ +│ │ │ │ │ │ +│ │ │ ┌──────────────────────┐ │ │ │ +│ │ │ │ Subnet │ │ │ │ +│ │ │ │ (10.0.0.0/24) │ │ │ │ +│ │ │ │ │ │ │ │ +│ │ │ │ ┌────────────────┐ │ │ │ │ +│ │ │ │ │ Windows VM │ │ │ │ │ +│ │ │ │ │ + Managed Disk │ │ │ │ │ +│ │ │ │ └────────────────┘ │ │ │ │ +│ │ │ └──────────────────────┘ │ │ │ +│ │ │ │ │ │ │ +│ │ │ ┌───┴───┐ │ │ │ +│ │ │ │ NIC │ │ │ │ +│ │ │ └───┬───┘ │ │ │ +│ │ └───────────┼────────────────┘ │ │ +│ │ │ │ │ +│ │ ┌───────────┴───────┐ │ │ +│ │ │ Network Security │ │ │ +│ │ │ Group (RDP:3389) │ │ │ +│ │ └───────────────────┘ │ │ +│ │ │ │ │ +│ │ ┌───────────┴───────┐ │ │ +│ │ │ Public IP │ │ │ +│ │ │ (Dynamic) │ │ │ +│ │ └───────────────────┘ │ │ +│ └───────────────────────────────────┘ │ +└─────────────────────────────────────────┘ +``` + +## Security Considerations + +⚠️ **Important**: This is a demo configuration with the following security considerations: + +1. **Open RDP Access**: The NSG allows RDP (port 3389) from any source IP (`*`). For production: + - Restrict source to specific IP ranges + - Use Azure Bastion for secure VM access + - Consider Just-In-Time (JIT) VM access + +2. **Password Authentication**: Uses password authentication. For production: + - Use SSH keys or certificate-based authentication where possible + - Enable Azure AD authentication + - Implement MFA (Multi-Factor Authentication) + +3. **Dynamic Public IP**: The IP changes when VM is deallocated. For production: + - Use Static IP allocation + - Consider using Private Endpoints + - Implement Azure VPN or ExpressRoute + +## Troubleshooting + +### Deployment Fails with "InvalidTemplateDeployment" + +- Ensure your Azure CLI is up to date: `az upgrade` +- Verify you have sufficient permissions at the subscription level +- Check that the VM size is available in the target region + +### Cannot Connect via RDP + +- Verify the VM is running: `az vm get-instance-view --resource-group rg-demo-vm --name ` +- Check NSG rules allow RDP on port 3389 +- Ensure you're using the correct Public IP address +- Verify Windows Firewall on the VM isn't blocking RDP + +### "VM Size Not Available" Error + +Try a different VM size available in Sweden Central: +- `Standard_B1s` (smaller, cheaper) +- `Standard_D2s_v3` (better performance) + +## Cost Estimation + +Approximate monthly costs (as of 2026, Sweden Central region): +- VM (Standard_B2s): ~$30-40/month +- Managed Disk (Standard LRS 127GB): ~$5/month +- Public IP (Dynamic): ~$3/month +- Network bandwidth: Variable based on usage + +**Total**: ~$40-50/month (approximate) + +💡 **Tip**: To minimize costs, deallocate the VM when not in use: +```bash +az vm deallocate --resource-group rg-demo-vm --name +``` + +## Additional Resources + +- [Azure Bicep Documentation](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/) +- [Azure VM Documentation](https://learn.microsoft.com/en-us/azure/virtual-machines/) +- [Azure Virtual Network Documentation](https://learn.microsoft.com/en-us/azure/virtual-network/) +- [Azure CLI Reference](https://learn.microsoft.com/en-us/cli/azure/) + +## Support + +For issues or questions: +1. Check the [Azure Bicep GitHub Issues](https://github.com/Azure/bicep/issues) +2. Review [Azure Documentation](https://learn.microsoft.com/en-us/azure/) +3. Open an issue in this repository \ No newline at end of file diff --git a/infra/bicep/main.bicep b/infra/bicep/main.bicep new file mode 100644 index 0000000..3569c5d --- /dev/null +++ b/infra/bicep/main.bicep @@ -0,0 +1,119 @@ +// Demo Azure VM + Network Infrastructure +// Deploys a Windows Server VM with networking resources + +targetScope = 'subscription' + +// Parameters +@description('Azure region for all resources') +param location string = 'swedencentral' + +@description('Name of the resource group') +@minLength(1) +@maxLength(90) +param resourceGroupName string = 'rg-demo-vm' + +@description('Admin username for the VM') +@minLength(1) +@maxLength(20) +param adminUsername string = 'azureadmin' + +@description('Admin password for the VM') +@secure() +@minLength(12) +param adminPassword string + +@description('VM size for the demo') +param vmSize string = 'Standard_B2s' + +@description('Virtual network address prefix') +param vnetAddressPrefix string = '10.0.0.0/16' + +@description('Subnet address prefix') +param subnetAddressPrefix string = '10.0.0.0/24' + +@description('Prefix for resource naming') +@minLength(1) +@maxLength(10) +param resourcePrefix string = 'demo' + +// Variables +var uniqueSuffix = uniqueString(subscription().subscriptionId, location, resourceGroupName) +var vmName = '${resourcePrefix}-vm-${uniqueSuffix}' +var vnetName = '${resourcePrefix}-vnet-${uniqueSuffix}' +var subnetName = 'default' +var nsgName = '${resourcePrefix}-nsg-${uniqueSuffix}' +var nicName = '${resourcePrefix}-nic-${uniqueSuffix}' +var publicIpName = '${resourcePrefix}-pip-${uniqueSuffix}' + +// Resource Group +resource resourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: location +} + +// Network Security Group +module nsg 'modules/nsg.bicep' = { + scope: resourceGroup + name: 'nsgDeployment' + params: { + location: location + nsgName: nsgName + } +} + +// Virtual Network +module vnet 'modules/vnet.bicep' = { + scope: resourceGroup + name: 'vnetDeployment' + params: { + location: location + vnetName: vnetName + vnetAddressPrefix: vnetAddressPrefix + subnetName: subnetName + subnetAddressPrefix: subnetAddressPrefix + nsgId: nsg.outputs.nsgId + } +} + +// Public IP +module publicIp 'modules/publicip.bicep' = { + scope: resourceGroup + name: 'publicIpDeployment' + params: { + location: location + publicIpName: publicIpName + } +} + +// Network Interface +module nic 'modules/nic.bicep' = { + scope: resourceGroup + name: 'nicDeployment' + params: { + location: location + nicName: nicName + subnetId: vnet.outputs.subnetId + publicIpId: publicIp.outputs.publicIpId + } +} + +// Virtual Machine +module vm 'modules/vm.bicep' = { + scope: resourceGroup + name: 'vmDeployment' + params: { + location: location + vmName: vmName + vmSize: vmSize + adminUsername: adminUsername + adminPassword: adminPassword + nicId: nic.outputs.nicId + } +} + +// Outputs (no secrets) +output resourceGroupName string = resourceGroup.name +output vmName string = vmName +output vnetName string = vnetName +output publicIpAddress string = publicIp.outputs.publicIpAddress +output vmId string = vm.outputs.vmId diff --git a/infra/bicep/main.bicepparam b/infra/bicep/main.bicepparam new file mode 100644 index 0000000..de33864 --- /dev/null +++ b/infra/bicep/main.bicepparam @@ -0,0 +1,25 @@ +// Bicep parameter file for demo VM deployment +using 'main.bicep' + +// Azure region for all resources +param location = 'swedencentral' + +// Resource group name +param resourceGroupName = 'rg-demo-vm' + +// VM admin username (change before deployment) +param adminUsername = 'azureadmin' + +// VM admin password - REQUIRED: Provide at deployment time +// Use --parameters adminPassword='YourSecurePassword123!' or through secure method +// param adminPassword = '' // DO NOT set password in this file + +// VM size - Standard_B2s is low-cost and suitable for demos +param vmSize = 'Standard_B2s' + +// Network configuration - default address spaces +param vnetAddressPrefix = '10.0.0.0/16' +param subnetAddressPrefix = '10.0.0.0/24' + +// Resource naming prefix +param resourcePrefix = 'demo' diff --git a/infra/bicep/modules/nic.bicep b/infra/bicep/modules/nic.bicep new file mode 100644 index 0000000..b58fa22 --- /dev/null +++ b/infra/bicep/modules/nic.bicep @@ -0,0 +1,38 @@ +// Network Interface Module + +@description('Azure region for resources') +param location string + +@description('Name of the Network Interface') +param nicName string + +@description('Subnet resource ID') +param subnetId string + +@description('Public IP resource ID') +param publicIpId string + +// Network Interface +resource networkInterface 'Microsoft.Network/networkInterfaces@2024-01-01' = { + name: nicName + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: subnetId + } + publicIPAddress: { + id: publicIpId + } + } + } + ] + } +} + +output nicId string = networkInterface.id +output nicName string = networkInterface.name diff --git a/infra/bicep/modules/nsg.bicep b/infra/bicep/modules/nsg.bicep new file mode 100644 index 0000000..e6bcd69 --- /dev/null +++ b/infra/bicep/modules/nsg.bicep @@ -0,0 +1,34 @@ +// Network Security Group Module + +@description('Azure region for resources') +param location string + +@description('Name of the Network Security Group') +param nsgName string + +// Network Security Group with basic RDP rule for Windows VM demo +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2024-01-01' = { + name: nsgName + location: location + properties: { + securityRules: [ + { + name: 'AllowRDP' + properties: { + priority: 1000 + protocol: 'Tcp' + access: 'Allow' + direction: 'Inbound' + sourceAddressPrefix: '*' + sourcePortRange: '*' + destinationAddressPrefix: '*' + destinationPortRange: '3389' + description: 'Allow RDP access for demo purposes' + } + } + ] + } +} + +output nsgId string = networkSecurityGroup.id +output nsgName string = networkSecurityGroup.name diff --git a/infra/bicep/modules/publicip.bicep b/infra/bicep/modules/publicip.bicep new file mode 100644 index 0000000..dc20d99 --- /dev/null +++ b/infra/bicep/modules/publicip.bicep @@ -0,0 +1,24 @@ +// Public IP Module + +@description('Azure region for resources') +param location string + +@description('Name of the Public IP') +param publicIpName string + +// Public IP for VM access +resource publicIp 'Microsoft.Network/publicIPAddresses@2024-01-01' = { + name: publicIpName + location: location + sku: { + name: 'Basic' + } + properties: { + publicIPAllocationMethod: 'Dynamic' + publicIPAddressVersion: 'IPv4' + } +} + +output publicIpId string = publicIp.id +output publicIpName string = publicIp.name +output publicIpAddress string = publicIp.properties.ipAddress diff --git a/infra/bicep/modules/vm.bicep b/infra/bicep/modules/vm.bicep new file mode 100644 index 0000000..09e101e --- /dev/null +++ b/infra/bicep/modules/vm.bicep @@ -0,0 +1,73 @@ +// Virtual Machine Module + +@description('Azure region for resources') +param location string + +@description('Name of the Virtual Machine') +param vmName string + +@description('Size of the Virtual Machine') +param vmSize string + +@description('Admin username for the VM') +param adminUsername string + +@description('Admin password for the VM') +@secure() +param adminPassword string + +@description('Network Interface resource ID') +param nicId string + +// Virtual Machine +resource virtualMachine 'Microsoft.Compute/virtualMachines@2024-03-01' = { + name: vmName + location: location + properties: { + hardwareProfile: { + vmSize: vmSize + } + osProfile: { + computerName: vmName + adminUsername: adminUsername + adminPassword: adminPassword + windowsConfiguration: { + enableAutomaticUpdates: true + provisionVMAgent: true + patchSettings: { + patchMode: 'AutomaticByOS' + assessmentMode: 'ImageDefault' + } + } + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + name: '${vmName}-osdisk' + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'Standard_LRS' + } + caching: 'ReadWrite' + } + } + networkProfile: { + networkInterfaces: [ + { + id: nicId + properties: { + primary: true + } + } + ] + } + } +} + +output vmId string = virtualMachine.id +output vmName string = virtualMachine.name diff --git a/infra/bicep/modules/vnet.bicep b/infra/bicep/modules/vnet.bicep new file mode 100644 index 0000000..012dcbf --- /dev/null +++ b/infra/bicep/modules/vnet.bicep @@ -0,0 +1,48 @@ +// Virtual Network Module + +@description('Azure region for resources') +param location string + +@description('Name of the Virtual Network') +param vnetName string + +@description('Virtual Network address prefix') +param vnetAddressPrefix string + +@description('Name of the subnet') +param subnetName string + +@description('Subnet address prefix') +param subnetAddressPrefix string + +@description('Network Security Group resource ID') +param nsgId string + +// Virtual Network with subnet +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-01-01' = { + name: vnetName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + vnetAddressPrefix + ] + } + subnets: [ + { + name: subnetName + properties: { + addressPrefix: subnetAddressPrefix + networkSecurityGroup: { + id: nsgId + } + } + } + ] + } +} + +output vnetId string = virtualNetwork.id +output vnetName string = virtualNetwork.name +output subnetId string = virtualNetwork.properties.subnets[0].id +output subnetName string = virtualNetwork.properties.subnets[0].name From 1dabfa864fa3e6787e2c80812f210efbc9aeb262 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 22:03:20 +0000 Subject: [PATCH 3/3] Address code review feedback: security and SKU improvements - Update Public IP to Standard SKU (Basic deprecated as of Sept 2025) - Change Public IP allocation from Dynamic to Static for stability - Add rdpSourceAddressPrefix parameter for RDP source IP restriction - Update .gitignore to specifically target Bicep artifacts (infra/bicep/**/*.json) - Enhance README with RDP source IP restriction examples - Update security considerations documentation Co-authored-by: robpitcher <13648061+robpitcher@users.noreply.github.com> --- .gitignore | 2 +- infra/bicep/README.md | 42 +++++++++++++++++++++++------- infra/bicep/main.bicep | 4 +++ infra/bicep/main.bicepparam | 5 ++++ infra/bicep/modules/nsg.bicep | 5 +++- infra/bicep/modules/publicip.bicep | 4 +-- 6 files changed, 49 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 9ad1d68..948edf7 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,4 @@ terraform.rc .vscode/settings.json # Bicep build artifacts (ARM JSON templates) -*.json \ No newline at end of file +infra/bicep/**/*.json \ No newline at end of file diff --git a/infra/bicep/README.md b/infra/bicep/README.md index c6d3270..671d872 100644 --- a/infra/bicep/README.md +++ b/infra/bicep/README.md @@ -110,7 +110,7 @@ This will show: - **Username**: `azureadmin` (or what you specified) - **Password**: The password you provided during deployment -**Note**: The Public IP is dynamic (allocated when VM starts). It may change if the VM is deallocated. +**Note**: The Public IP uses Standard SKU with static allocation, so it remains the same even if the VM is deallocated. ## Customization @@ -141,6 +141,25 @@ az deployment sub create \ | `vnetAddressPrefix` | VNet address space | `10.0.0.0/16` | | `subnetAddressPrefix` | Subnet address space | `10.0.0.0/24` | | `resourcePrefix` | Resource naming prefix | `demo` | +| `rdpSourceAddressPrefix` | Source IP/CIDR for RDP access | `*` (any) | + +#### 🔒 Security Tip: Restrict RDP Access + +For better security, restrict RDP access to your IP address: + +```bash +# Get your public IP +MY_IP=$(curl -s ifconfig.me) + +# Deploy with restricted RDP access +az deployment sub create \ + --name demo-vm-deployment \ + --location swedencentral \ + --template-file main.bicep \ + --parameters main.bicepparam \ + --parameters adminPassword='YourPassword!' \ + --parameters rdpSourceAddressPrefix="${MY_IP}/32" +``` ## Clean Up Resources @@ -195,20 +214,25 @@ az group delete --name rg-demo-vm --yes --no-wait ⚠️ **Important**: This is a demo configuration with the following security considerations: -1. **Open RDP Access**: The NSG allows RDP (port 3389) from any source IP (`*`). For production: - - Restrict source to specific IP ranges - - Use Azure Bastion for secure VM access - - Consider Just-In-Time (JIT) VM access +1. **RDP Access Control**: + - By default, the NSG allows RDP (port 3389) from any source IP (`*`) + - **Recommendation**: Use the `rdpSourceAddressPrefix` parameter to restrict access to your IP address + - For production: + - Always restrict source to specific IP ranges + - Use Azure Bastion for secure VM access without public IPs + - Consider Just-In-Time (JIT) VM access + - Enable Azure AD authentication with MFA 2. **Password Authentication**: Uses password authentication. For production: - Use SSH keys or certificate-based authentication where possible - Enable Azure AD authentication - Implement MFA (Multi-Factor Authentication) + - Use Azure Key Vault for credential management -3. **Dynamic Public IP**: The IP changes when VM is deallocated. For production: - - Use Static IP allocation - - Consider using Private Endpoints - - Implement Azure VPN or ExpressRoute +3. **Static Public IP**: The IP remains the same for easier demo access. For production: + - Use Private Endpoints where possible + - Implement Azure VPN or ExpressRoute for private connectivity + - Consider using Azure Bastion instead of public IPs ## Troubleshooting diff --git a/infra/bicep/main.bicep b/infra/bicep/main.bicep index 3569c5d..e5cb701 100644 --- a/infra/bicep/main.bicep +++ b/infra/bicep/main.bicep @@ -36,6 +36,9 @@ param subnetAddressPrefix string = '10.0.0.0/24' @maxLength(10) param resourcePrefix string = 'demo' +@description('Source IP address or range for RDP access. Use * for any source (demo only), or specify your IP/CIDR for better security') +param rdpSourceAddressPrefix string = '*' + // Variables var uniqueSuffix = uniqueString(subscription().subscriptionId, location, resourceGroupName) var vmName = '${resourcePrefix}-vm-${uniqueSuffix}' @@ -58,6 +61,7 @@ module nsg 'modules/nsg.bicep' = { params: { location: location nsgName: nsgName + rdpSourceAddressPrefix: rdpSourceAddressPrefix } } diff --git a/infra/bicep/main.bicepparam b/infra/bicep/main.bicepparam index de33864..00c41b8 100644 --- a/infra/bicep/main.bicepparam +++ b/infra/bicep/main.bicepparam @@ -23,3 +23,8 @@ param subnetAddressPrefix = '10.0.0.0/24' // Resource naming prefix param resourcePrefix = 'demo' + +// RDP Source IP restriction - IMPORTANT: Change to your IP for better security +// Use '*' for any source (demo only, not recommended) +// Use your IP: '203.0.113.45/32' or CIDR range: '203.0.113.0/24' +param rdpSourceAddressPrefix = '*' diff --git a/infra/bicep/modules/nsg.bicep b/infra/bicep/modules/nsg.bicep index e6bcd69..7a87ddc 100644 --- a/infra/bicep/modules/nsg.bicep +++ b/infra/bicep/modules/nsg.bicep @@ -6,6 +6,9 @@ param location string @description('Name of the Network Security Group') param nsgName string +@description('Source IP address or range for RDP access. Use * for any source (demo only), or specify CIDR (e.g., 203.0.113.0/24)') +param rdpSourceAddressPrefix string = '*' + // Network Security Group with basic RDP rule for Windows VM demo resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2024-01-01' = { name: nsgName @@ -19,7 +22,7 @@ resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2024-01-0 protocol: 'Tcp' access: 'Allow' direction: 'Inbound' - sourceAddressPrefix: '*' + sourceAddressPrefix: rdpSourceAddressPrefix sourcePortRange: '*' destinationAddressPrefix: '*' destinationPortRange: '3389' diff --git a/infra/bicep/modules/publicip.bicep b/infra/bicep/modules/publicip.bicep index dc20d99..93aa211 100644 --- a/infra/bicep/modules/publicip.bicep +++ b/infra/bicep/modules/publicip.bicep @@ -11,10 +11,10 @@ resource publicIp 'Microsoft.Network/publicIPAddresses@2024-01-01' = { name: publicIpName location: location sku: { - name: 'Basic' + name: 'Standard' } properties: { - publicIPAllocationMethod: 'Dynamic' + publicIPAllocationMethod: 'Static' publicIPAddressVersion: 'IPv4' } }