Skip to content

Commit

Permalink
Added Azure.VM.PublicIPAttached (#3012)
Browse files Browse the repository at this point in the history
* Added Azure.VM.PublicIPAttached

* Update changelog

* Update docs/en/rules/Azure.VM.PublicIPAttached.md

Co-authored-by: Bernie White <[email protected]>

* Update docs/en/rules/Azure.VM.PublicIPAttached.md

Co-authored-by: Bernie White <[email protected]>

* Update docs/en/rules/Azure.VM.PublicIPAttached.md

Co-authored-by: Bernie White <[email protected]>

* Update docs/en/rules/Azure.VM.PublicIPAttached.md

Co-authored-by: Bernie White <[email protected]>

* Update docs/en/rules/Azure.VM.PublicIPAttached.md

Co-authored-by: Bernie White <[email protected]>

---------

Co-authored-by: Bernie White <[email protected]>
  • Loading branch information
BenjaminEngeset and BernieWhite authored Aug 12, 2024
1 parent e4dedd8 commit fe84d55
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 0 deletions.
5 changes: 5 additions & 0 deletions docs/CHANGELOG-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers

## Unreleased

- New rules:
- Virtual Machine:
- Verify that virtual machines does not have public IPs attached by @BenjaminEngeset.
[#11](https://github.com/Azure/PSRule.Rules.Azure/issues/11)

## v1.39.0-B0029 (pre-release)

What's changed since pre-release v1.39.0-B0009:
Expand Down
101 changes: 101 additions & 0 deletions docs/en/rules/Azure.VM.PublicIPAttached.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
severity: Critical
pillar: Security
category: SE:06 Network controls
resource: Virtual Machine
online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.VM.PublicIPAttached/
---

# Public IPs attached

## SYNOPSIS

Avoid attaching public IPs directly to virtual machines.

## DESCRIPTION

Attaching a public IP address to a virtual machine network interface (NIC) exposes it directly to the Internet.
This exposure can make the VM vulnerable to unauthorized inbound access and security compromise.
Minimize the number of Internet ingress/ egress points to enhance security and reduces potential attack surfaces.

For enhanced security, consider one or more of the following options:

- **Secure remote access** &mdash; by RDP or SSH to virtual machines can be configured through Azure Bastion.
- Azure Bastion provides a secure encrypted connection without exposing a public IP.
- **Exposing web services** &mdash; by HTTP/S can be configured by App Gateway or Azure Front Door (AFD).
- App Gateway and AFD provide a secure reverse proxy that supports web application firewall (WAF) filtering.
- **Internet connectivity** &mdash; should be managed through a security hardened device such as Azure Firewall.
- This option also allows additional controls to be applied for east/ west and north/ south traffic filtering.
- Alternatively a Network Virtual Appliance (NVA) can used.

## RECOMMENDATION

Evaluate alternative methods for inbound access to virtual machines to enhance security and minimize risk.

### Configure with Azure template

To deploy VM network interfaces that pass this rule:

- For each IP configuration specified in the `properties.ipConfigurations` property:
- Ensure that the `properties.publicIPAddress.id` property does not reference a Public IP resource.

For example:

```json
{
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2023-11-01",
"name": "[parameters('nicName')]",
"location": "[parameters('location')]",
"properties": {
"ipConfigurations": [
{
"name": "[parameters('ipConfig')]",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName'))]"
}
}
}
]
}
}
```

### Configure with Bicep

To deploy VM network interfaces that pass this rule:

- For each IP configuration specified in the `properties.ipConfigurations` property:
- Ensure that the `properties.publicIPAddress.id` property does not reference a Public IP resource.

For example:

```bicep
resource nic 'Microsoft.Network/networkInterfaces@2023-11-01' = {
name: nicName
location: location
properties: {
ipConfigurations: [
{
name: ipconfig
properties: {
privateIPAllocationMethod: 'Dynamic'
subnet: {
id: resourceId('Microsoft.Network/virtualNetworks/subnets', virtualNetworkName, subnetName)
}
}
}
]
}
}
```

## LINKS

- [SE:06 Network controls](https://learn.microsoft.com/azure/well-architected/security/networking)
- [Plan for inbound and outbound internet connectivity](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-inbound-and-outbound-internet-connectivity)
- [Dissociate public IP address from a VM](https://learn.microsoft.com/azure/virtual-network/ip-services/remove-public-ip-address-vm)
- [Azure Bastion](https://learn.microsoft.com/azure/bastion/bastion-overview)
- [Azure deployment reference](https://learn.microsoft.com/azure/templates/microsoft.network/networkinterfaces)
1 change: 1 addition & 0 deletions src/PSRule.Rules.Azure/en/PSRule-rules.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,5 @@
AppServiceAvailabilityZoneSKU = "The app service plan ({0}) is not deployed with a SKU that supports zone-redundancy."
FirewallSubnetNAT = "The firewall should have a NAT gateway associated."
PrivateSubnet = "The subnet ({0}) should disable default outbound access."
VMPublicIPAttached = "The virtual machine with the NIC ({0}) should not have a public IP address attached."
}
17 changes: 17 additions & 0 deletions src/PSRule.Rules.Azure/rules/Azure.VM.Rule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,23 @@ Rule 'Azure.VM.MaintenanceConfig' -Ref 'AZR-000375' -Type 'Microsoft.Compute/vir

#endregion Maintenance Configuration

#region Public IP

# Synopsis: Avoid attaching public IPs directly to virtual machines.
Rule 'Azure.VM.PublicIPAttached' -Ref 'AZR-000449' -Type 'Microsoft.Network/networkInterfaces' -Tag @{ release = 'GA'; ruleSet = '2024_09'; 'Azure.WAF/pillar' = 'Security'; } {
$configurations = @($TargetObject.properties.ipConfigurations)

if ($configurations.Count -eq 0) {
return $Assert.Pass()
}

foreach ($config in $configurations) {
$Assert.HasDefaultValue($config, 'properties.publicIPAddress.id', $null).Reason($LocalizedData.VMPublicIPAttached, $PSRule.TargetName)
}
}

#endregion Public IP

#region Helper functions

function global:HasPublisherMicrosoftSQLServer {
Expand Down
18 changes: 18 additions & 0 deletions tests/PSRule.Rules.Azure.Tests/Azure.VM.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,24 @@ Describe 'Azure.VM' -Tag 'VM' {
$ruleResult.Length | Should -Be 1;
$ruleResult.TargetName | Should -BeIn 'vm-C';
}

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

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

$ruleResult[0].Reason | Should -BeExactly "The virtual machine with the NIC (nic-A) should not have a public IP address attached.";
$ruleResult[1].Reason | Should -BeExactly "The virtual machine with the NIC (nic-B) should not have a public IP address attached.";
$ruleResult[2].Reason | Should -BeExactly "The virtual machine with the NIC (nic-C) should not have a public IP address attached.";

# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult.Length | Should -Be 5;
$ruleResult.TargetName | Should -Be 'aks-agentpool-00000000-nic-1', 'aks-agentpool-00000000-nic-2', 'aks-agentpool-00000000-nic-3', 'pe-001', 'private-link.nic.00000000-0000-0000-0000-000000000000';
}
}

Context 'Resource name - Azure.VM.Name' {
Expand Down

0 comments on commit fe84d55

Please sign in to comment.