modules/NSGCreation/NSGCreation.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# Load Modules
Import-Module ((Split-Path $PSScriptRoot -Parent) + "\Log\Log.psd1")
Import-Module ((Split-Path $PSScriptRoot -Parent) + "\UpdateVmssInstances\UpdateVmssInstances.psd1")
function NSGCreation {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $True)][Microsoft.Azure.Commands.Network.Models.PSLoadBalancer] $BasicLoadBalancer,
        [Parameter(Mandatory = $True)][Microsoft.Azure.Commands.Network.Models.PSLoadBalancer] $StdLoadBalancer
    )
    log -Message "[NSGCreation] Initiating NSG Creation"

    log -Message "[NSGCreation] Looping all VMSS in the backend pool of the Load Balancer"
    $vmssIds = $BasicLoadBalancer.BackendAddressPools.BackendIpConfigurations.id | Foreach-Object { ($_ -split '/virtualMachines/')[0] } | Select-Object -Unique    
    
    foreach ($vmssId in $vmssIds) {
        $vmss = Get-AzResource -ResourceId $vmssId | Get-AzVmss

        # Check if VMSS already has a NSG
        log -Message "[NSGCreation] Checking if VMSS Named: $($vmss.Name) has a NSG"
        if (![string]::IsNullOrEmpty($vmss.VirtualMachineProfile.NetworkProfile.NetworkInterfaceConfigurations.NetworkSecurityGroup)) {
            log -Message "[NSGCreation] NSG detected in VMSS Named: $($vmss.Name) NetworkInterfaceConfigurations.NetworkSecurityGroup Id: $($vmss.VirtualMachineProfile.NetworkProfile.NetworkInterfaceConfigurations.NetworkSecurityGroup.Id)" -severity "Warning"
            log -Message "[NSGCreation] NSG will not be created for VMSS Named: $($vmss.Name)" -severity "Warning"
            break
        }
        log -Message "[NSGCreation] NSG not detected."

        log -Message "[NSGCreation] Creating NSG for VMSS: $vmssName"

        try {
            $ErrorActionPreference = 'Stop'
            $nsg = New-AzNetworkSecurityGroup -ResourceGroupName $vmss.ResourceGroupName -Name ("NSG-" + $vmss.Name) -Location $vmss.Location -Force
        }
        catch {
            $message = @"
            [NSGCreation] An error occured while creating NSG '$("NSG-"+$vmss.Name)'. TRAFFIC FROM LOAD BALANCER TO BACKEND POOL MEMBERS WILL
            BE BLOCKED UNTIL AN NSG WITH AN ALLOW RULE IS CREATED! To recover, manually create an NSG which allows traffic to the
            backend ports on the VM/VMSS and associate it with the VM, VMSS, or subnet. Error: $_
"@

            log 'Error' $message
            Exit
        }

        log -Message "[NSGCreation] NSG Named: $("NSG-"+$vmss.Name) created."

        # Adding NSG Rule for each Load Balancing Rule
        # Note: For now I'm assuming there is no way to have more than one VMSS in a single LB
        log -Message "[NSGCreation] Adding one NSG Rule for each Load Balancing Rule"
        $loadBalancingRules = $BasicLoadBalancer.LoadBalancingRules
        $priorityCount = 100
        foreach ($loadBalancingRule in $loadBalancingRules) {
            $networkSecurityRuleConfig = @{
                Name                                = ($loadBalancingRule.Name + "-loadBalancingRule")
                Protocol                            = $loadBalancingRule.Protocol
                SourcePortRange                     = "*"
                DestinationPortRange                = $loadBalancingRule.BackendPort
                SourceAddressPrefix                 = "*"
                DestinationAddressPrefix            = "*"
                SourceApplicationSecurityGroup      = $null
                DestinationApplicationSecurityGroup = $null
                Access                              = "Allow"
                Priority                            = $priorityCount
                Direction                           = "Inbound"
            }
            log -Message "[NSGCreation] Adding NSG Rule Named: $($networkSecurityRuleConfig.Name) to NSG Named: $($nsg.Name)"
            $nsg | Add-AzNetworkSecurityRuleConfig @networkSecurityRuleConfig > $null
            $priorityCount++
        }

        # Adding NSG Rule for each inboundNAT Rule
        log -Message "[NSGCreation] Adding one NSG Rule for each inboundNatRule"
        $networkSecurityRuleConfig = $null
        $inboundNatRules = $BasicLoadBalancer.InboundNatRules
        foreach ($inboundNatRule in $inboundNatRules) {
            if([string]::IsNullOrEmpty($inboundNatRule.FrontendPortRangeStart)){
                $dstportrange = ($inboundNatRule.BackendPort).ToString()
            }
            else{
                $dstportrange = (($inboundNatRule.FrontendPortRangeStart).ToString() + "-" + ($inboundNatRule.FrontendPortRangeEnd).ToString())
            }
            $networkSecurityRuleConfig = @{
                Name                                = ($inboundNatRule.Name + "-NatRule")
                Protocol                            = $inboundNatRule.Protocol
                SourcePortRange                     = "*"
                DestinationPortRange                = $dstportrange
                SourceAddressPrefix                 = "*"
                DestinationAddressPrefix            = "*"
                SourceApplicationSecurityGroup      = $null
                DestinationApplicationSecurityGroup = $null
                Access                              = "Allow"
                Priority                            = $priorityCount
                Direction                           = "Inbound"
            }
            log -Message "[NSGCreation] Adding NSG Rule Named: $($networkSecurityRuleConfig.Name) to NSG Named: $($nsg.Name)"
            $nsg | Add-AzNetworkSecurityRuleConfig @networkSecurityRuleConfig > $null
            $priorityCount++
        }

        # Saving NSG
        log -Message "[NSGCreation] Saving NSG Named: $($nsg.Name)"
        try {
            $ErrorActionPreference = 'Stop'
            Set-AzNetworkSecurityGroup -NetworkSecurityGroup $nsg > $null
        }
        catch {
            $message = @"
            [NSGCreation] An error occured while adding security rules to NSG '$("NSG-"+$vmss.Name)'. TRAFFIC FROM LOAD BALANCER TO BACKEND POOL MEMBERS WILL
            BE BLOCKED UNTIL AN NSG WITH AN ALLOW RULE IS CREATED! To recover, manually rules in NSG '$("NSG-"+$vmss.Name)' which allows traffic
            to the backend ports on the VM/VMSS and associate the NSG with the VM, VMSS, or subnet. Error: $_
"@

            log 'Error' $message
            Exit
        }

        # Adding NSG to VMSS
        log -Message "[NSGCreation] Adding NSG Named: $($nsg.Name) to VMSS Named: $($vmss.Name)"
        foreach ($networkInterfaceConfiguration in $vmss.VirtualMachineProfile.NetworkProfile.NetworkInterfaceConfigurations) {
            $networkInterfaceConfiguration.NetworkSecurityGroup = $nsg.Id
        }

        # Saving VMSS
        log -Message "[NSGCreation] Saving VMSS Named: $($vmss.Name)"
        try {
            $ErrorActionPreference = 'Stop'
            Update-AzVmss -ResourceGroupName $vmss.ResourceGroupName -VMScaleSetName $vmss.Name -VirtualMachineScaleSet $vmss > $null
        }
        catch {
            $message = @"
            [NSGCreation] An error occured while updating VMSS '$($vmss.name)' to associate the new NSG '$("NSG-"+$vmss.Name)'. TRAFFIC FROM LOAD BALANCER TO
            BACKEND POOL MEMBERS WILL BE BLOCKED UNTIL AN NSG WITH AN ALLOW RULE IS CREATED! To recover, manually associate NSG '$("NSG-"+$vmss.Name)'
            with the VM, VMSS, or subnet. Error: $_
"@

            log 'Error' $message
            Exit
        }

        UpdateVmssInstances -vmss $vmss
    }
    log -Message "[NSGCreation] NSG Creation Completed"
}

Export-ModuleMember -Function NSGCreation