Skip to content

Commit e7721a7

Browse files
authored
Merge pull request #10388 from tejasshah7/tesha/FqdnFilteringFqSupport
Support for FQDNs in Network and NAT Rules for Azure Firewall
2 parents efd1c29 + f3fee01 commit e7721a7

File tree

7 files changed

+2300
-2005
lines changed

7 files changed

+2300
-2005
lines changed

src/Network/Network.Test/ScenarioTests/AzureFirewallTests.ps1

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ function Test-AzureFirewallCRUD {
8080
$networkRule1Protocol3 = "ICMP"
8181
$networkRule1DestinationPort1 = "90"
8282

83+
# AzureFirewallNetworkRule 2
84+
$networkRule2Name = "networkRule2"
85+
$networkRule2Desc = "desc2"
86+
$networkRule2SourceAddress1 = "10.0.0.0"
87+
$networkRule2SourceAddress2 = "111.1.0.0/24"
88+
$networkRule2DestinationFqdn1 = "www.bing.com"
89+
$networkRule2Protocol1 = "UDP"
90+
$networkRule2Protocol2 = "TCP"
91+
$networkRule2Protocol3 = "ICMP"
92+
$networkRule2DestinationPort1 = "80"
93+
8394
# AzureFirewallNatRuleCollection
8495
$natRcName = "natRc"
8596
$natRcPriority = 200
@@ -96,6 +107,17 @@ function Test-AzureFirewallCRUD {
96107
$natRule1TranslatedAddress = "10.1.2.3"
97108
$natRule1TranslatedPort = "91"
98109

110+
# AzureFirewallNatRule 2
111+
$natRule2Name = "natRule2"
112+
$natRule2Desc = "desc2"
113+
$natRule2SourceAddress1 = "10.0.0.0"
114+
$natRule2SourceAddress2 = "111.1.0.0/24"
115+
$natRule2Protocol1 = "UDP"
116+
$natRule2Protocol2 = "TCP"
117+
$natRule2DestinationPort1 = "95"
118+
$natRule2TranslatedFqdn = "server1.internal.com"
119+
$natRule2TranslatedPort = "96"
120+
99121
try {
100122
# Create the resource group
101123
$resourceGroup = New-AzResourceGroup -Name $rgname -Location $location -Tags @{ testtag = "testval" }
@@ -189,6 +211,13 @@ function Test-AzureFirewallCRUD {
189211
# Create Network Rule Collection
190212
$netRc = New-AzFirewallNetworkRuleCollection -Name $networkRcName -Priority $networkRcPriority -Rule $networkRule -ActionType $networkRcActionType
191213

214+
# Create Second Network Rule
215+
$networkRule2 = New-AzFirewallNetworkRule -Name $networkRule2Name -Description $networkRule2Desc -Protocol $networkRule2Protocol1, $networkRule2Protocol2 -SourceAddress $networkRule2SourceAddress1, $networkRule2SourceAddress2 -DestinationFqdn $networkRule2DestinationFqdn1 -DestinationPort $networkRule2DestinationPort1
216+
$networkRule2.AddProtocol($networkRule2Protocol3)
217+
218+
# Add this second Network Rule to the rule collection
219+
$netRc.AddRule($networkRule2)
220+
192221
# Create a NAT rule
193222
$natRule = New-AzFirewallNatRule -Name $natRule1Name -Description $natRule1Desc -Protocol $natRule1Protocol1 -SourceAddress $natRule1SourceAddress1, $natRule1SourceAddress2 -DestinationAddress $publicip.IpAddress -DestinationPort $natRule1DestinationPort1 -TranslatedAddress $natRule1TranslatedAddress -TranslatedPort $natRule1TranslatedPort
194223
$natRule.AddProtocol($natRule1Protocol2)
@@ -203,9 +232,16 @@ function Test-AzureFirewallCRUD {
203232
} "The argument `"ICMP`" does not belong to the set"
204233
Assert-ThrowsContains { $natRule.AddProtocol("ICMP") } "Invalid protocol"
205234

235+
# Create second NAT rule
236+
$natRule2 = New-AzFirewallNatRule -Name $natRule2Name -Description $natRule2Desc -Protocol $natRule2Protocol1 -SourceAddress $natRule2SourceAddress1, $natRule2SourceAddress2 -DestinationAddress $publicip.IpAddress -DestinationPort $natRule2DestinationPort1 -TranslatedFqdn $natRule2TranslatedFqdn -TranslatedPort $natRule2TranslatedPort
237+
$natRule2.AddProtocol($natRule2Protocol2)
238+
206239
# Create a NAT Rule Collection
207240
$natRc = New-AzFirewallNatRuleCollection -Name $natRcName -Priority $natRcPriority -Rule $natRule
208241

242+
# Add second NAT Rule to rule Collection
243+
$natRc.AddRule($natRule2)
244+
209245
# Add ApplicationRuleCollections to the Firewall using method AddApplicationRuleCollection
210246
$azureFirewall.AddApplicationRuleCollection($appRc)
211247
$azureFirewall.AddApplicationRuleCollection($appRc2)
@@ -245,10 +281,10 @@ function Test-AzureFirewallCRUD {
245281
Assert-AreEqual 1 @($getAzureFirewall.ApplicationRuleCollections[1].Rules).Count
246282

247283
Assert-AreEqual 1 @($getAzureFirewall.NatRuleCollections).Count
248-
Assert-AreEqual 1 @($getAzureFirewall.NatRuleCollections[0].Rules).Count
284+
Assert-AreEqual 2 @($getAzureFirewall.NatRuleCollections[0].Rules).Count
249285

250286
Assert-AreEqual 1 @($getAzureFirewall.NetworkRuleCollections).Count
251-
Assert-AreEqual 1 @($getAzureFirewall.NetworkRuleCollections[0].Rules).Count
287+
Assert-AreEqual 2 @($getAzureFirewall.NetworkRuleCollections[0].Rules).Count
252288

253289
$appRc = $getAzureFirewall.GetApplicationRuleCollectionByName($appRcName)
254290
$appRule = $appRc.GetRuleByName($appRule1Name)
@@ -329,7 +365,7 @@ function Test-AzureFirewallCRUD {
329365
Assert-AreEqual $appRule1Fqdn1 $appRule.TargetFqdns[0]
330366
Assert-AreEqual $appRule1Fqdn2 $appRule.TargetFqdns[1]
331367

332-
# Verify NAT rule collection and NAT rule
368+
# Verify NAT rule collection and NAT rules
333369
$natRc = $getAzureFirewall.GetNatRuleCollectionByName($natRcName)
334370
$natRule = $natRc.GetRuleByName($natRule1Name)
335371

@@ -356,7 +392,29 @@ function Test-AzureFirewallCRUD {
356392
Assert-AreEqual $natRule1TranslatedAddress $natRule.TranslatedAddress
357393
Assert-AreEqual $natRule1TranslatedPort $natRule.TranslatedPort
358394

359-
# Verify network rule collection and network rule
395+
$natRule2 = $natRc.GetRuleByName($natRule2Name)
396+
397+
Assert-AreEqual $natRule2Name $natRule2.Name
398+
Assert-AreEqual $natRule2Desc $natRule2.Description
399+
400+
Assert-AreEqual 2 $natRule2.SourceAddresses.Count
401+
Assert-AreEqual $natRule2SourceAddress1 $natRule2.SourceAddresses[0]
402+
Assert-AreEqual $natRule2SourceAddress2 $natRule2.SourceAddresses[1]
403+
404+
Assert-AreEqual 1 $natRule2.DestinationAddresses.Count
405+
Assert-AreEqual $publicip.IpAddress $natRule2.DestinationAddresses[0]
406+
407+
Assert-AreEqual 2 $natRule2.Protocols.Count
408+
Assert-AreEqual $natRule2Protocol1 $natRule2.Protocols[0]
409+
Assert-AreEqual $natRule2Protocol2 $natRule2.Protocols[1]
410+
411+
Assert-AreEqual 1 $natRule2.DestinationPorts.Count
412+
Assert-AreEqual $natRule2DestinationPort1 $natRule2.DestinationPorts[0]
413+
414+
Assert-AreEqual $natRule2TranslatedFqdn $natRule2.TranslatedFqdn
415+
Assert-AreEqual $natRule2TranslatedPort $natRule2.TranslatedPort
416+
417+
# Verify network rule collection and network rules
360418
$networkRc = $getAzureFirewall.GetNetworkRuleCollectionByName($networkRcName)
361419
$networkRule = $networkRc.GetRuleByName($networkRule1Name)
362420

@@ -382,6 +440,26 @@ function Test-AzureFirewallCRUD {
382440
Assert-AreEqual 1 $networkRule.DestinationPorts.Count
383441
Assert-AreEqual $networkRule1DestinationPort1 $networkRule.DestinationPorts[0]
384442

443+
$networkRule2 = $networkRc.GetRuleByName($networkRule2Name)
444+
445+
Assert-AreEqual $networkRule2Name $networkRule2.Name
446+
Assert-AreEqual $networkRule2Desc $networkRule2.Description
447+
448+
Assert-AreEqual 2 $networkRule2.SourceAddresses.Count
449+
Assert-AreEqual $networkRule2SourceAddress1 $networkRule2.SourceAddresses[0]
450+
Assert-AreEqual $networkRule2SourceAddress2 $networkRule2.SourceAddresses[1]
451+
452+
Assert-AreEqual 1 $networkRule2.DestinationFqdns.Count
453+
Assert-AreEqual $networkRule2DestinationFqdn1 $networkRule2.DestinationFqdns[0]
454+
455+
Assert-AreEqual 3 $networkRule2.Protocols.Count
456+
Assert-AreEqual $networkRule2Protocol1 $networkRule2.Protocols[0]
457+
Assert-AreEqual $networkRule2Protocol2 $networkRule2.Protocols[1]
458+
Assert-AreEqual $networkRule2Protocol3 $networkRule2.Protocols[2]
459+
460+
Assert-AreEqual 1 $networkRule2.DestinationPorts.Count
461+
Assert-AreEqual $networkRule2DestinationPort1 $networkRule2.DestinationPorts[0]
462+
385463
# Delete AzureFirewall
386464
$delete = Remove-AzFirewall -ResourceGroupName $rgname -name $azureFirewallName -PassThru -Force
387465
Assert-AreEqual true $delete

src/Network/Network.Test/SessionRecords/Commands.Network.Test.ScenarioTests.AzureFirewallTests/TestAzureFirewallCRUD.json

Lines changed: 2127 additions & 1995 deletions
Large diffs are not rendered by default.

src/Network/Network/AzureFirewall/NatRule/NewAzureFirewallNatRuleCommand.cs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,17 @@ public class NewAzureFirewallNatRuleCommand : NetworkBaseCmdlet
6666
public string[] Protocol { get; set; }
6767

6868
[Parameter(
69-
Mandatory = true,
69+
Mandatory = false,
7070
HelpMessage = "The translated address for this NAT rule")]
7171
[ValidateNotNullOrEmpty]
7272
public string TranslatedAddress { get; set; }
7373

74+
[Parameter(
75+
Mandatory = false,
76+
HelpMessage = "The translated FQDN for this NAT rule")]
77+
[ValidateNotNullOrEmpty]
78+
public string TranslatedFqdn { get; set; }
79+
7480
[Parameter(
7581
Mandatory = true,
7682
HelpMessage = "The translated port for this NAT rule")]
@@ -95,7 +101,26 @@ public override void Execute()
95101
}
96102

97103
ValidateIsSingleIpNotRange(DestinationAddress.Single());
98-
ValidateIsSingleIpNotRange(TranslatedAddress);
104+
if (TranslatedAddress != null)
105+
{
106+
ValidateIsSingleIpNotRange(TranslatedAddress);
107+
}
108+
if (TranslatedFqdn != null)
109+
{
110+
ValidateIsFqdn(TranslatedFqdn);
111+
}
112+
113+
// Only one of TranslatedAddress or TranslatedFqdn is allowed
114+
if ((TranslatedAddress != null) && (TranslatedFqdn != null))
115+
{
116+
throw new ArgumentException("Both TranslatedAddress and TranslatedFqdn not allowed");
117+
}
118+
119+
// One of TranslatedAddress or TranslatedFqdn must be present
120+
if ((TranslatedAddress == null) && (TranslatedFqdn == null))
121+
{
122+
throw new ArgumentException("Either TranslatedAddress or TranslatedFqdn is required");
123+
}
99124

100125
ValidateIsSinglePortNotRange(DestinationPort.Single());
101126
ValidateIsSinglePortNotRange(TranslatedPort);
@@ -110,6 +135,7 @@ public override void Execute()
110135
DestinationAddresses = this.DestinationAddress?.ToList(),
111136
DestinationPorts = this.DestinationPort?.ToList(),
112137
TranslatedAddress = this.TranslatedAddress,
138+
TranslatedFqdn = this.TranslatedFqdn,
113139
TranslatedPort = this.TranslatedPort
114140
};
115141
WriteObject(networkRule);
@@ -133,5 +159,15 @@ private void ValidateIsSinglePortNotRange(string portStr)
133159
throw new ArgumentException($"Invalid value {portStr}. Only a single port value is accepted (e.g. 8080).");
134160
}
135161
}
162+
163+
private void ValidateIsFqdn(string fqdn)
164+
{
165+
var fqdnRegEx = new Regex("^[a-zA-Z0-9]+(([a-zA-Z0-9_\\-]*[a-zA-Z0-9]+)*\\.)*(?:[a-zA-Z0-9]{2,})$");
166+
167+
if (!fqdnRegEx.IsMatch(fqdn))
168+
{
169+
throw new ArgumentException($"Invalid value {fqdn}.");
170+
}
171+
}
136172
}
137173
}

src/Network/Network/AzureFirewall/NetworkRule/NewAzureFirewallNetworkRuleCommand.cs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using System.Linq;
1818
using System.Management.Automation;
1919
using Microsoft.Azure.Commands.Network.Models;
20+
using System.Text.RegularExpressions;
2021
using MNM = Microsoft.Azure.Management.Network.Models;
2122

2223
namespace Microsoft.Azure.Commands.Network
@@ -43,11 +44,17 @@ public class NewAzureFirewallNetworkRuleCommand : NetworkBaseCmdlet
4344
public string[] SourceAddress { get; set; }
4445

4546
[Parameter(
46-
Mandatory = true,
47+
Mandatory = false,
4748
HelpMessage = "The destination addresses of the rule")]
4849
[ValidateNotNullOrEmpty]
4950
public string[] DestinationAddress { get; set; }
5051

52+
[Parameter(
53+
Mandatory = false,
54+
HelpMessage = "The destination FQDN of the rule")]
55+
[ValidateNotNullOrEmpty]
56+
public string[] DestinationFqdn { get; set; }
57+
5158
[Parameter(
5259
Mandatory = true,
5360
HelpMessage = "The destination ports of the rule")]
@@ -68,17 +75,48 @@ public class NewAzureFirewallNetworkRuleCommand : NetworkBaseCmdlet
6875
public override void Execute()
6976
{
7077
base.Execute();
71-
78+
79+
if (DestinationFqdn != null)
80+
{
81+
foreach (string fqdn in DestinationFqdn)
82+
{
83+
ValidateIsFqdn(fqdn);
84+
}
85+
}
86+
87+
// Only one of DestinationAddress or DestinationFqdns is allowed
88+
if ((DestinationAddress != null) && (DestinationFqdn != null))
89+
{
90+
throw new ArgumentException("Both DestinationAddress and DestinationFqdns not allowed");
91+
}
92+
93+
// One of DestinationAddress or DestinationFqdns must be present
94+
if ((DestinationAddress == null) && (DestinationFqdn == null))
95+
{
96+
throw new ArgumentException("Either DestinationAddress or DestinationFqdns is required");
97+
}
98+
7299
var networkRule = new PSAzureFirewallNetworkRule
73100
{
74101
Name = this.Name,
75102
Description = this.Description,
76103
Protocols = this.Protocol?.ToList(),
77104
SourceAddresses = this.SourceAddress?.ToList(),
78105
DestinationAddresses = this.DestinationAddress?.ToList(),
106+
DestinationFqdns = this.DestinationFqdn?.ToList(),
79107
DestinationPorts = this.DestinationPort?.ToList()
80108
};
81109
WriteObject(networkRule);
82110
}
111+
112+
private void ValidateIsFqdn(string fqdn)
113+
{
114+
var fqdnRegEx = new Regex("^\\*$|^[a-zA-Z0-9]+(([a-zA-Z0-9_\\-]*[a-zA-Z0-9]+)*\\.)*(?:[a-zA-Z0-9]{2,})$");
115+
116+
if (!fqdnRegEx.IsMatch(fqdn))
117+
{
118+
throw new ArgumentException($"Invalid value {fqdn}.");
119+
}
120+
}
83121
}
84122
}

src/Network/Network/ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
- New-AzureRmExpressRouteConnection : added parameter EnableInternetSecurity
4545
- Set-AzureRmExpressRouteConnection : added parameter EnableInternetSecurity
4646
* Fix required subnet with name AzureBastionSubnet in `PSBastion` can be case insensitive
47+
* Support for Destination FQDNs in Network Rules and Translated FQDN in NAT Rules for Azure Firewall
4748

4849
## Version 1.15.0
4950
* Add new cmdlet Get-AzAvailableServiceAlias which can be called to get the aliases that can be used for Service Endpoint Policies.

src/Network/Network/Models/AzureFirewall/PSAzureFirewallNatRule.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ public class PSAzureFirewallNatRule
3434

3535
public string TranslatedAddress { get; set; }
3636

37+
public string TranslatedFqdn { get; set; }
38+
3739
public string TranslatedPort { get; set; }
3840

3941
[JsonIgnore]

src/Network/Network/Models/AzureFirewall/PSAzureFirewallNetworkRule.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ public class PSAzureFirewallNetworkRule
2929
public List<string> SourceAddresses { get; set; }
3030

3131
public List<string> DestinationAddresses { get; set; }
32-
32+
33+
public List<string> DestinationFqdns { get; set; }
34+
3335
public List<string> DestinationPorts { get; set; }
3436

3537
[JsonIgnore]
@@ -49,7 +51,13 @@ public string DestinationAddressesText
4951
{
5052
get { return JsonConvert.SerializeObject(DestinationAddresses, Formatting.Indented); }
5153
}
52-
54+
55+
[JsonIgnore]
56+
public string DestinationFqdnsText
57+
{
58+
get { return JsonConvert.SerializeObject(DestinationFqdns, Formatting.Indented); }
59+
}
60+
5361
[JsonIgnore]
5462
public string DestinationPortsText
5563
{

0 commit comments

Comments
 (0)