Предположим, что сетевая команда выделила нам диапазон IP-адресов 10.172.0.0/16 для будущих Landing Zones в Azure. Цель — автоматизировать расчёт IP-диапазонов, создав инструмент, который будет автоматически вычислять нужные нам диапазоны на основе простых и понятных входных данных о будущих сетях.

Этот ноутбук демонстрирует, как достичь этого с помощью модуля ipmgmt.

Начнём с установки модуля:

Install-Module ipmgmt -Scope CurrentUser

А теперь импортируем его:

Import-Module ipmgmt

Модуль ipmgmt состоит всего из двух командлетов. Get-VLSMBreakdown разбивает диапазон на более мелкие, что позволяет сегментировать диапазон на VNET’ы, а затем каждый VNET на подсети. Get-IPRanges, имея список используемых диапазонов и “корневой” диапазон, пытается найти свободный слот нужного размера — это удобно для предотвращения потерь IP-пространства.

Get-Command -Module ipmgmt
CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Function        Get-IPRanges                                       0.1.5      ipmgmt
Function        Get-VLSMBreakdown                                  0.1.5      ipmgmt

Разобьём наш крупный “корневой” IP-диапазон на более мелкие. Для этого подготовим список поддиапазонов в виде хэш-таблиц PowerShell: @{type = "VNET-HUB"; size = (256-2)}. Здесь мы указываем, что имя диапазона VNET-HUB, а размер — 256-2, т.е. максимальное число IP в подсети /24 за вычетом первого и последнего IP.

Если требуется несколько подсетей, создаём массив таких таблиц:

$subnets = @{type = "VNET-HUB"; size = (256-2)},
           @{type = "VNET-A"; size = (256-2)}

Теперь попытаемся разбить корневую сеть:

Get-VLSMBreakdown -Network 10.172.0.0/16 -SubnetSize $subnets | ft type, network, netmask, *usable, cidr -AutoSize
type     Network      Netmask       FirstUsable  LastUsable     Usable Cidr
----     -------      -------       -----------  ----------     ------ ----
VNET-A   10.172.1.0   255.255.255.0 10.172.1.1   10.172.1.254      254   24
VNET-HUB 10.172.0.0   255.255.255.0 10.172.0.1   10.172.0.254      254   24
reserved 10.172.128.0 255.255.128.0 10.172.128.1 10.172.255.254  32766   17
reserved 10.172.64.0  255.255.192.0 10.172.64.1  10.172.127.254  16382   18
reserved 10.172.32.0  255.255.224.0 10.172.32.1  10.172.63.254    8190   19
reserved 10.172.16.0  255.255.240.0 10.172.16.1  10.172.31.254    4094   20
reserved 10.172.8.0   255.255.248.0 10.172.8.1   10.172.15.254    2046   21
reserved 10.172.4.0   255.255.252.0 10.172.4.1   10.172.7.254     1022   22
reserved 10.172.2.0   255.255.254.0 10.172.2.1   10.172.3.254      510   23

Здесь мы получили два диапазона: VNET-A и VNET-HUB. При этом образовались неиспользуемые слоты в корневом диапазоне, которые помечены как reserved для наглядности. Чем мельче создаваемые подсети, тем больше таких “резервных” диапазонов останется.

Также можно использовать CIDR-нотацию:

$subnets = @{type = "GTWSUBNET"; cidr = 27},
@{type = "DMZSUBNET"; cidr = 26},
@{type = "EDGSUBNET"; cidr = 27},
@{type = "APPSUBNET"; cidr = 26},
@{type = "CRESUBNET"; cidr = 26}

Get-VLSMBreakdown -Network 10.10.5.0/24 -SubnetSizeCidr $subnets | ft -AutoSize
type      Network     AddressFamily Netmask         Broadcast   FirstUsable LastUsable  Usable Total
----      -------     ------------- -------         ---------   ----------- ----------  ------ -----
EDGSUBNET 10.10.5.224  InterNetwork 255.255.255.224 10.10.5.255 10.10.5.225 10.10.5.254     30   32
GTWSUBNET 10.10.5.192  InterNetwork 255.255.255.224 10.10.5.223 10.10.5.193 10.10.5.222     30   32
CRESUBNET 10.10.5.128  InterNetwork 255.255.255.192 10.10.5.191 10.10.5.129 10.10.5.190     62   64
APPSUBNET 10.10.5.64   InterNetwork 255.255.255.192 10.10.5.127 10.10.5.65  10.10.5.126     62   64
DMZSUBNET 10.10.5.0    InterNetwork 255.255.255.192 10.10.5.63  10.10.5.1   10.10.5.62      62   64

