Skip to content
Merged
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
9 changes: 8 additions & 1 deletion src/Network/Network.Test/ScenarioTests/AzureFirewallTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ public void TestAzureFirewallCRUDwithManagementIpConfig()
{
TestRunner.RunTestScript("Test-AzureFirewallCRUDwithManagementIpConfig");
}


[Fact]
[Trait(Category.AcceptanceType, Category.CheckIn)]
[Trait(Category.Owner, NrpTeamAlias.azurefirewall)]
public void TestAzureFirewallWithDNSProxy()
{
TestRunner.RunTestScript("Test-AzureFirewallWithDNSProxy");
}
}
}
112 changes: 111 additions & 1 deletion src/Network/Network.Test/ScenarioTests/AzureFirewallTests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function Test-AzureFirewallCRUD {
$publicip = New-AzPublicIpAddress -ResourceGroupName $rgname -name $publicIpName -location $location -AllocationMethod Static -Sku Standard

# Create AzureFirewall (with no rules, ThreatIntel is in Alert mode by default)
$azureFirewall = New-AzFirewall Name $azureFirewallName -ResourceGroupName $rgname -Location $location -VirtualNetworkName $vnetName -PublicIpName $publicIpName
$azureFirewall = New-AzFirewall -Name $azureFirewallName -ResourceGroupName $rgname -Location $location -VirtualNetworkName $vnetName -PublicIpName $publicIpName -DnsProxyNotRequiredForNetworkRule

# Get AzureFirewall
$getAzureFirewall = Get-AzFirewall -name $azureFirewallName -ResourceGroupName $rgname
Expand Down Expand Up @@ -1360,3 +1360,113 @@ function Test-AzureFirewallPrivateRangeCRUD {
Clean-ResourceGroup $rgname
}
}

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

$vnetName = Get-ResourceName
$subnetName = "AzureFirewallSubnet"
$publicIpName = Get-ResourceName
$dnsServers = @("10.10.10.1", "20.20.20.2")

# AzureFirewallNetworkRuleCollection
$networkRcName = "networkRc"
$networkRcPriority = 200
$networkRcActionType = "Deny"

# AzureFirewallNetworkRule 1
$networkRule1Name = "networkRule"
$networkRule1Desc = "desc1"
$networkRule1SourceAddress1 = "10.0.0.0"
$networkRule1SourceAddress2 = "111.1.0.0/24"
$networkRule1DestinationAddress1 = "*"
$networkRule1Protocol1 = "UDP"
$networkRule1Protocol2 = "TCP"
$networkRule1Protocol3 = "ICMP"
$networkRule1DestinationPort1 = "90"

# AzureFirewallNetworkRule 2
$networkRule2Name = "networkRule2"
$networkRule2Desc = "desc2"
$networkRule2SourceAddress1 = "10.0.0.0"
$networkRule2SourceAddress2 = "111.1.0.0/24"
$networkRule2DestinationFqdn1 = "www.bing.com"
$networkRule2Protocol1 = "UDP"
$networkRule2Protocol2 = "TCP"
$networkRule2Protocol3 = "ICMP"
$networkRule2DestinationPort1 = "80"

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

# Create the Virtual Network
$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
# Get full subnet details
$subnet = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $vnet -Name $subnetName

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

# Create Network Rule
$networkRule = New-AzFirewallNetworkRule -Name $networkRule1Name -Description $networkRule1Desc -Protocol $networkRule1Protocol1, $networkRule1Protocol2 -SourceAddress $networkRule1SourceAddress1, $networkRule1SourceAddress2 -DestinationAddress $networkRule1DestinationAddress1 -DestinationPort $networkRule1DestinationPort1
$networkRule.AddProtocol($networkRule1Protocol3)

# Test handling of incorrect values
Assert-ThrowsContains { $networkRule.AddProtocol() } "Cannot find an overload"
Assert-ThrowsContains { $networkRule.AddProtocol($null) } "A protocol must be provided"
Assert-ThrowsContains { $networkRule.AddProtocol("ABCD") } "Invalid protocol"

# Create Network Rule Collection
$netRc = New-AzFirewallNetworkRuleCollection -Name $networkRcName -Priority $networkRcPriority -Rule $networkRule -ActionType $networkRcActionType

# Create Second Network Rule
$networkRule2 = New-AzFirewallNetworkRule -Name $networkRule2Name -Description $networkRule2Desc -Protocol $networkRule2Protocol1, $networkRule2Protocol2 -SourceAddress $networkRule2SourceAddress1, $networkRule2SourceAddress2 -DestinationFqdn $networkRule2DestinationFqdn1 -DestinationPort $networkRule2DestinationPort1
$networkRule2.AddProtocol($networkRule2Protocol3)

