|
# NSGs need to have the tags UpdateInboundSrcFromDns and/or UpdateOutboundDstFromDns set |
|
# Tag values follow the pattern <ruleNamePrefix>:<dnsName>,<ruleNamePrefix>:<dnsName>,etc. |
|
# <ruleNamePrefix> is the name of the rule to be updated |
|
# <dnsName> is the DNS name to lookup the addresses for |
|
# Using the tag UpdateInboundSrcFromDns updates the SourceAddressPrefix of the matching rule to the addresses for the DNS lookup |
|
# Using the tag UpdateOutboundDstFromDns updates the DestinationAddressPrefix of the matching rule to the addresses for the DNS lookup |
|
# A single DNS name can resolve to one or more addresses, so a rule will be created for each address |
|
# Each rule created will increase the priority of the original rule by one for each address, so rules need to be spaced in priority appropriately |
|
# This script can be scheduled in an Azure Automation Runbook to regularly update NSGs from DNS, allowing NSGs to adapt to DNS changes |
|
# If this is done, the schedule for the script should be something less than the TTL of the DNS records involved |
|
|
|
function Get-AzureRmNetworkSecurityGroupWithDnsUpdateTags { |
|
[array](Find-AzureRmResource -TagName "UpdateOutboundDstFromDns" | ? ResourceType -eq "Microsoft.Network/networkSecurityGroups") + |
|
[array](Find-AzureRmResource -TagName "UpdateInboundSrcFromDns" | ? ResourceType -eq "Microsoft.Network/networkSecurityGroups") | |
|
Select-Object -Unique | %{ |
|
Get-AzureRmNetworkSecurityGroup -ResourceGroupName $_.ResourceGroupName -Name $_.Name |
|
} |
|
} |
|
|
|
function Write-HostNetworkSecurityGroupRuleConfig { |
|
param ( |
|
[Parameter(Mandatory = $true)] |
|
[Microsoft.Azure.Commands.Network.Models.PSNetworkSecurityGroup]$NetworkSecurityGroup |
|
) |
|
|
|
$NetworkSecurityGroup.SecurityRules | Sort-Object Direction,Priority | ft Name,Direction,Access,Priority,Protocol,SourcePortRange,SourceAddressPrefix,DestinationPortRange,DestinationAddressPrefix |
|
} |
|
|
|
function Get-DnsUpdateRules { |
|
param ( |
|
[Parameter(Mandatory = $true)] |
|
[string]$RuleDefinition |
|
) |
|
|
|
# Each rule separated by a comma |
|
$rules = $RuleDefinition.Split(',') |
|
|
|
# Each rule name prefix and DNS name separated by a colon |
|
$rules | %{ |
|
$rule = $_.Split(':') |
|
|
|
# Create a PSObject for the rule and resolve DNS name to addresses |
|
New-Object -TypeName PSObject -Property @{ |
|
RuleNamePrefix = $rule[0]; |
|
Addresses = [array]([System.Net.Dns]::GetHostAddresses($rule[1]) | Select-Object -ExpandProperty IPAddressToString) |
|
} |
|
} |
|
} |
|
|
|
function Update-AzureRmNetworkSecurityGroupFromDnsUpdateRules { |
|
param ( |
|
[Parameter(Mandatory = $true)] |
|
[Microsoft.Azure.Commands.Network.Models.PSNetworkSecurityGroup]$NetworkSecurityGroup, |
|
|
|
[Parameter(Mandatory = $true)] |
|
[array]$Rules, |
|
|
|
[Parameter(Mandatory = $true)] |
|
[string]$RuleParameterForAddress |
|
) |
|
|
|
$Rules | %{ |
|
$rule = $_ |
|
$ruleNameMatches = $NetworkSecurityGroup.SecurityRules | ? Name -like "$($_.RuleNamePrefix)*" |
|
$ruleTemplate = $ruleNameMatches | Select-Object -First 1 |
|
if ($ruleTemplate -ne $null) { |
|
$ruleNameMatches | %{ |
|
$dummy = $NetworkSecurityGroup.SecurityRules.Remove($_) |
|
} |
|
$_.Addresses | %{ $index = 0} { |
|
Write-Host "Adding address $_ for rule name prefix $($rule.RuleNamePrefix)..." |
|
$params = @{ |
|
NetworkSecurityGroup = $NetworkSecurityGroup; |
|
Name = "$($rule.RuleNamePrefix)-$($index + 1)"; |
|
Direction = $ruleTemplate.Direction; |
|
Access = $ruleTemplate.Access; |
|
Priority = ($ruleTemplate.Priority + $index); |
|
Protocol = $ruleTemplate.Protocol; |
|
SourcePortRange = $ruleTemplate.SourcePortRange; |
|
SourceAddressPrefix = $ruleTemplate.SourceAddressPrefix; |
|
DestinationPortRange = $ruleTemplate.DestinationPortRange; |
|
DestinationAddressPrefix = $ruleTemplate.DestinationAddressPrefix; |
|
} |
|
$params[$RuleParameterForAddress] = "$_/32" |
|
$dummy = Add-AzureRmNetworkSecurityRuleConfig @params |
|
$index++ |
|
} |
|
} else { |
|
Write-Host "Rule name prefix $($_.RuleNamePrefix) not found" |
|
} |
|
} |
|
} |
|
|
|
function Update-AzureRmNetworkSecurityGroupRuleConfigFromDnsUpdateTags { |
|
# Find tagged NSGs |
|
$nsgs = Get-AzureRmNetworkSecurityGroupWithDnsUpdateTags |
|
|
|
# Update rules based on tag values |
|
$nsgs | %{ |
|
$nsg = $_ |
|
Write-Host "Found tagged network security group $($nsg.Id)" |
|
Write-HostNetworkSecurityGroupRuleConfig -NetworkSecurityGroup $nsg |
|
|
|
Write-Host "Updating inbound rules" |
|
$inboundRules = Get-DnsUpdateRules -RuleDefinition $nsg.Tag["UpdateInboundSrcFromDns"] |
|
Update-AzureRmNetworkSecurityGroupFromDnsUpdateRules -NetworkSecurityGroup $nsg -Rules $inboundRules -RuleParameterForAddress "SourceAddressPrefix" |
|
|
|
Write-Host "Updating outbound rules" |
|
$ouboundRules = Get-DnsUpdateRules -RuleDefinition $nsg.Tag["UpdateOutboundDstFromDns"] |
|
Update-AzureRmNetworkSecurityGroupFromDnsUpdateRules -NetworkSecurityGroup $nsg -Rules $ouboundRules -RuleParameterForAddress "DestinationAddressPrefix" |
|
|
|
Write-Host "Updating network security group $($nsg.Id)" |
|
Write-HostNetworkSecurityGroupRuleConfig -NetworkSecurityGroup $nsg |
|
$dummy = $nsg | Set-AzureRmNetworkSecurityGroup |
|
} |
|
} |
|
|
|
Update-AzureRmNetworkSecurityGroupRuleConfigFromDnsUpdateTags |