Skip to content

Instantly share code, notes, and snippets.

@gavincampbell
Last active June 1, 2020 17:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gavincampbell/58ec298a2127a60e8ce4d787070904fe to your computer and use it in GitHub Desktop.
Save gavincampbell/58ec298a2127a60e8ce4d787070904fe to your computer and use it in GitHub Desktop.
Example code and tests for creating conditional NSG rules using optional parameters
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json",
"contentVersion": "0.0.0.1",
"parameters": {
"vnetName": {
"type": "string"
},
"vnetAddressPrefix": {
"type": "string"
},
"webServerSubnetName": {
"type": "string"
},
"webServerSubnetAddressPrefix": {
"type": "string"
},
"webServerNsgName": {
"type": "string"
},
"testRunnerIpRange": {
"type": "string",
"defaultValue": ""
}
},
"resources": [
{
"name": "[parameters('vnetName')]",
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2019-11-01",
"location": "[resourceGroup().location]",
"dependsOn": [
"[parameters('webServerNsgName')]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('vnetAddressPrefix')]"
]
},
"subnets": [
{
"name": "[parameters('webServerSubnetName')]",
"properties": {
"addressPrefix": "[parameters('webServerSubnetAddressPrefix')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('webServerNsgName'))]"
}
}
}
]
}
},
{
"name": "[parameters('webServerNsgName')]",
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2019-11-01",
"location": "[resourceGroup().location]",
"properties": {
"securityRules": [
{
"name": "DefaultDeny",
"properties": {
"description": "Denies all inbound traffic not matched by a previous rule",
"protocol": "*",
"sourcePortRange": "*",
"destinationPortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Deny",
"priority": 4096,
"direction": "Inbound"
}
}
]
}
},
{
"name": "[concat(parameters('webServerNsgName'),'/allow8081fromTestSubnet')]",
"type": "Microsoft.Network/networkSecurityGroups/securityRules",
"location": "[resourceGroup().location]",
"dependsOn": [
"[parameters('webServerNsgName')]"
],
"condition": "[greater(length(parameters('testRunnerIpRange')),0)]",
"apiVersion": "2019-11-01",
"properties": {
"description": "nsgRuleDescription",
"protocol": "tcp",
"sourcePortRange": "*",
"destinationPortRange": "8081",
"sourceAddressPrefix": "[parameters('testRunnerIpRange')]",
"destinationAddressPrefix": "[parameters('webServerSubnetAddressPrefix')]",
"access": "Allow",
"priority": 100,
"direction": "Inbound"
}
}
]
}
@{
resourceGroupNamePrefix = 'conditionalNsgRulesDemoRg-'
resourceGroupLocation = 'UKSouth'
vNetConfig = @{
vNetName = 'conditionalNsgRulesDemovNet'
addressPrefix = '192.168.0.0/24'
}
webSubnetConfig = @{
subnetName = 'webServerSubnet'
addressPrefix = '192.168.0.0/25'
}
testSubnetConfig = @{
subnetName = 'testSubnet'
addressPrefix = '192.168.0.128/25'
}
nsgName = 'webServerNsg'
}
$scriptRoot = $PSScriptRoot
Describe "NSG Tests" {
BeforeAll {
$Config = Import-PowerShellDataFile -Path $scriptRoot/config.psd1
$someRandomLetters = -join ((65..90) + (97..122) | Get-Random -Count 20 | % {[char]$_})
# source: https://devblogs.microsoft.com/scripting/generate-random-letters-with-powershell/
$resourceGroupName = $Config.resourceGroupNamePrefix + '-' + $someRandomLetters
New-AzResourceGroup -Name $resourceGroupName -Location $Config.resourceGroupLocation
New-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -Location $Config.resourceGroupLocation -AddressPrefix $Config.vNetConfig.addressPrefix
$defaultTemplateParams = @{
vnetName = $Config.vNetConfig.vNetName
vnetAddressPrefix = $Config.vNetConfig.addressPrefix
webServerSubnetName = $Config.webSubnetConfig.subnetName
webServerSubnetAddressPrefix = $Config.webSubnetConfig.addressPrefix
webServerNsgName = $Config.nsgName
}
$defaultDeploymentParams = @{
ResourceGroupName = $resourceGroupName
TemplateFile = "$scriptRoot/azuredeploy.json"
Force = $true
}
$baseCaseAssertions = {
$vNet = Get-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -ExpandResource 'Subnets/NetworkSecurityGroup'
$webServerSubnet = Get-AzVirtualNetworkSubnetConfig -Name $Config.webSubnetConfig.subnetName -VirtualNetwork $vNet
$nsg = $webServerSubnet.NetworkSecurityGroup
It "Creates a vnet Called $($Config.vNetConfig.vNetName)" {
$vNet | Should -Not -BeNullOrEmpty
}
It "Creates a subnet called $($Config.webSubnetConfig.subnetName)" {
$webServerSubnet | Should -Not -BeNullOrEmpty
}
It "Attaches an NSG called $($Config.nsgName) to the subnet $($Config.webSubnetConfig.subnetName)" {
$webServerSubnet.NetworkSecurityGroup.Id.split("/") | select -last 1| Should -Be $Config.nsgName
}
It "Creates a Default Deny rule with priority 4096" {
$nsg.SecurityRules | ?{ $_.Priority -eq 4096 -and $_.Access -eq 'Deny' -and
$_.Direction -eq 'Inbound' -and $_.Protocol -eq '*' -and
$_.SourceAddressPrefix -eq '*' -and $_.DestinationAddressPrefix -eq '*'} |
Should -Not -BeNullOrEmpty
}
}
}
Context "Create the NSG without passing a value to the testRunnerIpRange parameter" {
$TemplateParams = $defaultTemplateParams
$deploymentParams = $defaultDeploymentParams + @{TemplateParameterObject = $TemplateParams; Mode = 'Complete'}
New-AzResourceGroupDeployment @deploymentParams
$vNet = Get-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -ExpandResource 'Subnets/NetworkSecurityGroup'
$webServerSubnet = Get-AzVirtualNetworkSubnetConfig -Name $Config.webSubnetConfig.subnetName -VirtualNetwork $vNet
$nsg = $webServerSubnet.NetworkSecurityGroup
It "Doesn't create an ingress rule for the testRunnerIpRange" {
$nsg.SecurityRules | ?{ $_.Access -eq 'Allow' -and
$_.Direction -eq 'Inbound' -and
$_.SourceAddressPrefix -eq $Config.testSubnetConfig.addressPrefix} |
Should -BeNullOrEmpty
}
Invoke-Command -ScriptBlock $baseCaseAssertions
}
Context "Create the NSG passing $($Config.testSubnetConfig.addressPrefix) to the testRunnerIpRange parameter" {
$TemplateParams = $defaultTemplateParams + @{testRunnerIpRange = $Config.testSubnetConfig.addressPrefix }
$deploymentParams = $defaultDeploymentParams + @{TemplateParameterObject = $TemplateParams; Mode = 'Complete'}
New-AzResourceGroupDeployment @deploymentParams
$vNet = Get-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -ExpandResource 'Subnets/NetworkSecurityGroup'
$webServerSubnet = Get-AzVirtualNetworkSubnetConfig -Name $Config.webSubnetConfig.subnetName -VirtualNetwork $vNet
$nsg = $webServerSubnet.NetworkSecurityGroup
It "Creates an ingress rule for the $($Config.testSubnetConfig.addressPrefix) CIDR" {
$nsg.SecurityRules | ?{ $_.Access -eq 'Allow' -and
$_.Direction -eq 'Inbound' -and
$_.DestinationPortRange -eq "8081" -and
$_.SourceAddressPrefix -eq $Config.testSubnetConfig.addressPrefix} |
Should -Not -BeNullOrEmpty
}
Invoke-Command -ScriptBlock $baseCaseAssertions
}
Context "Create the nsg in complete mode with the testRunnerIpRange parameter set then redeploy in Incremental Mode with the testRunnerIPRange parameter removed" {
$TemplateParams = $defaultTemplateParams + @{testRunnerIpRange = $Config.testSubnetConfig.addressPrefix }
$deploymentParams = $defaultDeploymentParams + @{TemplateParameterObject = $TemplateParams; Mode = 'Complete'}
New-AzResourceGroupDeployment @deploymentParams
$vNet = Get-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -ExpandResource 'Subnets/NetworkSecurityGroup'
$webServerSubnet = Get-AzVirtualNetworkSubnetConfig -Name $Config.webSubnetConfig.subnetName -VirtualNetwork $vNet
$nsg = $webServerSubnet.NetworkSecurityGroup
It "Creates the nsg rule on the initial deployment" {
$nsg.SecurityRules | ?{ $_.Access -eq 'Allow' -and
$_.Direction -eq 'Inbound' -and
$_.DestinationPortRange -eq "8081" -and
$_.SourceAddressPrefix -eq $Config.testSubnetConfig.addressPrefix} |
Should -Not -BeNullOrEmpty
}
$TemplateParams = $defaultTemplateParams
$deploymentParams = $defaultDeploymentParams + @{TemplateParameterObject = $TemplateParams; Mode = 'Incremental'}
New-AzResourceGroupDeployment @deploymentParams
$vNet = Get-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -ExpandResource 'Subnets/NetworkSecurityGroup'
$webServerSubnet = Get-AzVirtualNetworkSubnetConfig -Name $Config.webSubnetConfig.subnetName -VirtualNetwork $vNet
$nsg = $webServerSubnet.NetworkSecurityGroup
It "Deletes the Security Rule on the subsequent incremental deployment" {
$nsg.SecurityRules | ?{ $_.Access -eq 'Allow' -and
$_.Direction -eq 'Inbound' -and
$_.DestinationPortRange -eq "8081" -and
$_.SourceAddressPrefix -eq $Config.testSubnetConfig.addressPrefix} |
Should -BeNullOrEmpty
}
Invoke-Command -ScriptBlock $baseCaseAssertions
}
Context "Create the nsg in complete mode with the testRunnerIpRange parameter set then redeploy in Complete Mode with the testRunnerIPRange parameter removed" {
$TemplateParams = $defaultTemplateParams + @{testRunnerIpRange = $Config.testSubnetConfig.addressPrefix }
$deploymentParams = $defaultDeploymentParams + @{TemplateParameterObject = $TemplateParams; Mode = 'Complete'}
New-AzResourceGroupDeployment @deploymentParams
$vNet = Get-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -ExpandResource 'Subnets/NetworkSecurityGroup'
$webServerSubnet = Get-AzVirtualNetworkSubnetConfig -Name $Config.webSubnetConfig.subnetName -VirtualNetwork $vNet
$nsg = $webServerSubnet.NetworkSecurityGroup
It "Creates the nsg rule on the initial deployment" {
$nsg.SecurityRules | ?{ $_.Access -eq 'Allow' -and
$_.Direction -eq 'Inbound' -and
$_.DestinationPortRange -eq "8081" -and
$_.SourceAddressPrefix -eq $Config.testSubnetConfig.addressPrefix} |
Should -Not -BeNullOrEmpty
}
$TemplateParams = $defaultTemplateParams
$deploymentParams = $defaultDeploymentParams + @{TemplateParameterObject = $TemplateParams; Mode = 'Complete'}
New-AzResourceGroupDeployment @deploymentParams
$vNet = Get-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -ExpandResource 'Subnets/NetworkSecurityGroup'
$webServerSubnet = Get-AzVirtualNetworkSubnetConfig -Name $Config.webSubnetConfig.subnetName -VirtualNetwork $vNet
$nsg = $webServerSubnet.NetworkSecurityGroup
It "Deletes the Security Rule on the subsequent Complete Deployment" {
$nsg.SecurityRules | ?{ $_.Access -eq 'Allow' -and
$_.Direction -eq 'Inbound' -and
$_.DestinationPortRange -eq "8081" -and
$_.SourceAddressPrefix -eq $Config.testSubnetConfig.addressPrefix} |
Should -BeNullOrEmpty
}
Invoke-Command -ScriptBlock $baseCaseAssertions
}
Context "Create the nsg in complete mode with the testRunnerIpRange parameter unset then redeploy in Incremental Mode with the testRunnerIPRange parameter added" {
$TemplateParams = $defaultTemplateParams
$deploymentParams = $defaultDeploymentParams + @{TemplateParameterObject = $TemplateParams; Mode = 'Complete'}
New-AzResourceGroupDeployment @deploymentParams
$vNet = Get-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -ExpandResource 'Subnets/NetworkSecurityGroup'
$webServerSubnet = Get-AzVirtualNetworkSubnetConfig -Name $Config.webSubnetConfig.subnetName -VirtualNetwork $vNet
$nsg = $webServerSubnet.NetworkSecurityGroup
It "Doesn't create the nsg rule on the initial deployment" {
$nsg.SecurityRules | ?{ $_.Access -eq 'Allow' -and
$_.Direction -eq 'Inbound' -and
$_.DestinationPortRange -eq "8081" -and
$_.SourceAddressPrefix -eq $Config.testSubnetConfig.addressPrefix} |
Should -BeNullOrEmpty
}
$TemplateParams = $defaultTemplateParams + @{testRunnerIpRange = $Config.testSubnetConfig.addressPrefix }
$deploymentParams = $defaultDeploymentParams + @{TemplateParameterObject = $TemplateParams; Mode = 'Incremental'}
New-AzResourceGroupDeployment @deploymentParams
$vNet = Get-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -ExpandResource 'Subnets/NetworkSecurityGroup'
$webServerSubnet = Get-AzVirtualNetworkSubnetConfig -Name $Config.webSubnetConfig.subnetName -VirtualNetwork $vNet
$nsg = $webServerSubnet.NetworkSecurityGroup
It "Creates the Security Rule on the subsequent incremental deployment" {
$nsg.SecurityRules | ?{ $_.Access -eq 'Allow' -and
$_.Direction -eq 'Inbound' -and
$_.DestinationPortRange -eq "8081" -and
$_.SourceAddressPrefix -eq $Config.testSubnetConfig.addressPrefix} |
Should -Not -BeNullOrEmpty
}
Invoke-Command -ScriptBlock $baseCaseAssertions
}
Context "Create the nsg in complete mode with the testRunnerIpRange parameter unset then redeploy in Complete Mode with the testRunnerIPRange parameter added" {
$TemplateParams = $defaultTemplateParams
$deploymentParams = $defaultDeploymentParams + @{TemplateParameterObject = $TemplateParams; Mode = 'Complete'}
New-AzResourceGroupDeployment @deploymentParams
$vNet = Get-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -ExpandResource 'Subnets/NetworkSecurityGroup'
$webServerSubnet = Get-AzVirtualNetworkSubnetConfig -Name $Config.webSubnetConfig.subnetName -VirtualNetwork $vNet
$nsg = $webServerSubnet.NetworkSecurityGroup
It "Doesn't create the nsg rule on the initial deployment" {
$nsg.SecurityRules | ?{ $_.Access -eq 'Allow' -and
$_.Direction -eq 'Inbound' -and
$_.DestinationPortRange -eq "8081" -and
$_.SourceAddressPrefix -eq $Config.testSubnetConfig.addressPrefix} |
Should -BeNullOrEmpty
}
$TemplateParams = $defaultTemplateParams + @{testRunnerIpRange = $Config.testSubnetConfig.addressPrefix }
$deploymentParams = $defaultDeploymentParams + @{TemplateParameterObject = $TemplateParams; Mode = 'Complete'}
New-AzResourceGroupDeployment @deploymentParams
$vNet = Get-AzVirtualNetwork -Name $Config.vNetConfig.vNetName -ResourceGroupName $resourceGroupName -ExpandResource 'Subnets/NetworkSecurityGroup'
$webServerSubnet = Get-AzVirtualNetworkSubnetConfig -Name $Config.webSubnetConfig.subnetName -VirtualNetwork $vNet
$nsg = $webServerSubnet.NetworkSecurityGroup
It "Creates the Security Rule on the subsequent Complete Deployment" {
$nsg.SecurityRules | ?{ $_.Access -eq 'Allow' -and
$_.Direction -eq 'Inbound' -and
$_.DestinationPortRange -eq "8081" -and
$_.SourceAddressPrefix -eq $Config.testSubnetConfig.addressPrefix} |
Should -Not -BeNullOrEmpty
}
Invoke-Command -ScriptBlock $baseCaseAssertions
}
AfterAll {
Remove-AzResourceGroup -Name $resourceGroupName -Verbose -Force
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment