Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save rupertbenbrook/b025e1925ccbde7429a74f87b5b28dac to your computer and use it in GitHub Desktop.
Save rupertbenbrook/b025e1925ccbde7429a74f87b5b28dac to your computer and use it in GitHub Desktop.
Script to update all the Azure Network Security Groups in a subscription that have specific tags on them to indicate the source or destination addresses of the NSG rules need to be updated from DNS lookups. Useful when wanting to set NSGs for specific DNS names as opposed to IP addresses, and can be run on a schedule in an Azure Automation Runbook.
# 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment