Skip to content

Commit

Permalink
Deny all inbound NSG rule #94 #93 #92 #103 (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
BernieWhite authored Jul 25, 2019
1 parent d3d9000 commit 9837410
Show file tree
Hide file tree
Showing 11 changed files with 547 additions and 4 deletions.
20 changes: 17 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,29 @@
},
"cSpell.words": [
"Kubernetes",
"NSGs",
"OWASP",
"RBAC",
"SKUs",
"VNET",
"VNETs",
"cmdlet",
"cmdlets",
"NSGs",
"endregion",
"lifecycle",
"nics",
"stateful",
"subnet",
"subnets",
"VNETs"
"subnets"
],
"cSpell.enabledLanguageIds": [
"csharp",
"git-commit",
"markdown",
"plaintext",
"powershell",
"text",
"yaml",
"yml"
]
}
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
- Enforce minimum TLS version for App Service. [#99](https://github.com/BernieWhite/PSRule.Rules.Azure/issues/99)
- Updated App Service site rules to include slots. [#100](https://github.com/BernieWhite/PSRule.Rules.Azure/issues/100)
- `Azure.AppService.ARRAffinity` and `Azure.AppService.UseHTTPS` now run against slots.
- Added rule to detect deny all inbound NSG rule. [#94](https://github.com/BernieWhite/PSRule.Rules.Azure/issues/94)
- Added unused resource rules.
- Network security groups that are not associated. [#93](https://github.com/BernieWhite/PSRule.Rules.Azure/issues/93)
- Unattached network interfaces. [#92](https://github.com/BernieWhite/PSRule.Rules.Azure/issues/92)
- Added NSG rule to check for lateral traversal security rules. [#103](https://github.com/BernieWhite/PSRule.Rules.Azure/issues/103)

## v0.3.0-B190710 (pre-release)

Expand Down
23 changes: 23 additions & 0 deletions docs/rules/en-US/Azure.VirtualNetwork.LateralTraversal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
severity: Important
category: Security configuration
online version: https://github.com/BernieWhite/PSRule.Rules.Azure/blob/master/docs/rules/en-US/Azure.VirtualNetwork.LateralTraversal.md
---

# Limit lateral traversal

## SYNOPSIS

Deny outbound management connections from non-management hosts.

## DESCRIPTION

Network Security Groups (NSGs) allow virtual machines to be segmented from each other by enforcing access rules for all traffic in/ out of a virtual machine.

This micro-segmentation approach provides a control to reduce lateral movement between hosts within Azure, a virtual network or an individual subnet.

Typically, a subset of trusted hosts such as privileged access workstations, bastion hosts or jump boxes will be used for management. Management protocols originating from application workload hosts should be blocked.

## RECOMMENDATION

Consider configuring NSGs rules to block outbound management traffic from non-management hosts.
19 changes: 19 additions & 0 deletions docs/rules/en-US/Azure.VirtualNetwork.NICAttached.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
severity: Awareness
category: Operations management
online version: https://github.com/BernieWhite/PSRule.Rules.Azure/blob/master/docs/rules/en-US/Azure.VirtualNetwork.NICAttached.md
---

# Attach NIC or clean up

## SYNOPSIS

Network interfaces (NICs) should be attached.

## DESCRIPTION

NICs are deployed as resources separate from virtual machines. NICs that are not attached to a virtual machine perform no purpose.

## RECOMMENDATION

Consider cleaning up NICs that are not required to reduce management complexity. Also consider using Resource Groups to help manage the lifecycle of related resources together.
19 changes: 19 additions & 0 deletions docs/rules/en-US/Azure.VirtualNetwork.NSGAssociated.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
severity: Awareness
category: Operations management
online version: https://github.com/BernieWhite/PSRule.Rules.Azure/blob/master/docs/rules/en-US/Azure.VirtualNetwork.NSGAssociated.md
---

# Associate NSGs or clean up

## SYNOPSIS

Network Security Groups (NSGs) should be associated.

## DESCRIPTION

NSGs basic stateful firewalls that are deployed as separate resources and can be associated to network interfaces or subnets. NSGs that are not associated with a network interface or subnet perform no purpose.

## RECOMMENDATION

Consider cleaning up NSGs that are not required to reduce management complexity. Also consider using Resource Groups to help manage the lifecycle of related resources together.
25 changes: 25 additions & 0 deletions docs/rules/en-US/Azure.VirtualNetwork.NSGDenyAllInbound.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
severity: Important
category: Reliability
online version: https://github.com/BernieWhite/PSRule.Rules.Azure/blob/master/docs/rules/en-US/Azure.VirtualNetwork.NSGDenyAllInbound.md
---

# Avoid denying all inbound traffic

## SYNOPSIS

Avoid denying all inbound traffic.

## DESCRIPTION

Network Security Groups can be configured to block all network traffic inbound to a virtual machine.

Blocking all inbound traffic into a virtual machine will fail load balancer health probes and other required traffic.

Inbound network traffic can be whitelisted by including allow rules above deny all inbound rule by specifying a lower priority number. Rules with a lower priority number will be process first.

## RECOMMENDATION

Deny all inbound rules should not use priority 100. The lowest configurable priority is 100, meaning that whitelisted network traffic rules can not be placed before the deny all.

Consider whitelisting inbound network traffic as required.
5 changes: 5 additions & 0 deletions docs/rules/en-US/Azure.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ RuleName | Description | Category
[Azure.AppService.MinPlan](Azure.AppService.MinPlan.md) | Use at least a Standard App Service Plan. | Performance
[Azure.AppService.ARRAffinity](Azure.AppService.ARRAffinity.md) | Disable client affinity for stateless services. | Performance
[Azure.AppService.UseHTTPS](Azure.AppService.UseHTTPS.md) | Use HTTPS only. Disable HTTP when not required. | Security configuration
[Azure.AppService.MinTLS](Azure.AppService.MinTLS.md) | App Service should reject TLS versions older then 1.2. | Security configuration
[Azure.DataFactory.Version](Azure.DataFactory.Version.md) | Consider migrating to DataFactory v2. | Operations management
[Azure.MySQL.UseSSL](Azure.MySQL.UseSSL.md) | Enforce encrypted MySQL connections. | Security configuration
[Azure.MySQL.FirewallRuleCount](Azure.MySQL.FirewallRuleCount.md) | Determine if there is an excessive number of firewall rules. | Operations management
Expand Down Expand Up @@ -52,6 +53,9 @@ RuleName | Description | Category
[Azure.VirtualNetwork.SingleDNS](Azure.VirtualNetwork.SingleDNS.md) | VNETs should have at least two DNS servers assigned. | Reliability
[Azure.VirtualNetwork.LocalDNS](Azure.VirtualNetwork.LocalDNS.md) | Virtual networks (VNETs) should use Azure local DNS servers. | Reliability
[Azure.VirtualNetwork.NSGAnyInboundSource](Azure.VirtualNetwork.NSGAnyInboundSource.md) | Network security groups should avoid any inbound rules. | Security configuration
[Azure.VirtualNetwork.NSGDenyAllInbound](Azure.VirtualNetwork.NSGDenyAllInbound.md) | Avoid denying all inbound traffic. | Reliability
[Azure.VirtualNetwork.LateralTraversal](Azure.VirtualNetwork.LateralTraversal.md) | Deny outbound management connections from non-management hosts. | Security configuration
[Azure.VirtualNetwork.NSGAssociated](Azure.VirtualNetwork.NSGAssociated.md) | Network Security Groups (NSGs) should be associated. | Operations management
[Azure.VirtualNetwork.AppGwMinInstance](Azure.VirtualNetwork.AppGwMinInstance.md) | Application Gateways should use a minimum of two instances. | Reliability
[Azure.VirtualNetwork.AppGwMinSku](Azure.VirtualNetwork.AppGwMinSku.md) | Application Gateway should use a minimum instance size of Medium. | Performance
[Azure.VirtualNetwork.AppGwUseWAF](Azure.VirtualNetwork.AppGwUseWAF.md) | Internet accessible Application Gateways should use WAF. | Security configuration
Expand All @@ -60,3 +64,4 @@ RuleName | Description | Category
[Azure.VirtualNetwork.AppGwWAFEnabled](Azure.VirtualNetwork.AppGwWAFEnabled.md) | Application Gateway Web Application Firewall (WAF) must be enabled to protect backend resources. | Security configuration
[Azure.VirtualNetwork.AppGwOWASP](Azure.VirtualNetwork.AppGwOWASP.md) | Application Gateway Web Application Firewall (WAF) should use OWASP 3.x rules. | Security configuration
[Azure.VirtualNetwork.AppGwWAFRules](Azure.VirtualNetwork.AppGwWAFRules.md) | Application Gateway Web Application Firewall (WAF) should have all rules enabled. | Security configuration
[Azure.VirtualNetwork.NICAttached](Azure.VirtualNetwork.NICAttached.md) | Network interfaces (NICs) should be attached. | Operations management
8 changes: 8 additions & 0 deletions src/PSRule.Rules.Azure/rules/Azure.Common.Rule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ function global:IsExport {
}
}

# Get a sorted list of NSG rules
function global:GetOrderedNSGRules {
param ()
process {
$TargetObject.properties.securityRules | Sort-Object @{ Expression = { $_.Properties.priority }; Descending = $False }
}
}

function global:SupportsAcceleratedNetworking {
process {
if ($TargetObject.ResourceType -ne 'Microsoft.Compute/virtualMachines' -or !(IsExport)) {
Expand Down
60 changes: 59 additions & 1 deletion src/PSRule.Rules.Azure/rules/Azure.VirtualNetwork.Rule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Validation rules for virtual networking
#

#region Virtual Network

# Synopsis: Subnets should have NSGs assigned, except for the GatewaySubnet
Rule 'Azure.VirtualNetwork.UseNSGs' -If { ResourceType 'Microsoft.Network/virtualNetworks' } -Tag @{ severity = 'Critical'; category = 'Security configuration' } {
Recommend 'Subnets should have NSGs assigned'
Expand All @@ -21,7 +23,7 @@ Rule 'Azure.VirtualNetwork.UseNSGs' -If { ResourceType 'Microsoft.Network/virtua

# Synopsis: VNETs should have at least two DNS servers assigned
Rule 'Azure.VirtualNetwork.SingleDNS' -If { ResourceType 'Microsoft.Network/virtualNetworks' } -Tag @{ severity = 'Single point of failure'; category = 'Reliability' } {
# If DNS servers are customsied, at least two IP addresses should be defined
# If DNS servers are customized, at least two IP addresses should be defined
if (!(Exists 'properties.dhcpOptions.dnsServers') -or ($TargetObject.properties.dhcpOptions.dnsServers.Count -eq 0)) {
$True;
}
Expand Down Expand Up @@ -50,6 +52,10 @@ Rule 'Azure.VirtualNetwork.LocalDNS' -If { ResourceType 'Microsoft.Network/virtu
}
}

#endregion Virtual Network

#region Network Security Group

# Synopsis: Network security groups should avoid any inbound rules
Rule 'Azure.VirtualNetwork.NSGAnyInboundSource' -If { ResourceType 'Microsoft.Network/networkSecurityGroups' } -Tag @{ severity = 'Critical'; category = 'Security configuration' } {
Recommend 'Avoid rules that apply to all source addresses'
Expand All @@ -63,6 +69,47 @@ Rule 'Azure.VirtualNetwork.NSGAnyInboundSource' -If { ResourceType 'Microsoft.Ne
$Null -eq $rules;
}

# Synopsis: Avoid blocking all inbound network traffic
Rule 'Azure.VirtualNetwork.NSGDenyAllInbound' -If { ResourceType 'Microsoft.Network/networkSecurityGroups' } {
$denyRules = @(GetOrderedNSGRules | Where-Object {
$_.properties.direction -eq 'Inbound' -and
$_.properties.access -eq 'Deny' -and
$_.properties.sourceAddressPrefix -eq '*'
})
$inboundRules = @(GetOrderedNSGRules | Where-Object {
$_.properties.direction -eq 'Inbound'
})

$Null -eq $denyRules -or $denyRules.Length -eq 0 -or $denyRules[0].name -ne $inboundRules[0].name
}

# Synopsis: Lateral traversal from application servers should be blocked
Rule 'Azure.VirtualNetwork.LateralTraversal' -If { ResourceType 'Microsoft.Network/networkSecurityGroups' } {
$rules = @($TargetObject.properties.securityRules | Where-Object {
$_.properties.direction -eq 'Outbound' -and
$_.properties.access -eq 'Deny' -and
(
$_.properties.destinationPortRange -eq '3389' -or
$_.properties.destinationPortRange -eq '22'
)
})

$Null -ne $rules -and $rules.Length -gt 0
}

# Synopsis: Network security groups should be associated to either a subnet or network interface
Rule 'Azure.VirtualNetwork.NSGAssociated' -If { ResourceType 'Microsoft.Network/networkSecurityGroups' } {
$subnets = ($TargetObject.Properties.subnets | Measure-Object).Count;
$interfaces = ($TargetObject.Properties.networkInterfaces | Measure-Object).Count;

# NSG should be associated to either a subnet or network interface
$subnets -gt 0 -or $interfaces -gt 0
}

#endregion Network Security Group

#region Application Gateway

# Synopsis: Application Gateway should use a minimum of two instances
Rule 'Azure.VirtualNetwork.AppGwMinInstance' -If { ResourceType 'Microsoft.Network/applicationGateways' } -Tag @{ severity = 'Important'; category = 'Reliability' } {
AnyOf {
Expand Down Expand Up @@ -114,3 +161,14 @@ Rule 'Azure.VirtualNetwork.AppGwWAFRules' -If { (IsAppGwWAF) } {
$disabledRules = @($TargetObject.Properties.webApplicationFirewallConfiguration.disabledRuleGroups)
$disabledRules.Count -eq 0
}

#endregion Application Gateway

#region Network Interface

# Synopsis: Network interfaces should be attached
Rule 'Azure.VirtualNetwork.NICAttached' -If { ResourceType 'Microsoft.Network/networkInterfaces' } {
Exists 'Properties.virtualMachine.id'
}

#endregion Network Interface
64 changes: 64 additions & 0 deletions tests/PSRule.Rules.Azure.Tests/Azure.VirtualNetwork.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,54 @@ Describe 'Azure.VirtualNetwork' -Tag 'Network' {
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'nsg-B';

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 2;
$ruleResult.TargetName | Should -Be 'nsg-A', 'nsg-C';
}

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

# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'nsg-C';

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 2;
$ruleResult.TargetName | Should -Be 'nsg-A', 'nsg-B';
}

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

# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'nsg-C';

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 2;
$ruleResult.TargetName | Should -BeIn 'nsg-A', 'nsg-B';
}

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

# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 2;
$ruleResult.TargetName | Should -Be 'nsg-B', 'nsg-C';

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
Expand Down Expand Up @@ -217,5 +265,21 @@ Describe 'Azure.VirtualNetwork' -Tag 'Network' {
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'appgw-A';
}

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

# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'nic-B';

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -Be 'nic-A';
}
}
}
Loading

0 comments on commit 9837410

Please sign in to comment.