Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/Network/Network.Test/ScenarioTests/AzureFirewallTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,21 @@ public void TestAzureFirewallAutoscaleConfiguration()
{
TestRunner.RunTestScript("Test-AzureFirewallAutoscaleConfiguration");
}

[Fact]
[Trait(Category.AcceptanceType, Category.CheckIn)]
[Trait(Category.Owner, NrpTeamAlias.azurefirewall)]
public void TestAzureFirewallCRUDWithEdgeZone()
{
TestRunner.RunTestScript("Test-AzureFirewallCRUDWithEdgeZone");
}

[Fact]
[Trait(Category.AcceptanceType, Category.CheckIn)]
[Trait(Category.Owner, NrpTeamAlias.azurefirewall)]
public void TestAzureFirewallEdgeZoneZonesValidation()
{
TestRunner.RunTestScript("Test-AzureFirewallEdgeZoneZonesValidation");
}
}
}
180 changes: 180 additions & 0 deletions src/Network/Network.Test/ScenarioTests/AzureFirewallTests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2495,4 +2495,184 @@ function Test-AzureFirewallAutoscaleConfiguration {
# Cleanup
Clean-ResourceGroup $rgname
}
}

<#
.SYNOPSIS
Tests AzureFirewall CRUD with EdgeZone.
#>
function Test-AzureFirewallCRUDWithEdgeZone {
# Setup
$rgname = Get-ResourceGroupName
$azureFirewallName = Get-ResourceName
$resourceTypeParent = "Microsoft.Network/AzureFirewalls"
$location = Get-ProviderLocation $resourceTypeParent "eastus2euap"

$vnetName = Get-ResourceName
$subnetName = "AzureFirewallSubnet"
$publicIpName = Get-ResourceName
$edgeZone = "microsoftrrezm1"

try {
# Create the resource group
$resourceGroup = New-AzResourceGroup -Name $rgname -Location $location -Tags @{ testtag = "testval" }

# Create the Virtual Network with EdgeZone
$subnet = New-AzVirtualNetworkSubnetConfig -Name $subnetName -AddressPrefix 10.0.0.0/24
$vnet = New-AzVirtualNetwork -Name $vnetName -ResourceGroupName $rgname -Location $location -AddressPrefix 10.0.0.0/16 -Subnet $subnet -EdgeZone $edgeZone

# Create public ip with EdgeZone
$publicip = New-AzPublicIpAddress -ResourceGroupName $rgname -name $publicIpName -location $location -AllocationMethod Static -Sku Standard -EdgeZone $edgeZone

# Create AzureFirewall with EdgeZone (should have no zones)
$azureFirewall = New-AzFirewall -Name $azureFirewallName -ResourceGroupName $rgname -Location $location -VirtualNetwork $vnet -PublicIpAddress $publicip -EdgeZone $edgeZone

# Get AzureFirewall
$getAzureFirewall = Get-AzFirewall -name $azureFirewallName -ResourceGroupName $rgname

# Verification
Assert-AreEqual $rgName $getAzureFirewall.ResourceGroupName
Assert-AreEqual $azureFirewallName $getAzureFirewall.Name
Assert-NotNull $getAzureFirewall.Location
Assert-AreEqual (Normalize-Location $location) $getAzureFirewall.Location
Assert-NotNull $getAzureFirewall.Etag
Assert-AreEqual "Alert" $getAzureFirewall.ThreatIntelMode
Assert-AreEqual 1 @($getAzureFirewall.IpConfigurations).Count
Assert-NotNull $getAzureFirewall.IpConfigurations[0].Subnet.Id
Assert-NotNull $getAzureFirewall.IpConfigurations[0].PublicIpAddress.Id
Assert-NotNull $getAzureFirewall.IpConfigurations[0].PrivateIpAddress
Assert-AreEqual 0 @($getAzureFirewall.ApplicationRuleCollections).Count
Assert-AreEqual 0 @($getAzureFirewall.NatRuleCollections).Count
Assert-AreEqual 0 @($getAzureFirewall.NetworkRuleCollections).Count

# Verify EdgeZone specific behavior
Assert-NotNull $getAzureFirewall.ExtendedLocation
Assert-AreEqual $edgeZone $getAzureFirewall.ExtendedLocation.Name
Assert-AreEqual "EdgeZone" $getAzureFirewall.ExtendedLocation.Type
# Verify that zones are null when EdgeZone is specified
Assert-Null $getAzureFirewall.Zones

# Update the firewall to test modification
$azureFirewall.ThreatIntelMode = "Deny"
Set-AzFirewall -AzureFirewall $azureFirewall

# Verify the update
$getAzureFirewall = Get-AzFirewall -name $azureFirewallName -ResourceGroupName $rgname
Assert-AreEqual "Deny" $getAzureFirewall.ThreatIntelMode
# Verify EdgeZone properties are preserved
Assert-NotNull $getAzureFirewall.ExtendedLocation
Assert-AreEqual $edgeZone $getAzureFirewall.ExtendedLocation.Name
Assert-Null $getAzureFirewall.Zones

# Delete AzureFirewall
$delete = Remove-AzFirewall -ResourceGroupName $rgname -name $azureFirewallName -PassThru -Force
Assert-AreEqual true $delete

$list = Get-AzFirewall -ResourceGroupName $rgname
Assert-AreEqual 0 @($list).Count
}
finally {
# Cleanup
Clean-ResourceGroup $rgname
}
}

