Skip to content

Commit

Permalink
feat(new): Added Azure.EventHub.Firewall (Azure#2872)
Browse files Browse the repository at this point in the history
* feat(new): Added Azure.EventHub.Firewall

* doc: Update changelog

* refactor: Updated Azure.EventHub.Firewall

* Update for AnyOf function

---------

Co-authored-by: Bernie White <[email protected]>
  • Loading branch information
BenjaminEngeset and BernieWhite authored May 22, 2024
1 parent 00e1ca9 commit 9cb4be7
Show file tree
Hide file tree
Showing 5 changed files with 468 additions and 15 deletions.
4 changes: 4 additions & 0 deletions docs/CHANGELOG-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers
[#2846](https://github.com/Azure/PSRule.Rules.Azure/issues/2846)
- Check that database accounts have public network access disabled by @BenjaminEngeset.
[#2702](https://github.com/Azure/PSRule.Rules.Azure/issues/2702)
- Event Hub:
- Check that access to the namespace endpoints is restricted to only allowed sources by @BenjaminEngeset.
[#2701](https://github.com/Azure/PSRule.Rules.Azure/issues/2701)
- Updated rules:
- API Management:
- **Important change**: Updated `Azure.APIM.AvailabilityZone` to improve accuracy with non-premium SKUs by @BenjaminEngeset.
Expand All @@ -49,6 +52,7 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers
- Updated rule doc.
- Bumped rule set to `2024_06`.


## v1.37.0-B0009 (pre-release)

What's changed since v1.36.0:
Expand Down
105 changes: 105 additions & 0 deletions docs/en/rules/Azure.EventHub.Firewall.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
severity: Critical
pillar: Security
category: SE:06 Network controls
resource: Event Hub
online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.EventHub.Firewall/
---

# Access to the namespace endpoints should be restricted to only allowed sources

## SYNOPSIS

Access to the namespace endpoints should be restricted to only allowed sources.

## DESCRIPTION

By default, Event Hub namespaces are accessible from public internet.

With the firewall feature, it is possible to either fully disabling public network access by ensuring that the namespace endpoints isn't exposed on the public internet or configure rules to only accept traffic from specific addresses.

## RECOMMENDATION

Consider restricting network access to the Event Hub namespace by requiring private endpoints or by limiting access to permitted client addresses with the service firewall.

## EXAMPLES

### Configure with Azure template

To deploy Event Hub namespaces that pass this rule:

- Set the `properties.publicNetworkAccess` property to `Disabled` to require private endpoints. OR
- Alternatively, you can configure the `Microsoft.EventHub/namespaces/networkRuleSets` sub-resource by:
- Setting the `properties.publicNetworkAccess` property to `Disabled` to require private endpoints. OR
- Setting the `properties.defaultAction` property to `Deny` to restrict network access to the service by default.

For example:

```json
{
"type": "Microsoft.EventHub/namespaces",
"apiVersion": "2024-01-01",
"name": "[parameters('name')]",
"location": "[parameters('location')]",
"identity": {
"type": "SystemAssigned"
},
"sku": {
"name": "Standard"
},
"properties": {
"disableLocalAuth": true,
"minimumTlsVersion": "1.2",
"publicNetworkAccess": "Disabled",
"zoneRedundant": true
}
}
```

### Configure with Bicep

To deploy Event Hub namespaces that pass this rule:

- Set the `properties.publicNetworkAccess` property to `Disabled` to require private endpoints. OR
- Alternatively, you can configure the `Microsoft.EventHub/namespaces/networkRuleSets` sub-resource by:
- Setting the `properties.publicNetworkAccess` property to `Disabled` to require private endpoints. OR
- Setting the `properties.defaultAction` property to `Deny` to restrict network access to the service by default.

For example:

```bicep
resource ns 'Microsoft.EventHub/namespaces@2024-01-01' = {
name: name
location: location
identity: {
type: 'SystemAssigned'
}
sku: {
name: 'Standard'
}
properties: {
disableLocalAuth: true
minimumTlsVersion: '1.2'
publicNetworkAccess: 'Disabled'
zoneRedundant: true
}
}
```

## NOTES

If there are no IP and virtual network rules, all the traffic flows into the namespace even if you set the defaultAction to `deny` on the firewall. The namespace can be accessed over the public internet. Specify at least one IP rule or virtual network rule for the namespace to activate the default action on the firewall.

The firewall feature isn't supported in the `basic` tier.

## LINKS

- [SE:06 Network controls](https://learn.microsoft.com/azure/well-architected/security/networking)
- [Azure security baseline for Event Hub](https://learn.microsoft.com/security/benchmark/azure/baselines/event-hubs-security-baseline)
- [NS-1: Establish network segmentation boundaries](https://learn.microsoft.com/security/benchmark/azure/baselines/event-hubs-security-baseline#ns-1-establish-network-segmentation-boundaries)
- [NS-2: Secure cloud services with network controls](https://learn.microsoft.com/security/benchmark/azure/baselines/event-hubs-security-baseline#ns-1-establish-network-segmentation-boundaries)
- [Allow access to Azure Event Hub namespaces from specific IP addresses or ranges](https://learn.microsoft.com/azure/event-hubs/event-hubs-ip-filtering)
- [Allow access to Azure Event Hub namespaces from specific virtual networks](https://learn.microsoft.com/azure/event-hubs/event-hubs-service-endpoints)
- [Allow access to Azure Event Hub namespaces via private endpoints](https://learn.microsoft.com/azure/event-hubs/private-link-service)
- [Azure resource deployment](https://learn.microsoft.com/azure/templates/microsoft.eventhub/namespaces/eventhubs)
- [Azure resource deployment](https://learn.microsoft.com/azure/templates/microsoft.eventhub/namespaces/networkrulesets)
33 changes: 33 additions & 0 deletions src/PSRule.Rules.Azure/rules/Azure.EventHub.Rule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,37 @@ Rule 'Azure.EventHub.Usage' -Ref 'AZR-000101' -Type 'Microsoft.EventHub/namespac
$Assert.GreaterOrEqual($items, '.', 1);
}

# Synopsis: Access to the namespace endpoints should be restricted to only allowed sources.
Rule 'Azure.EventHub.Firewall' -Ref 'AZR-000422' -Type 'Microsoft.EventHub/namespaces', 'Microsoft.EventHub/namespaces/networkRuleSets' -If { Test-IsNoBasicTier } -Tag @{ release = 'GA'; ruleSet = '2024_06'; 'Azure.WAF/pillar' = 'Security'; } -Labels @{ 'Azure.MCSB.v1/control' = 'NS-1', 'NS-2' } {
# NB: Microsoft.EventHub/namespaces/networkRuleSets overrides properties.publicNetworkAccess and properties.defaultAction property.

$firewalls = @($TargetObject)
if ($PSRule.TargetType -eq 'Microsoft.EventHub/namespaces') {
$firewalls = @(GetSubResources -ResourceType 'Microsoft.EventHub/namespaces/networkRuleSets')
}

if ($firewalls.Count -eq 0 -and $PSRule.TargetType -eq 'Microsoft.EventHub/namespaces') {
$Assert.HasFieldValue($TargetObject, 'properties.publicNetworkAccess', 'Disabled')
}

else {
foreach ($firewall in $firewalls) {
AnyOf {
$Assert.HasFieldValue($firewall, 'properties.publicNetworkAccess', 'Disabled')
$Assert.HasFieldValue($firewall, 'properties.defaultAction', 'Deny')
}
}
}
}

#endregion Rules

#region Helper functions

function global:Test-IsNoBasicTier {
[CmdletBinding()]
param ()
-not $Assert.HasFieldValue($TargetObject, 'sku.tier', 'Basic').Result
}

#endregion Helper functions
43 changes: 31 additions & 12 deletions tests/PSRule.Rules.Azure.Tests/Azure.EventHub.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ Describe 'Azure.EventHub' -Tag 'EventHub' {
Context 'Conditions' {
BeforeAll {
$invokeParams = @{
Baseline = 'Azure.All'
Module = 'PSRule.Rules.Azure'
Baseline = 'Azure.All'
Module = 'PSRule.Rules.Azure'
WarningAction = 'Ignore'
ErrorAction = 'Stop'
ErrorAction = 'Stop'
}
$dataPath = Join-Path -Path $here -ChildPath 'Resources.EventHub.json';
$result = Invoke-PSRule @invokeParams -InputPath $dataPath;
Expand All @@ -42,8 +42,8 @@ Describe 'Azure.EventHub' -Tag 'EventHub' {
# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 2;
$ruleResult.TargetName | Should -BeIn 'hubns-B', 'hubns-C';
$ruleResult.Length | Should -Be 5;
$ruleResult.TargetName | Should -BeIn 'hubns-B', 'hubns-C', 'hubns-D', 'hubns-E', 'hubns-F';

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
Expand All @@ -58,8 +58,8 @@ Describe 'Azure.EventHub' -Tag 'EventHub' {
# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 2;
$ruleResult.TargetName | Should -BeIn 'hubns-B', 'hubns-C';
$ruleResult.Length | Should -Be 5;
$ruleResult.TargetName | Should -BeIn 'hubns-B', 'hubns-C', 'hubns-D', 'hubns-E', 'hubns-F';

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
Expand All @@ -82,8 +82,27 @@ Describe 'Azure.EventHub' -Tag 'EventHub' {
# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -BeIn 'hubns-C';
$ruleResult.Length | Should -Be 4;
$ruleResult.TargetName | Should -BeIn 'hubns-C', 'hubns-D', 'hubns-E', 'hubns-F';
}

It 'Azure.EventHub.Firewall' {
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.EventHub.Firewall' };

# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult.Length | Should -Be 4;
$ruleResult.TargetName | Should -BeIn 'hubns-B', 'hubns-C', 'hubns-D', 'default-A';

$ruleResult[0].Reason | Should -BeExactly "Path properties.publicNetworkAccess: Does not exist."
$ruleResult[1].Reason | Should -BeExactly "Path properties.publicNetworkAccess: Is set to 'Enabled'."
$ruleResult[2].Reason | Should -BeIn "Path properties.publicNetworkAccess: Is set to 'Enabled'.", "Path properties.defaultAction: Is set to 'Allow'."
$ruleResult[3].Reason | Should -BeIn "Path properties.publicNetworkAccess: Is set to 'Enabled'.", "Path properties.defaultAction: Is set to 'Allow'."

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult.Length | Should -Be 5;
$ruleResult.TargetName | Should -BeIn 'hubns-E', 'hubns-F', 'default-B', 'default-C', 'default-D';
}
}

Expand All @@ -92,10 +111,10 @@ Describe 'Azure.EventHub' -Tag 'EventHub' {
$outputFile = Join-Path -Path $rootPath -ChildPath out/tests/Resources.EventHub.json;
Export-AzRuleTemplateData -TemplateFile (Join-Path -Path $here -ChildPath 'Resources.EventHub.Template.json') -OutputPath $outputFile;
$invokeParams = @{
Baseline = 'Azure.All'
Module = 'PSRule.Rules.Azure'
Baseline = 'Azure.All'
Module = 'PSRule.Rules.Azure'
WarningAction = 'Ignore'
ErrorAction = 'Stop'
ErrorAction = 'Stop'
}
$result = Invoke-PSRule @invokeParams -InputPath $outputFile -Outcome All;
}
Expand Down
Loading

0 comments on commit 9cb4be7

Please sign in to comment.