Skip to content

Commit

Permalink
feat(checks): Added 3.10 rule
Browse files Browse the repository at this point in the history
  • Loading branch information
m-pizarro committed May 20, 2022
1 parent 660e2f3 commit 1f47a98
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/gcp/nist-800-53-rev4/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,6 @@ Policy Pack based on the [800-53 Rev. 4](https://csrc.nist.gov/publications/deta
| GCP NIST 3.7 | PostgreSQL database instance 'log_temp_files' database flag should be set to '0' (on) |
| GCP NIST 3.8 | PostgreSQL database instance 'log_min_duration_statement' database flag should be set to '-1' (disabled) |
| GCP NIST 3.9 | At least one project-level logging sink should be configured with an empty filter |
| GCP NIST 3.10 | Network subnet flow logs should be enabled |
| GCP NIST 4.1 | Compute instance disks should be encrypted with customer-supplied encryption keys (CSEKs) |
| GCP NIST 4.2 | SQL database instances should require incoming connections to use SSL |
90 changes: 90 additions & 0 deletions src/gcp/nist-800-53-rev4/rules/gcp-nist-800-53-rev4-3.10.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// GCP CIS 1.2.0 Rule equivalent 3.8
export default {
id: 'gcp-nist-800-53-rev4-3.10',
title:
'GCP NIST 3.10 Network subnet flow logs should be enabled',
description: `Flow Logs is a feature that enables users to capture information about the IP traffic going to
and from network interfaces in the organization's VPC Subnets. Once a flow log is created,
the user can view and retrieve its data in Stackdriver Logging. It is recommended that Flow
Logs be enabled for every business-critical VPC subnet.`,

audit: `**From Console:**
1. Go to the VPC network GCP Console visiting https://console.cloud.google.com/networking/networks/list
2. From the list of network subnets,
make sure for each subnet *Flow Logs* is set to *On*
**From Command Line:**
gcloud compute networks list --format json | \\ jq -r '.[].subnetworks | .[]' | \
xargs -I {} gcloud compute networks subnets describe {} --format json | \
jq -r '. | "Subnet: \\(.name) Purpose: \\(.purpose) VPC Flow Log Enabled: \\(has("enableFlowLogs"))"'
The output of the above command will list each subnet, the subnet's purpose, and a *true* or *false* value if *Flow Logs* are enabled.
If the subnet's purpose is *PRIVATE* then *Flow Logs* should be *true*.
`,
rationale: `VPC networks and subnetworks not reserved for internal HTTP(S) load balancing provide logically isolated and secure network partitions where GCP resources can be launched. When Flow Logs are enabled for a subnet, VMs within that subnet start reporting on all Transmission Control Protocol (TCP) and User Datagram Protocol (UDP) flows. Each VM samples the TCP and UDP flows it sees, inbound and outbound, whether the flow is to or from another VM, a host in the on-premises datacenter, a Google service, or a host on the Internet. If two GCP VMs are communicating, and both are in subnets that have VPC Flow Logs enabled, both VMs report the flows.
Flow Logs supports the following use cases:
- Network monitoring
- Understanding network usage and optimizing network traffic expenses
- Network forensics
- Real-time security analysis
Flow Logs provide visibility into network traffic for each VM inside the subnet and can be used to detect
anomalous traffic or provide insight during security workflows.
Note: Subnets reserved for use by internal HTTP(S) load balancers do not support VPC flow logs.`,
remediation: `**From Console:**
1. Go to the VPC network GCP Console visiting https://console.cloud.google.com/networking/networks/list
2. Click the name of a subnet, The *Subnet details* page displays.
3. Click the *EDIT* button.
4. Set *Flow Logs* to *On*.
5. Click Save.
**From Command Line:**
To set Private Google access for a network subnet, run the following command:
gcloud compute networks subnets update [SUBNET_NAME] --region [REGION] --enable-flow-logs`,
references: [
'https://cloud.google.com/vpc/docs/using-flow-logs#enabling_vpc_flow_logging',
'https://cloud.google.com/vpc/',
],
gql: `{
querygcpNetwork{
id
__typename
subnets{
purpose
enableFlowLogs
}
}
}`,
resource: 'querygcpNetwork[*]',
severity: 'high',
conditions: {
path: '@.subnets',
array_all: {
or: [
{
path: '[*].purpose',
notEqual: 'PRIVATE',
},
{
and: [
{
path: '[*].purpose',
equal: 'PRIVATE',
},
{
path: '[*].enableFlowLogs',
equal: true,
},
],
},
],
},
},
}
2 changes: 2 additions & 0 deletions src/gcp/nist-800-53-rev4/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Gcp_NIST_800_53_36 from './gcp-nist-800-53-rev4-3.6'
import Gcp_NIST_800_53_37 from './gcp-nist-800-53-rev4-3.7'
import Gcp_NIST_800_53_38 from './gcp-nist-800-53-rev4-3.8'
import Gcp_NIST_800_53_39 from './gcp-nist-800-53-rev4-3.9'
import Gcp_NIST_800_53_310 from './gcp-nist-800-53-rev4-3.10'
import Gcp_NIST_800_53_41 from './gcp-nist-800-53-rev4-4.1'
import Gcp_NIST_800_53_42 from './gcp-nist-800-53-rev4-4.2'

Expand All @@ -40,6 +41,7 @@ export default [
Gcp_NIST_800_53_37,
Gcp_NIST_800_53_38,
Gcp_NIST_800_53_39,
Gcp_NIST_800_53_310,
Gcp_NIST_800_53_41,
Gcp_NIST_800_53_42,
]
154 changes: 152 additions & 2 deletions src/gcp/nist-800-53-rev4/tests/nist-800-53-rev4-3.x.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
/* eslint-disable max-len */
import cuid from 'cuid'
import CloudGraph, { Rule, Result, Engine } from '@cloudgraph/sdk'
import 'jest'

import Gcp_NIST_800_53_31 from '../rules/gcp-nist-800-53-rev4-3.1'
import Gcp_NIST_800_53_32 from '../rules/gcp-nist-800-53-rev4-3.2'
Expand All @@ -11,6 +9,8 @@ import Gcp_NIST_800_53_35 from '../rules/gcp-nist-800-53-rev4-3.5'
import Gcp_NIST_800_53_36 from '../rules/gcp-nist-800-53-rev4-3.6'
import Gcp_NIST_800_53_37 from '../rules/gcp-nist-800-53-rev4-3.7'
import Gcp_NIST_800_53_38 from '../rules/gcp-nist-800-53-rev4-3.8'
import Gcp_NIST_800_53_39 from '../rules/gcp-nist-800-53-rev4-3.9'
import Gcp_NIST_800_53_310 from '../rules/gcp-nist-800-53-rev4-3.10'

export interface DatabaseFlagsItem {
name: string
Expand Down Expand Up @@ -48,9 +48,22 @@ export interface SqlInstances {
ipAddresses?: IpAddress[]
}

export interface LogBucket {
name: string
retentionDays: number
locked: boolean
}

export interface LogSink {
filter?: string
destination?: string
}

export interface QuerygcpProject {
id: string
sqlInstances: SqlInstances[]
logSinks?: LogSink[]
logBuckets?: LogBucket[]
}

export interface AuditLogConfig {
Expand All @@ -69,10 +82,22 @@ export interface QuerygcpIamPolicy {
auditConfigs: AuditConfig[]
}

export interface GcpNetworkSubnet {
purpose: string
enableFlowLogs: boolean | null
}

export interface QuerygcpNetwork {
id: string
subnets?: GcpNetworkSubnet[]
name?: string
ipV4Range?: string | null
}
export interface NIST3xQueryResponse {
querygcpProject?: QuerygcpProject[]
querygcpSqlInstance?: SqlInstances[]
querygcpIamPolicy?: QuerygcpIamPolicy[]
querygcpNetwork?: QuerygcpNetwork[]
}

describe('GCP NIST 800-53: Rev. 4', () => {
Expand Down Expand Up @@ -931,4 +956,129 @@ describe('GCP NIST 800-53: Rev. 4', () => {
await testRule(data, Result.FAIL)
})
})

describe('GCP NIST 3.9 At least one project-level logging sink should be configured with an empty filter', () => {
const getTestRuleFixture = (filter: string): NIST3xQueryResponse => {
return {
querygcpProject: [
{
id: cuid(),
sqlInstances: [],
logSinks: [
{
filter: 'dummy filter',
},
{
filter,
},
],
},
],
}
}

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

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

test('No Security Issue when there is a logSink with an empty filter', async () => {
const data: NIST3xQueryResponse = getTestRuleFixture('')
await testRule(data, Result.PASS)
})

test('Security Issue when there is a logSink with an empty filter', async () => {
const data: NIST3xQueryResponse = getTestRuleFixture('dummy-filter')
await testRule(data, Result.FAIL)
})
})


describe('GCP NIST 3.10 Network subnet flow logs should be enabled', () => {
const testRule = async (
subnets: GcpNetworkSubnet[],
expectedResult: Result
): Promise<void> => {
// Arrange
const data: NIST3xQueryResponse = {
querygcpNetwork: [
{
id: cuid(),
subnets,
},
],
}

// Act
const [processedRule] = await rulesEngine.processRule(
Gcp_NIST_800_53_310 as Rule,
{ ...data }
)

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

test('No Security Issue when all PRIVATE subnets have enableFlowLogs set to true', async () => {
const subnets: GcpNetworkSubnet[] = [
{
purpose: 'PRIVATE',
enableFlowLogs: true,
},
{
purpose: 'PRIVATE',
enableFlowLogs: true,
},
{
purpose: 'DUMMY',
enableFlowLogs: null,
},
{
purpose: 'DUMMY',
enableFlowLogs: true,
},
{
purpose: 'DUMMY',
enableFlowLogs: false,
},
]
await testRule(subnets, Result.PASS)
})

test('Security Issue when at least 1 PRIVATE subnet has enableFlowLogs set to false', async () => {
const subnets: GcpNetworkSubnet[] = [
{
purpose: 'PRIVATE',
enableFlowLogs: true,
},
{
purpose: 'PRIVATE',
enableFlowLogs: false,
},
]
await testRule(subnets, Result.FAIL)
})
test('Security Issue when at least 1 PRIVATE subnet has enableFlowLogs set to null', async () => {
const subnets: GcpNetworkSubnet[] = [
{
purpose: 'PRIVATE',
enableFlowLogs: true,
},
{
purpose: 'PRIVATE',
enableFlowLogs: null,
},
]
await testRule(subnets, Result.FAIL)
})
})
})

0 comments on commit 1f47a98

Please sign in to comment.