<#
.SYNOPSIS
Tests EdgeZone and Zones validation - zones should be null when EdgeZone is specified.
#>
function Test-AzureFirewallEdgeZoneZonesValidation {
# Setup
$rgname = Get-ResourceGroupName
$azureFirewallName = Get-ResourceName
$resourceTypeParent = "Microsoft.Network/AzureFirewalls"
$location = Get-ProviderLocation $resourceTypeParent "eastus2euap"

$vnetName = Get-ResourceName
$subnetName = "AzureFirewallSubnet"
$publicIpName = Get-ResourceName
$edgeZone = "microsoftrrezm1"

try {
# Create the resource group
$resourceGroup = New-AzResourceGroup -Name $rgname -Location $location

# Create the Virtual Network with EdgeZone
$subnet = New-AzVirtualNetworkSubnetConfig -Name $subnetName -AddressPrefix 10.0.0.0/24
$vnet = New-AzVirtualNetwork -Name $vnetName -ResourceGroupName $rgname -Location $location -AddressPrefix 10.0.0.0/16 -Subnet $subnet -EdgeZone $edgeZone

# Create public ip with EdgeZone
$publicip = New-AzPublicIpAddress -ResourceGroupName $rgname -name $publicIpName -location $location -AllocationMethod Static -Sku Standard -EdgeZone $edgeZone

# Test 1: Attempt to create firewall with both EdgeZone and Zone parameters (should fail)
Assert-ThrowsLike { New-AzFirewall -Name $azureFirewallName -ResourceGroupName $rgname -Location $location -VirtualNetwork $vnet -PublicIpAddress $publicip -EdgeZone $edgeZone -Zone 1,2,3 } "*Zones cannot be specified when EdgeZone is provided*"

# Test 2: Create firewall with only EdgeZone (should succeed)
$azureFirewall = New-AzFirewall -Name $azureFirewallName -ResourceGroupName $rgname -Location $location -VirtualNetwork $vnet -PublicIpAddress $publicip -EdgeZone $edgeZone

# Get AzureFirewall
$getAzureFirewall = Get-AzFirewall -name $azureFirewallName -ResourceGroupName $rgname

# Verify EdgeZone is set and Zones is null
Assert-NotNull $getAzureFirewall.ExtendedLocation
Assert-AreEqual $edgeZone $getAzureFirewall.ExtendedLocation.Name
Assert-AreEqual "EdgeZone" $getAzureFirewall.ExtendedLocation.Type
Assert-Null $getAzureFirewall.Zones

# Delete the firewall
Remove-AzFirewall -ResourceGroupName $rgname -name $azureFirewallName -Force

# Test 3: Create firewall with only Zone parameters (no EdgeZone)
# Create new VNet and Public IP with zones for this test
$vnetName2 = Get-ResourceName
$publicIpName2 = Get-ResourceName
$subnet2 = New-AzVirtualNetworkSubnetConfig -Name $subnetName -AddressPrefix 10.1.0.0/24
$vnet2 = New-AzVirtualNetwork -Name $vnetName2 -ResourceGroupName $rgname -Location $location -AddressPrefix 10.1.0.0/16 -Subnet $subnet2
$publicip2 = New-AzPublicIpAddress -ResourceGroupName $rgname -name $publicIpName2 -location $location -AllocationMethod Static -Sku Standard -Zone 1,2,3

$azureFirewall2Name = Get-ResourceName
$azureFirewall2 = New-AzFirewall -Name $azureFirewall2Name -ResourceGroupName $rgname -Location $location -VirtualNetwork $vnet2 -PublicIpAddress $publicip2 -Zone 1,2,3

# Get AzureFirewall
$getAzureFirewall2 = Get-AzFirewall -name $azureFirewall2Name -ResourceGroupName $rgname

# Verify Zones are set and ExtendedLocation is null
Assert-AreEqual 3 @($getAzureFirewall2.Zones).Count
Assert-Null $getAzureFirewall2.ExtendedLocation

# Delete the firewall
Remove-AzFirewall -ResourceGroupName $rgname -name $azureFirewall2Name -Force

# Test 4: Create firewall with only EdgeZone (no Zone parameters)
$azureFirewall3Name = Get-ResourceName
$azureFirewall3 = New-AzFirewall -Name $azureFirewall3Name -ResourceGroupName $rgname -Location $location -VirtualNetwork $vnet -PublicIpAddress $publicip -EdgeZone $edgeZone

# Get AzureFirewall
$getAzureFirewall3 = Get-AzFirewall -name $azureFirewall3Name -ResourceGroupName $rgname

# Verify EdgeZone is set and Zones is null
Assert-NotNull $getAzureFirewall3.ExtendedLocation
Assert-AreEqual $edgeZone $getAzureFirewall3.ExtendedLocation.Name
Assert-Null $getAzureFirewall3.Zones

# Delete the firewall
Remove-AzFirewall -ResourceGroupName $rgname -name $azureFirewall3Name -Force

# Test 5: Test Set-AzFirewall with EdgeZone and Zones validation
# Create a firewall with EdgeZone
$azureFirewall4Name = Get-ResourceName
$azureFirewall4 = New-AzFirewall -Name $azureFirewall4Name -ResourceGroupName $rgname -Location $location -VirtualNetwork $vnet -PublicIpAddress $publicip -EdgeZone $edgeZone

# Try to add zones using Set-AzFirewall (should fail)
$getAzureFirewall4 = Get-AzFirewall -name $azureFirewall4Name -ResourceGroupName $rgname
$getAzureFirewall4.Zones = @("1", "2", "3")
Assert-ThrowsLike { Set-AzFirewall -AzureFirewall $getAzureFirewall4 } "*Zones cannot be specified when EdgeZone is provided*"

# Clean up
Remove-AzFirewall -ResourceGroupName $rgname -name $azureFirewall4Name -Force
}
finally {
# Cleanup
Clean-ResourceGroup $rgname
}
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

61 changes: 57 additions & 4 deletions src/Network/Network/AzureFirewall/NewAzureFirewallCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ public class NewAzureFirewallCommand : AzureFirewallBaseCmdlet
HelpMessage = "A list of availability zones denoting where the firewall needs to come from.")]
public string[] Zone { get; set; }