# Add this second Network Rule to the rule collection
$netRc.AddRule($networkRule2)

# Create AzureFirewall with DNSProxy enabled and DNS Servers provided
$azureFirewall = New-AzFirewall -Name $azureFirewallName -ResourceGroupName $rgname -Location $location -VirtualNetworkName $vnetName -PublicIpName $publicIpName -NetworkRuleCollection $netRc -EnableDnsProxy -DnsServer $dnsServers

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

# Verification
Assert-AreEqual $rgName $getAzureFirewall.ResourceGroupName
Assert-AreEqual $azureFirewallName $getAzureFirewall.Name

# Check rule collections
Assert-AreEqual 1 @($getAzureFirewall.NetworkRuleCollections).Count
Assert-AreEqual 2 @($getAzureFirewall.NetworkRuleCollections[0].Rules).Count

# Check DNS Proxy
Assert-AreEqual true $getAzureFirewall.DNSEnableProxy
Assert-AreEqualArray $dnsServers $getAzureFirewall.DnsServer

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

# Delete VirtualNetwork
$delete = Remove-AzVirtualNetwork -ResourceGroupName $rgname -name $vnetName -PassThru -Force
Assert-AreEqual true $delete

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

Large diffs are not rendered by default.

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions src/Network/Network/AzureFirewall/NewAzureFirewallCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,24 @@ public class NewAzureFirewallCommand : AzureFirewallBaseCmdlet
)]
public string[] PrivateRange { get; set; }

[Parameter(
Mandatory = false,
HelpMessage = "Enable DNS Proxy. By default it is disabled."
)]
public SwitchParameter EnableDnsProxy { get; set; }

[Parameter(
Mandatory = false,
HelpMessage = "Requires DNS Proxy functionality for FQDNs within Network Rules. By default is is enabled."
)]
public SwitchParameter DnsProxyNotRequiredForNetworkRule { get; set; }

[Parameter(
Mandatory = false,
HelpMessage = "The list of DNS Servers"
)]
public string[] DnsServer { get; set; }

[Parameter(
Mandatory = false,
ValueFromPipelineByPropertyName = true,
Expand Down Expand Up @@ -278,6 +296,9 @@ private PSAzureFirewall CreateAzureFirewall()
ThreatIntelMode = this.ThreatIntelMode ?? MNM.AzureFirewallThreatIntelMode.Alert,
ThreatIntelWhitelist = this.ThreatIntelWhitelist,
PrivateRange = this.PrivateRange,
DNSEnableProxy = (this.EnableDnsProxy.IsPresent? "true" : "false"),
DNSRequireProxyForNetworkRules = (this.DnsProxyNotRequiredForNetworkRule.IsPresent ? "false" : "true"),
DNSServer = this.DnsServer,
Sku = sku
};

Expand All @@ -290,6 +311,8 @@ private PSAzureFirewall CreateAzureFirewall()
{
firewall.Allocate(this.virtualNetwork, this.publicIpAddresses, this.ManagementPublicIpAddress);
}

firewall.ValidateDNSProxyRequirements();
}

// Map to the sdk object
Expand Down
4 changes: 4 additions & 0 deletions src/Network/Network/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
- `New-AzPrivateDnsZoneGroup`
- `Set-AzPrivateDnsZoneGroup`
- `Remove-AzPrivateDnsZoneGroup`
* Add `DNSEnableProxy`, 'DNSRequireProxyForNetworkRules' and 'DNSServers' parameters to `AzureFirewall`
* Add `EnableDnsProxy`, 'DnsProxyNotRequiredForNetworkRule' and 'DnsServer' parameters to `AzureFirewall`
- Updated cmdlet:
- New-AzFirewall