Теперь давайте это использовать. Для этого нужно пройти аутентификацию в Azure. Локально можно просто выполнить:

Login-AzAccount

В Binder’е это будет немного иначе:

Connect-AzAccount -UseDeviceAuthentication

После аутентификации можно создавать сети. Например, так (отфильтруем reserved):

$vnets = Get-VLSMBreakdown -Network 10.172.0.0/16 -SubnetSize $subnets | ? type -ne 'reserved'

$vnets | % {
    New-AzVirtualNetwork -Name  $_.type -ResourceGroupName 'vnet-test' `
                         -Location 'eastus2' -AddressPrefix "$($_.Network)/$($_.cidr)" | select name, AddressSpace, ResourceGroupName, Location
}

Теперь допустим, что нужно добавить ещё несколько сетей и, возможно, использовать один из reserved слотов, если он подходит по размеру. Для этого и используется Get-IPRanges — он получает список используемых диапазонов и возвращает свободные слоты нужного размера. Например:

Get-IPRanges -Networks "10.172.1.0/24", "10.172.0.0/24" -CIDR 22 -BaseNet "10.172.0.0/16" | ft -AutoSize
IsFree Network    AddressFamily Netmask       Broadcast    FirstUsable LastUsable   Usable Total Cidr
------ -------    ------------- -------       ---------    ----------- ----------   ------ ----- --
False  10.172.0.0  InterNetwork 255.255.255.0 10.172.0.255 10.172.0.1  10.172.0.254    254   256 24
False  10.172.1.0  InterNetwork 255.255.255.0 10.172.1.255 10.172.1.1  10.172.1.254    254   256 24
True   10.172.4.0  InterNetwork 255.255.252.0 10.172.7.255 10.172.4.1  10.172.7.254   1022  1024 22

Что если нужно найти сразу несколько диапазонов? Без проблем. Можно использовать такой скрипт:

$cidrRange = 25,25,24,24,24,24,23,25,26,26 | sort
$existingRanges = (Get-AzVirtualNetwork -ResourceGroupName vnet-test | 
    select name, @{l = "AddressSpace"; e = { $_.AddressSpace.AddressPrefixes }}, ResourceGroupName, Location |
    select -expand AddressSpace)
$existingNetworks = $existingRanges | % {[System.Net.IPNetwork]$_}
$nets = $existingRanges

$ret = @()

$cidrRange | % {
    $ret = Get-IPRanges -Networks $nets -CIDR $_ -BaseNet "10.172.0.0/16"
    $nets = ($ret | select @{l="range"; e = {"$($_.network)/$($_.cidr)"}}).range
}

$ret | % {
    if ( -not ($_ -in $existingNetworks)) {$_.IsFree = $true}
}

$ret | ft -AutoSize
IsFree Network      AddressFamily Netmask         Broadcast    FirstUsable  LastUsable   Usable Total
------ -------      ------------- -------         ---------    -----------  ----------   ------ ---
False 10.172.0.0    InterNetwork 255.255.255.0   10.172.0.255 10.172.0.1   10.172.0.254    254 256
False 10.172.1.0    InterNetwork 255.255.255.0   10.172.1.255 10.172.1.1   10.172.1.254    254 256
True  10.172.2.0    InterNetwork 255.255.254.0   10.172.3.255 10.172.2.1   10.172.3.254    510 512
True  10.172.4.0    InterNetwork 255.255.255.0   10.172.4.255 10.172.4.1   10.172.4.254    254 256
True  10.172.5.0    InterNetwork 255.255.255.0   10.172.5.255 10.172.5.1   10.172.5.254    254 256
True  10.172.6.0    InterNetwork 255.255.255.0   10.172.6.255 10.172.6.1   10.172.6.254    254 256
True  10.172.7.0    InterNetwork 255.255.255.0   10.172.7.255 10.172.7.1   10.172.7.254    254 256
True  10.172.8.0    InterNetwork 255.255.255.128 10.172.8.127 10.172.8.1   10.172.8.126    126 128
True  10.172.8.128  InterNetwork 255.255.255.128 10.172.8.255 10.172.8.129 10.172.8.254    126 128
True  10.172.9.0    InterNetwork 255.255.255.128 10.172.9.127 10.172.9.1   10.172.9.126    126 128
True  10.172.9.128  InterNetwork 255.255.255.192 10.172.9.191 10.172.9.129 10.172.9.190     62  64
True  10.172.9.192  InterNetwork 255.255.255.192 10.172.9.255 10.172.9.193 10.172.9.254     62  64

Теперь у нас есть вся необходимая информация, чтобы расширить нашу сетевую архитектуру в Azure.