Skip to content

Commit

Permalink
Merge pull request #89 from cloudgraphdev/feature/CG-1168-support-azu…
Browse files Browse the repository at this point in the history
…re-pci-virtual-network

feat(CG-1168): add azure networking 3 rule
  • Loading branch information
tyler-dunkel authored Sep 2, 2022
2 parents 8cecc65 + 6d3925d commit e9e5c27
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/azure/pci-dss-3.2.1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,4 @@ Policy Pack based on the [PCI DSS version 3.2.1](https://www.pcisecuritystandard
| monitoring-check-4 | Monitor log profile should be created |
| networking-check-1 | Virtual Network security groups should not permit ingress from ‘0.0.0.0/0’ to TCP port 3389 (RDP) |
| networking-check-2 | Virtual Network security groups attached to SQL Server instances should not permit ingress from 0.0.0.0/0 to all ports and protocols |
| networking-check-3 | Virtual Network security groups should not permit ingress from '0.0.0.0/0' to TCP/UDP port 22 (SSH) |
94 changes: 94 additions & 0 deletions src/azure/pci-dss-3.2.1/rules/pci-dss-3.2.1-networking-check-3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
export default {
id: 'pci-dss-3.2.1-networking-check-3',
title:
'Networking Check 3: Virtual Network security groups should not permit ingress from 0.0.0.0/0 to TCP/UDP port 22 (SSH)',

description: 'Disable SSH access on network security groups from the Internet.',

audit: `**From Azure Console**
1. Open the Networking blade for the specific Virtual machine in Azure portal
2. Verify that the INBOUND PORT RULES **does not** have a rule for SSH such as
- port = 22,
- protocol = TCP,
- Source = Any OR Internet
**Using Azure Command Line Interface 2.0**
List Network security groups with corresponding non-default Security rules:
az network nsg list --query [*].[name,securityRules]
Ensure that none of the NSGs have security rule as below
"access" : "Allow"
"destinationPortRange" : "22" or "*" or "[port range containing 22]"
"direction" : "Inbound"
"protocol" : "TCP"
"sourceAddressPrefix" : "*" or "0.0.0.0" or "<nw>/0" or "/0" or "internet" or "any"`,

rationale: 'The potential security problem with using SSH over the Internet is that attackers can use various brute force techniques to gain access to Azure Virtual Machines. Once the attackers gain access, they can use a virtual machine as a launch point for compromising other machines on the Azure Virtual Network or even attack networked devices outside of Azure.',

remediation: `Disable direct SSH access to your Azure Virtual Machines from the Internet. After direct SSH access from the Internet is disabled, you have other options you can use to access these virtual machines for remote management:
- [Point-to-site VPN](https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-howto-point-to-site-resource-manager-portal)
- [Site-to-site VPN](https://docs.microsoft.com/en-us/azure/vpn-gateway/tutorial-site-to-site-portal)
- [ExpressRoute](https://docs.microsoft.com/en-us/azure/expressroute/)`,

references: [
'https://docs.microsoft.com/en-us/azure/security/azure-security-network-security-best-practices#disable-rdpssh-access-to-azure-virtual-machines',
'https://docs.microsoft.com/en-us/azure/security/benchmarks/security-controls-v2-network-security#ns-1-implement-security-for-internal-traffic',
],
gql: `{
queryazureNetworkSecurityGroup {
id
__typename
securityRules {
access
destinationPortRange
direction
protocol
sourceAddressPrefix
}
}
}`,
resource: 'queryazureNetworkSecurityGroup[*]',
severity: 'high',
conditions: {
not: {
path: '@.securityRules',
array_any: {
and: [
{
path: '[*].access',
in: ['Allow', 'allow']
},
{
or: [
{
path: '[*].destinationPortRange',
in: ['22', '*']
},
{
path: '[*].destinationPortRange',
match: /22/
}
]
},
{
path: '[*].direction',
in: ['Inbound', 'inbound']
},
{
path: '[*].protocol',
in: ['TCP', 'Tcp']
},
{
path: '[*].sourceAddressPrefix',
in: ['*', '0.0.0.0', '<nw>/0', '/0', 'Internet', 'internet', 'Any', 'any']
},
],
},
},
},
}
114 changes: 114 additions & 0 deletions src/azure/pci-dss-3.2.1/tests/pci-dss-3.2.1-networking-checks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { initRuleEngine } from '../../../utils/test'

import Azure_PCI_DSS_321_Networking_1 from '../rules/pci-dss-3.2.1-networking-check-1'
import Azure_PCI_DSS_321_Networking_2 from '../rules/pci-dss-3.2.1-networking-check-2'
import Azure_PCI_DSS_321_Networking_3 from '../rules/pci-dss-3.2.1-networking-check-3'

const ipV4WildcardAddress = '0.0.0.0/0'
const ipV6WildcardAddress = '::/0'
Expand Down Expand Up @@ -41,9 +42,29 @@ export interface QueryazureSqlServer {
firewallRules: FirewallRule[]
}

export interface SecurityRules {
access: string | undefined
destinationPortRange: string | undefined
direction: string | undefined
protocol: string | undefined
sourceAddressPrefix: string | undefined
}

export interface FlowLogs {
retentionPolicyEnabled?: boolean | undefined
retentionPolicyDays?: number | undefined
}

export interface QueryazureNetworkSecurityGroup {
id: string
securityRules?: SecurityRules[]
flowLogs?: FlowLogs[]
}

export interface PCIQueryResponse {
queryazureVirtualMachine?: QueryazureVirtualMachine[]
queryazureSqlServer?: QueryazureSqlServer[]
queryazureNetworkSecurityGroup?: QueryazureNetworkSecurityGroup[]
}

describe('PCI Data Security Standard: 3.2.1', () => {
Expand Down Expand Up @@ -209,6 +230,99 @@ describe('PCI Data Security Standard: 3.2.1', () => {
test('No Security Issue when there is an inbound that allow any IP', async () => {
await testRule('255.255.255.255', '0.0.0.0', Result.FAIL)
})
})

describe('Networking Check 3: Virtual Network security groups should not permit ingress from 0.0.0.0/0 to TCP/UDP port 22 (SSH)', () => {
const getTestRuleFixture = (
access?: string,
destinationPortRange?: string,
direction?: string,
protocol?: string,
sourceAddressPrefix?: string
): PCIQueryResponse => {
return {
queryazureNetworkSecurityGroup: [
{
id: cuid(),
securityRules: [
{
access,
destinationPortRange,
direction,
protocol,
sourceAddressPrefix,
},
],
},
],
}
}

const testRule = async (
data: PCIQueryResponse,
expectedResult: Result
): Promise<void> => {
// Act
const [processedRule] = await rulesEngine.processRule(
Azure_PCI_DSS_321_Networking_3 as Rule,
{ ...data }
)

// Asserts
expect(processedRule.result).toBe(expectedResult)
}

test('No Security Issue when SSH access is restricted from the internet', async () => {
const data: PCIQueryResponse = getTestRuleFixture('Deny', '22', 'Inbound', 'Tcp', 'Internet')

await testRule(data, Result.PASS)
})
test('No Security Issue when SSH access is restricted from the internet (No inbound rules configured)', async () => {
const data: PCIQueryResponse = getTestRuleFixture()
const securityGroup = data.queryazureNetworkSecurityGroup?.[0] as QueryazureNetworkSecurityGroup
securityGroup.securityRules = []
await testRule(data, Result.PASS)
})
test('Security Issue when there is an inbound rule with destinationPortRange equal to 22', async () => {
const data: PCIQueryResponse = getTestRuleFixture('Allow', '22', 'Inbound', 'Tcp', 'Internet')

await testRule(data, Result.FAIL)
})
test('Security Issue when there is an inbound rule with destinationPortRange equal to *', async () => {
const data: PCIQueryResponse = getTestRuleFixture('Allow', '*', 'Inbound', 'Tcp', 'Internet')

await testRule(data, Result.FAIL)
})
test('Security Issue when there is an inbound rule with destinationPortRange containing port 22', async () => {
const data: PCIQueryResponse = getTestRuleFixture('Allow', '["3389-3390","22","23"]', 'Inbound', 'Tcp', 'Internet')

await testRule(data, Result.FAIL)
})
test('Security Issue when there is an inbound rule with sourceAddressPrefix equal to *', async () => {
const data: PCIQueryResponse = getTestRuleFixture('Allow', '22', 'Inbound', 'Tcp', '*')

await testRule(data, Result.FAIL)
})
test('Security Issue when there is an inbound rule with sourceAddressPrefix equal to 0.0.0.0,', async () => {
const data: PCIQueryResponse = getTestRuleFixture('Allow', '22', 'Inbound', 'Tcp', '0.0.0.0')

await testRule(data, Result.FAIL)
})
test('Security Issue when there is an inbound rule with sourceAddressPrefix equal to <nw>/0,', async () => {
const data: PCIQueryResponse = getTestRuleFixture('Allow', '22', 'Inbound', 'Tcp', '<nw>/0')

await testRule(data, Result.FAIL)
})
test('Security Issue when there is an inbound rule with sourceAddressPrefix equal to Internet,', async () => {
const data: PCIQueryResponse = getTestRuleFixture('Allow', '22', 'Inbound', 'Tcp', 'Internet')

await testRule(data, Result.FAIL)
})

test('Security Issue when there is an inbound rule with sourceAddressPrefix equal to any,', async () => {
const data: PCIQueryResponse = getTestRuleFixture('Allow', '22', 'Inbound', 'Tcp', 'any')

await testRule(data, Result.FAIL)
})
})
})

0 comments on commit e9e5c27

Please sign in to comment.