[Parameter(
Mandatory = false,
HelpMessage = "The edge zone where the firewall needs to be deployed.")]
public string EdgeZone { get; set; }

[Alias("Sku")]
[Parameter(
Mandatory = false,
Expand Down Expand Up @@ -286,6 +291,52 @@ private PSAzureFirewall CreateAzureFirewall()
sku.Name = !string.IsNullOrEmpty(this.SkuName) ? this.SkuName : MNM.AzureFirewallSkuName.AzfwVnet;
sku.Tier = !string.IsNullOrEmpty(this.SkuTier) ? this.SkuTier : MNM.AzureFirewallSkuTier.Standard;

// Validate that EdgeZone and Zones are not both specified
if (!string.IsNullOrEmpty(this.EdgeZone) && this.Zone != null && this.Zone.Length > 0)
{
throw new ArgumentException("Zones cannot be specified when EdgeZone is provided. EdgeZone deployments do not support availability zones.", nameof(this.Zone));
}

// Validate that VirtualNetwork and PublicIpAddress are in the same EdgeZone when EdgeZone is specified
if (!string.IsNullOrEmpty(this.EdgeZone))
{
// Check VirtualNetwork has matching ExtendedLocation
if (this.virtualNetwork != null)
{
if (this.virtualNetwork.ExtendedLocation == null ||
string.IsNullOrEmpty(this.virtualNetwork.ExtendedLocation.Name) ||
!this.virtualNetwork.ExtendedLocation.Name.Equals(this.EdgeZone, StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException($"Virtual Network must be deployed in the same edge zone '{this.EdgeZone}' as the firewall. The Virtual Network's extended location does not match.", nameof(VirtualNetwork));
}
}

// Check PublicIpAddress(es) have matching ExtendedLocation
if (this.publicIpAddresses != null && this.publicIpAddresses.Length > 0)
{
foreach (var pip in this.publicIpAddresses)
{
if (pip.ExtendedLocation == null ||
string.IsNullOrEmpty(pip.ExtendedLocation.Name) ||
!pip.ExtendedLocation.Name.Equals(this.EdgeZone, StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException($"Public IP Address '{pip.Name}' must be deployed in the same edge zone '{this.EdgeZone}' as the firewall. The Public IP's extended location does not match.", nameof(PublicIpAddress));
}
}
}

// Check ManagementPublicIpAddress has matching ExtendedLocation
if (this.ManagementPublicIpAddress != null)
{
if (this.ManagementPublicIpAddress.ExtendedLocation == null ||
string.IsNullOrEmpty(this.ManagementPublicIpAddress.ExtendedLocation.Name) ||
!this.ManagementPublicIpAddress.ExtendedLocation.Name.Equals(this.EdgeZone, StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException($"Management Public IP Address must be deployed in the same edge zone '{this.EdgeZone}' as the firewall. The Management Public IP's extended location does not match.", nameof(ManagementPublicIpAddress));
}
}
}

if (sku.Tier.Equals(MNM.AzureFirewallSkuTier.Basic) && !string.IsNullOrEmpty(this.Location))
{
if (FirewallConstants.IsRegionRestrictedForBasicFirewall(this.Location))
Expand Down Expand Up @@ -336,10 +387,11 @@ private PSAzureFirewall CreateAzureFirewall()
VirtualHub = VirtualHubId != null ? new MNM.SubResource(VirtualHubId) : null,
FirewallPolicy = FirewallPolicyId != null ? new MNM.SubResource(FirewallPolicyId) : null,
HubIPAddresses = this.HubIPAddress,
Zones = this.Zone == null ? null : this.Zone.ToList(),
Zones = (!string.IsNullOrEmpty(this.EdgeZone)) ? null : (this.Zone == null ? null : this.Zone.ToList()),
EnableFatFlowLogging = (this.EnableFatFlowLogging.IsPresent ? "True" : null),
EnableDnstapLogging = (this.EnableDnstapLogging.IsPresent ? "True" : null),
EnableUDPLogOptimization = (this.EnableUDPLogOptimization.IsPresent ? "True" : null)
EnableUDPLogOptimization = (this.EnableUDPLogOptimization.IsPresent ? "True" : null),
ExtendedLocation = (!string.IsNullOrEmpty(this.EdgeZone)) ? new PSExtendedLocation(this.EdgeZone) : null
};

if (this.PublicIpAddress != null)
Expand Down Expand Up @@ -368,12 +420,13 @@ private PSAzureFirewall CreateAzureFirewall()
EnableFatFlowLogging = (this.EnableFatFlowLogging.IsPresent ? "True" : null),
EnableDnstapLogging = (this.EnableDnstapLogging.IsPresent ? "True" : null),
EnableUDPLogOptimization = (this.EnableUDPLogOptimization.IsPresent ? "True" : null),
RouteServerId = this.RouteServerId
RouteServerId = this.RouteServerId,
ExtendedLocation = (!string.IsNullOrEmpty(this.EdgeZone)) ? new PSExtendedLocation(this.EdgeZone) : null
};

if (this.Zone != null)
{
firewall.Zones = this.Zone?.ToList();
firewall.Zones = (!string.IsNullOrEmpty(this.EdgeZone)) ? null : this.Zone?.ToList();
}

if (this.virtualNetwork != null)
Expand Down
Loading
Loading