Skip to content

Commit d17e316

Browse files
committed
Changes to support Destination FQDNs in Network Rule and Translated FQDN
in NAT Rule for Azure Firewall
1 parent d404a70 commit d17e316

File tree

6 files changed

+191
-10
lines changed

6 files changed

+191
-10
lines changed

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

Lines changed: 100 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,18 @@ function Test-AzureFirewallCRUD {
96107
$natRule1TranslatedAddress = "10.1.2.3"
97108
$natRule1TranslatedPort = "91"
98109

110+
# AzureFirewallNatRule 2
111+
$natRule1Name = "natRule2"
112+
$natRule1Desc = "desc2"
113+
$natRule1SourceAddress1 = "10.0.0.0"
114+
$natRule1SourceAddress2 = "111.1.0.0/24"
115+
$natRule1DestinationAddress1 = "1.2.3.4"
116+
$natRule1Protocol1 = "UDP"
117+
$natRule1Protocol2 = "TCP"
118+
$natRule1DestinationPort1 = "95"
119+
$natRule1TranslatedFqdn = "server1.internal.com"
120+
$natRule1TranslatedPort = "96"
121+
99122
try {
100123
# Create the resource group
101124
$resourceGroup = New-AzResourceGroup -Name $rgname -Location $location -Tags @{ testtag = "testval" }
@@ -189,6 +212,13 @@ function Test-AzureFirewallCRUD {
189212
# Create Network Rule Collection
190213
$netRc = New-AzFirewallNetworkRuleCollection -Name $networkRcName -Priority $networkRcPriority -Rule $networkRule -ActionType $networkRcActionType
191214

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

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

243+
# Add second NAT Rule to rule Collection
244+
$natRc.AddRule($$natRule2)
245+
209246
# Add ApplicationRuleCollections to the Firewall using method AddApplicationRuleCollection
210247
$azureFirewall.AddApplicationRuleCollection($appRc)
211248
$azureFirewall.AddApplicationRuleCollection($appRc2)
@@ -245,10 +282,10 @@ function Test-AzureFirewallCRUD {
245282
Assert-AreEqual 1 @($getAzureFirewall.ApplicationRuleCollections[1].Rules).Count
246283

247284
Assert-AreEqual 1 @($getAzureFirewall.NatRuleCollections).Count
248-
Assert-AreEqual 1 @($getAzureFirewall.NatRuleCollections[0].Rules).Count
285+
Assert-AreEqual 2 @($getAzureFirewall.NatRuleCollections[0].Rules).Count
249286

250287
Assert-AreEqual 1 @($getAzureFirewall.NetworkRuleCollections).Count
251-
Assert-AreEqual 1 @($getAzureFirewall.NetworkRuleCollections[0].Rules).Count
288+
Assert-AreEqual 2 @($getAzureFirewall.NetworkRuleCollections[0].Rules).Count
252289

253290
$appRc = $getAzureFirewall.GetApplicationRuleCollectionByName($appRcName)
254291
$appRule = $appRc.GetRuleByName($appRule1Name)
@@ -329,7 +366,7 @@ function Test-AzureFirewallCRUD {
329366
Assert-AreEqual $appRule1Fqdn1 $appRule.TargetFqdns[0]
330367
Assert-AreEqual $appRule1Fqdn2 $appRule.TargetFqdns[1]
331368

332-
# Verify NAT rule collection and NAT rule
369+
# Verify NAT rule collection and NAT rules
333370
$natRc = $getAzureFirewall.GetNatRuleCollectionByName($natRcName)
334371
$natRule = $natRc.GetRuleByName($natRule1Name)
335372

@@ -356,7 +393,29 @@ function Test-AzureFirewallCRUD {
356393
Assert-AreEqual $natRule1TranslatedAddress $natRule.TranslatedAddress
357394
Assert-AreEqual $natRule1TranslatedPort $natRule.TranslatedPort
358395

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

@@ -382,6 +441,26 @@ function Test-AzureFirewallCRUD {
382441
Assert-AreEqual 1 $networkRule.DestinationPorts.Count
383442
Assert-AreEqual $networkRule1DestinationPort1 $networkRule.DestinationPorts[0]
384443

444+
$networkRule2 = $networkRc.GetRuleByName($networkRule2Name)
445+
446+
Assert-AreEqual $networkRule2Name $networkRule2.Name
447+
Assert-AreEqual $networkRule2Desc $networkRule2.Description
448+
449+
Assert-AreEqual 2 $networkRule2.SourceAddresses.Count
450+
Assert-AreEqual $networkRule2SourceAddress1 $networkRule2.SourceAddresses[0]
451+
Assert-AreEqual $networkRule2SourceAddress2 $networkRule2.SourceAddresses[1]
452+
453+
Assert-AreEqual 1 $networkRule2.DestinationAddresses.Count
454+
Assert-AreEqual $networkRule2DestinationAddress1 $networkRule2.DestinationAddresses[0]
455+
456+
Assert-AreEqual 3 $networkRule2.Protocols.Count
457+
Assert-AreEqual $networkRule2Protocol1 $networkRule2.Protocols[0]
458+
Assert-AreEqual $networkRule2Protocol2 $networkRule2.Protocols[1]
459+
Assert-AreEqual $networkRule2Protocol3 $networkRule2.Protocols[2]
460+
461+
Assert-AreEqual 1 $networkRule2.DestinationPorts.Count
462+
Assert-AreEqual $networkRule2DestinationPort1 $networkRule2.DestinationPorts[0]
463+
385464
# Delete AzureFirewall
386465
$delete = Remove-AzFirewall -ResourceGroupName $rgname -name $azureFirewallName -PassThru -Force
387466
Assert-AreEqual true $delete
@@ -449,6 +528,11 @@ function Test-AzureFirewallCRUDWithZones {
449528
$networkRcPriority = 200
450529
$networkRcActionType = "Deny"
451530

531+
# AzureFirewallNetworkRuleCollection2
532+
$networkRcName2 = "networkRc2"
533+
$networkRcPriority2 = 300
534+
$networkRcActionType = "Deny"
535+
452536
# AzureFirewallNetworkRule 1
453537
$networkRule1Name = "networkRule"
454538
$networkRule1Desc = "desc1"
@@ -476,6 +560,18 @@ function Test-AzureFirewallCRUDWithZones {
476560
$natRule1TranslatedAddress = "10.1.2.3"
477561
$natRule1TranslatedPort = "91"
478562

563+
# AzureFirewallNatRule 2
564+
$natRule2Name = "natRule2"
565+
$natRule2Desc = "desc2"
566+
$natRule2SourceAddress1 = "10.0.0.0"
567+
$natRule2SourceAddress2 = "111.1.0.0/24"
568+
$natRule2DestinationAddress1 = "1.2.3.4"
569+
$natRule2Protocol1 = "UDP"
570+
$natRule2Protocol2 = "TCP"
571+
$natRule2DestinationPort1 = "9001"
572+
$natRule2TranslatedFqdn = "httpserver.internal.com"
573+
$natRule2TranslatedPort = "9001"
574+
479575
try {
480576
# Create the resource group
481577
$resourceGroup = New-AzResourceGroup -Name $rgname -Location $location -Tags @{ testtag = "testval" }

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 FQDNs of the rule")]
55+
[ValidateNotNullOrEmpty]
56+
public string[] DestinationFqdns { 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 (DestinationFqdns != null)
80+
{
81+
foreach (string fqdn in DestinationFqdns)
82+
{
83+
ValidateIsFqdn(fqdn);
84+
}
85+
}
86+
87+
// Only one of DestinationAddress or DestinationFqdns is allowed
88+
if ((DestinationAddress != null) && (DestinationFqdns != 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) && (DestinationFqdns == 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.DestinationFqdns?.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
@@ -43,6 +43,7 @@
4343
- Update-AzureRmVpnConnection : added parameter EnableInternetSecurity
4444
- New-AzureRmExpressRouteConnection : added parameter EnableInternetSecurity
4545
- Set-AzureRmExpressRouteConnection : added parameter EnableInternetSecurity
46+
* Support for Destination FQDNs in Network Rules and Translated FQDN in NAT Rules for Azure Firewall
4647

4748
## Version 1.15.0
4849
* 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)