## Version 2.5.0
* Updated cmdlets to enable connection on private IP for Virtual Network Gateway.
Expand Down
17 changes: 15 additions & 2 deletions src/Network/Network/Common/NetworkResourceManagerProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,10 @@ private static void Initialize()
{
{ "ThreatIntel.Whitelist.FQDNs", src.ThreatIntelWhitelist?.FQDNs?.Aggregate((result, item) => result + "," + item) },
{ "ThreatIntel.Whitelist.IpAddresses", src.ThreatIntelWhitelist?.IpAddresses?.Aggregate((result, item) => result + "," + item) },
{ "Network.SNAT.PrivateRanges", src.PrivateRange?.Aggregate((result, item) => result + "," + item) }
{ "Network.SNAT.PrivateRanges", src.PrivateRange?.Aggregate((result, item) => result + "," + item) },
{ "Network.DNS.EnableProxy", src.DNSEnableProxy },
{ "Network.DNS.RequireProxyForNetworkRules", src.DNSRequireProxyForNetworkRules },
{ "Network.DNS.Servers", src.DNSServer?.Aggregate((result, item) => result + "," + item) }
}.Where(kvp => kvp.Value != null).ToDictionary(key => key.Key, val => val.Value); // TODO: remove after backend code is refactored
});
cfg.CreateMap<CNM.PSAzureFirewallSku, MNM.AzureFirewallSku>();
Expand Down Expand Up @@ -1239,7 +1242,17 @@ private static void Initialize()
}
catch (PSArgumentException)
{
dest.ThreatIntelWhitelist.IpAddresses = null;
dest.PrivateRange = null;
}
dest.DNSEnableProxy = src.AdditionalProperties?.SingleOrDefault(kvp => kvp.Key.Equals("Network.DNS.EnableProxy", StringComparison.OrdinalIgnoreCase)).Value;
dest.DNSRequireProxyForNetworkRules = src.AdditionalProperties?.SingleOrDefault(kvp => kvp.Key.Equals("Network.DNS.RequireProxyForNetworkRules", StringComparison.OrdinalIgnoreCase)).Value;
try
{
dest.DNSServer = src.AdditionalProperties?.SingleOrDefault(kvp => kvp.Key.Equals("Network.DNS.Servers", StringComparison.OrdinalIgnoreCase)).Value?.Split(',').Select(str => str.Trim()).ToArray();
}
catch (PSArgumentException)
{
dest.DNSServer = null;
}
});
cfg.CreateMap<MNM.AzureFirewallSku, CNM.PSAzureFirewallSku>();
Expand Down
51 changes: 51 additions & 0 deletions src/Network/Network/Models/AzureFirewall/PSAzureFirewall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ public string[] PrivateRange {
}
}

public string DNSEnableProxy { get; set; }

public string DNSRequireProxyForNetworkRules { get; set; }

public string[] DNSServer { get; set; }

public string ProvisioningState { get; set; }

public List<string> Zones { get; set; }
Expand Down Expand Up @@ -112,6 +118,12 @@ public string PrivateRangeText
get { return JsonConvert.SerializeObject(PrivateRange, Formatting.Indented); }
}

[JsonIgnore]
public string DNSServersText
{
get { return JsonConvert.SerializeObject(DNSServer, Formatting.Indented); }
}

#region Ip Configuration Operations

public void Allocate(PSVirtualNetwork virtualNetwork, PSPublicIpAddress[] publicIpAddresses, PSPublicIpAddress ManagementPublicIpAddress = null)
Expand Down Expand Up @@ -396,6 +408,45 @@ private void ValidateMaskedIpAddress(string ipAddress)

#endregion

#region DNS Proxy Validation

public void ValidateDNSProxyRequirements()
{
if (string.Equals(this.DNSEnableProxy, "true", StringComparison.OrdinalIgnoreCase))
{
// Nothing to validate since they have enabled DNS Proxy
return;
}

if (string.Equals(this.DNSRequireProxyForNetworkRules, "false", StringComparison.OrdinalIgnoreCase))
{
// Nothing to validate since both DNS Proxy and Requiring Proxy for Network Rules is disabled
return;
}

// Need to check if any Network Rules have FQDNs
var netRuleCollections = this.NetworkRuleCollections?.Where(rc => rc?.Rules != null && rc.Rules.Any()).ToList();
if (netRuleCollections == null)
{
// No network rules so nothing to do
return;
}

foreach (var netRuleCollection in netRuleCollections)
{
foreach (var rule in netRuleCollection.Rules)
{
if (rule?.DestinationFqdns != null && rule.DestinationFqdns.Any())
{
throw new PSArgumentException(string.Format("Found FQDNs {0} in network rule collection {1} rule {2} without DNS proxy being enabled or requirement setting disabled",
rule.DestinationFqdns, netRuleCollection.Name, rule.Name));
}
}
}
}

#endregion

#region Private Methods

private List<BaseRuleCollection> AddRuleCollection<BaseRuleCollection>(BaseRuleCollection ruleCollection, List<BaseRuleCollection> existingRuleCollections) where BaseRuleCollection : PSAzureFirewallBaseRuleCollection
Expand Down
Loading