135 lines
5.8 KiB
PowerShell
135 lines
5.8 KiB
PowerShell
$repositoryRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
|
|
$serverBootstrapPath = Join-Path $repositoryRoot 'scripts\Initialize-SguDomainController.ps1'
|
|
$clientBootstrapPath = Join-Path $repositoryRoot 'scripts\Invoke-SguClientBootstrap.ps1'
|
|
$azureClientPath = Join-Path $repositoryRoot 'scripts\Install-SguAzureP2sClient.ps1'
|
|
$bicepPath = Join-Path $repositoryRoot 'infra\azure\main.bicep'
|
|
|
|
$tokens = $null
|
|
$parseErrors = $null
|
|
$serverAst = [Management.Automation.Language.Parser]::ParseFile(
|
|
$serverBootstrapPath,
|
|
[ref]$tokens,
|
|
[ref]$parseErrors)
|
|
if ($parseErrors.Count -gt 0) {
|
|
throw ($parseErrors -join [Environment]::NewLine)
|
|
}
|
|
$networkFunctionNames = @(
|
|
'Test-PrivateIPv4Address',
|
|
'ConvertTo-NetworkCidr',
|
|
'ConvertTo-PrivateNetworkCidr'
|
|
)
|
|
$networkFunctions = $serverAst.FindAll({
|
|
param($node)
|
|
$node -is [Management.Automation.Language.FunctionDefinitionAst] -and
|
|
$networkFunctionNames -contains $node.Name
|
|
}, $true)
|
|
Invoke-Expression (($networkFunctions | ForEach-Object { $_.Extent.Text }) -join [Environment]::NewLine)
|
|
|
|
$clientTokens = $null
|
|
$clientParseErrors = $null
|
|
$clientAst = [Management.Automation.Language.Parser]::ParseFile(
|
|
$clientBootstrapPath,
|
|
[ref]$clientTokens,
|
|
[ref]$clientParseErrors)
|
|
if ($clientParseErrors.Count -gt 0) {
|
|
throw ($clientParseErrors -join [Environment]::NewLine)
|
|
}
|
|
$clientNetworkFunctions = $clientAst.FindAll({
|
|
param($node)
|
|
$node -is [Management.Automation.Language.FunctionDefinitionAst] -and
|
|
$node.Name -eq 'Test-IPv4AddressesSharePrefix'
|
|
}, $true)
|
|
Invoke-Expression (($clientNetworkFunctions | ForEach-Object { $_.Extent.Text }) -join [Environment]::NewLine)
|
|
|
|
Describe 'SGU public-cloud network safety' {
|
|
It 'canonicalizes a host address to its IPv4 network' {
|
|
ConvertTo-NetworkCidr -Address ([ipaddress]'10.77.0.4') `
|
|
-NetworkPrefixLength 24 | Should Be '10.77.0.0/24'
|
|
}
|
|
|
|
It 'canonicalizes the trusted P2S pool' {
|
|
ConvertTo-PrivateNetworkCidr -Cidr '172.30.4.19/16' |
|
|
Should Be '172.30.0.0/16'
|
|
}
|
|
|
|
It 'rejects a public trusted-client CIDR' {
|
|
$wasRejected = $false
|
|
try {
|
|
ConvertTo-PrivateNetworkCidr -Cidr '8.8.8.0/24' | Out-Null
|
|
}
|
|
catch {
|
|
$wasRejected = $true
|
|
}
|
|
$wasRejected | Should Be $true
|
|
}
|
|
|
|
It 'exposes explicit Azure modes on both bootstraps' {
|
|
((Get-Command $serverBootstrapPath).Parameters.Keys -contains
|
|
'NetworkConfigurationMode') | Should Be $true
|
|
((Get-Command $serverBootstrapPath).Parameters.Keys -contains
|
|
'TrustedClientNetworks') | Should Be $true
|
|
((Get-Command $clientBootstrapPath).Parameters.Keys -contains
|
|
'ConnectivityMode') | Should Be $true
|
|
((Get-Command $clientBootstrapPath).Parameters.Keys -contains
|
|
'VpnProfilePackagePath') | Should Be $true
|
|
((Get-Command $clientBootstrapPath).Parameters.Keys -contains
|
|
'CompatibilityProfile') | Should Be $true
|
|
}
|
|
|
|
It 'accepts an explicit static IPv4 address for a private Windows adapter' {
|
|
((Get-Command $clientBootstrapPath).Parameters.Keys -contains
|
|
'ClientIPv4Address') | Should Be $true
|
|
((Get-Command $clientBootstrapPath).Parameters.Keys -contains
|
|
'ClientPrefixLength') | Should Be $true
|
|
}
|
|
|
|
It 'matches a client and domain controller within the requested prefix' {
|
|
Test-IPv4AddressesSharePrefix -FirstAddress ([ipaddress]'192.168.50.11') `
|
|
-SecondAddress ([ipaddress]'192.168.50.10') -PrefixLength 24 |
|
|
Should Be $true
|
|
Test-IPv4AddressesSharePrefix -FirstAddress ([ipaddress]'192.168.51.11') `
|
|
-SecondAddress ([ipaddress]'192.168.50.10') -PrefixLength 24 |
|
|
Should Be $false
|
|
Test-IPv4AddressesSharePrefix -FirstAddress ([ipaddress]'10.77.15.20') `
|
|
-SecondAddress ([ipaddress]'10.77.0.4') -PrefixLength 16 |
|
|
Should Be $true
|
|
}
|
|
|
|
It 'prefers the private adapter instead of the Internet default route' {
|
|
$source = Get-Content -LiteralPath $clientBootstrapPath -Raw
|
|
$source | Should Match '\$withoutDefaultGateway\.Count -eq 1'
|
|
$source | Should Not Match "Get-NetRoute -AddressFamily IPv4 -DestinationPrefix '0\.0\.0\.0/0'"
|
|
}
|
|
|
|
It 'waits for the new address and WinRM route to stabilize' {
|
|
$source = Get-Content -LiteralPath $clientBootstrapPath -Raw
|
|
$source | Should Match "AddressState -eq 'Preferred'"
|
|
$source | Should Match 'function Wait-TcpPort'
|
|
$source | Should Match 'Wait-TcpPort -Address \$DomainControllerIPv4Address -Port 5985'
|
|
}
|
|
|
|
It 'keeps legacy and modern Windows package profiles isolated by build' {
|
|
$source = Get-Content -LiteralPath $clientBootstrapPath -Raw
|
|
$source.Contains("if (`$CompatibilityProfile -eq 'Windows10Legacy' -and `$windowsBuild -ge 22000)") |
|
|
Should Be $true
|
|
$source.Contains("if (`$CompatibilityProfile -eq 'Windows11Modern' -and `$windowsBuild -lt 22000)") |
|
|
Should Be $true
|
|
$source.Contains("if (`$CompatibilityProfile -eq 'Windows10Legacy' -and `$ConnectivityMode -eq 'AzureP2S')") |
|
|
Should Be $true
|
|
}
|
|
|
|
It 'uses an all-user machine-certificate VPN profile' {
|
|
$source = Get-Content -LiteralPath $azureClientPath -Raw
|
|
$source | Should Match '-AuthenticationMethod MachineCertificate'
|
|
$source | Should Match '-AllUserConnection'
|
|
$source | Should Match 'Add-DnsClientNrptRule'
|
|
}
|
|
|
|
It 'limits optional public administration to RDP' {
|
|
$template = Get-Content -LiteralPath $bicepPath -Raw
|
|
$template | Should Match "name: 'Allow-RDP-from-administrator'"
|
|
$template | Should Match "destinationPortRange: '3389'"
|
|
$template | Should Not Match "sourceAddressPrefix: '0\.0\.0\.0/0'"
|
|
}
|
|
}
|