Skip to content

Commit

Permalink
feat(CG-1293): add GCP CIS 1.30 1.16 rule
Browse files Browse the repository at this point in the history
  • Loading branch information
james-zhou-inspire11 committed Dec 10, 2022
1 parent 3040547 commit 286ea82
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/gcp/cis-1.3.0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Policy Pack based on the GCP Foundations 1.3.0 benchmark provided by the [Center
| GCP CIS 1.13 | Ensure API keys are restricted to use by only specified Hosts and Apps |
| GCP CIS 1.14 | Ensure API keys are restricted to only APIs that application needs access |
| GCP CIS 1.15 | Ensure API keys are rotated every 90 days |
| GCP CIS 1.16 | Ensure Essential Contacts is Configured for Organization |
| GCP CIS 2.1 | Ensure that Cloud Audit Logging is configured properly across all services and all users from a project |
| GCP CIS 2.2 | Ensure that sinks are configured for all log entries |
| GCP CIS 2.3 | Ensure that retention policies on log buckets are configured using Bucket Lock |
Expand Down
96 changes: 96 additions & 0 deletions src/gcp/cis-1.3.0/rules/gcp-cis-1.3.0-1.16.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable @typescript-eslint/no-explicit-any */

export default {
id: 'gcp-cis-1.3.0-1.16',
title: 'GCP CIS 1.16 Ensure Essential Contacts is Configured for Organization',
description:
'It is recommended that Essential Contacts is configured to designate email addresses for Google Cloud services to notify of important technical or security information.',
audit: `**From Console:**
1. Go to Essential Contacts by visiting https://console.cloud.google.com/iam-admin/essential-contacts
2. Make sure the organization appears in the resource selector at the top of the page. The resource selector tells you what project, folder, or organization you are currently managing contacts for.
3. Ensure that appropriate email addresses are configured for each of the following notification categories:
- Legal
- Security
- Suspension
- Technical
- Technical Incidents
Alternatively, appropriate email addresses can be configured for the All notification category to receive all possible important notifications.
**From Command Line:**
1. To list all configured organization Essential Contacts run a command:
gcloud essential-contacts list --organization=<ORGANIZATION_ID>
2. Ensure at least one appropriate email address is configured for each of the following notification categories:
- LEGAL
- SECURITY
- SUSPENSION
- TECHNICAL
- TECHNICAL_INCIDENTS
Alternatively, appropriate email addresses can be configured for the ALL notification category to receive all possible important notifications.
`,
rationale:
'Many Google Cloud services, such as Cloud Billing, send out notifications to share important information with Google Cloud users. By default, these notifications are sent to members with certain Identity and Access Management (IAM) roles. With Essential Contacts, you can customize who receives notifications by providing your own list of contacts.',
remediation: `**From Console:**
1. Go to Essential Contacts by visiting https://console.cloud.google.com/iam-admin/essential-contacts
2. Make sure the organization appears in the resource selector at the top of the page. The resource selector tells you what project, folder, or organization you are currently managing contacts for.
3. Click +Add contact
4. In the Email and Confirm Email fields, enter the email address of the contact.
5. From the Notification categories drop-down menu, select the notification categories that you want the contact to receive communications for.
6. Click Save
**From Command Line:**
1. To add an organization Essential Contacts run a command:
gcloud essential-contacts create --email="<EMAIL>" \
--notification-categories="<NOTIFICATION_CATEGORIES>" \
--organization=<ORGANIZATION_ID>
**Default Value:**
By default, there are no Essential Contacts configured.
In the absence of an Essential Contact, the following IAM roles are used to identify users to
notify for the following categories:
• Legal: roles/billing.admin
• Security: roles/resourcemanager.organizationAdmin
• Suspension: roles/owner
• Technical: roles/owner
• Technical Incidents: roles/owner
`,
references: [
'https://cloud.google.com/resource-manager/docs/managing-notification-contacts',
],
gql: `{
querygcpEssentialContact {
id
__typename
notificationCategorySubscriptions
email
}
}`,
resource: 'querygcpEssentialContact[1]',
severity: 'unknown',

check: ({ data }: any): boolean => {
const requiredCategories = ['LEGAL', 'SECURITY', 'SUSPENSION', 'TECHNICAL', 'TECHNICAL_INCIDENTS']
const categoryAll = 'ALL'

const subscribedCategories = data.querygcpEssentialContact
.filter((obj: any) => !('@' in obj))
.flatMap(({notificationCategorySubscriptions}: any) => notificationCategorySubscriptions)

const result = requiredCategories.every((category: any) => subscribedCategories.includes(category))

return result || subscribedCategories.includes(categoryAll)
}
}
2 changes: 2 additions & 0 deletions src/gcp/cis-1.3.0/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Gcp_CIS_130_112 from './gcp-cis-1.3.0-1.12'
import Gcp_CIS_130_113 from './gcp-cis-1.3.0-1.13'
import Gcp_CIS_130_114 from './gcp-cis-1.3.0-1.14'
import Gcp_CIS_130_115 from './gcp-cis-1.3.0-1.15'
import Gcp_CIS_130_116 from './gcp-cis-1.3.0-1.16'
import Gcp_CIS_130_21 from './gcp-cis-1.3.0-2.1'
import Gcp_CIS_130_22 from './gcp-cis-1.3.0-2.2'
import Gcp_CIS_130_23 from './gcp-cis-1.3.0-2.3'
Expand Down Expand Up @@ -89,6 +90,7 @@ export default [
Gcp_CIS_130_113,
Gcp_CIS_130_114,
Gcp_CIS_130_115,
Gcp_CIS_130_116,
Gcp_CIS_130_21,
Gcp_CIS_130_22,
Gcp_CIS_130_23,
Expand Down
76 changes: 76 additions & 0 deletions src/gcp/cis-1.3.0/tests/gcp-cis-1.3.0-1.x.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Gcp_CIS_130_111 from '../rules/gcp-cis-1.3.0-1.11'
import Gcp_CIS_130_112 from '../rules/gcp-cis-1.3.0-1.12'
import Gcp_CIS_130_113 from '../rules/gcp-cis-1.3.0-1.13'
import Gcp_CIS_130_115 from '../rules/gcp-cis-1.3.0-1.15'
import Gcp_CIS_130_116 from '../rules/gcp-cis-1.3.0-1.16'
import { initRuleEngine } from '../../../utils/test'

export interface MetricDescriptor {
Expand Down Expand Up @@ -103,13 +104,20 @@ export interface QuerygcpIamPolicy {
id: string
bindings: Bindings[]
}

export interface QuerygcpEssentialContact {
id: string
notificationCategorySubscriptions: string[]
email: string
}
export interface CIS1xQueryResponse {
querygcpOrganization?: QuerygcpOrganization[]
querygcpProject?: QuerygcpProject[]
querygcpApiKey?: QuerygcpApiKey[]
querygcpServiceAccount?: QuerygcpServiceAccount[]
querygcpKmsKeyRing?: QuerygcpKmsKeyRing[]
querygcpIamPolicy?: QuerygcpIamPolicy[]
querygcpEssentialContact?: QuerygcpEssentialContact[]
}

describe('CIS Google Cloud Platform Foundations: 1.3.0', () => {
Expand Down Expand Up @@ -881,4 +889,72 @@ describe('CIS Google Cloud Platform Foundations: 1.3.0', () => {
await testRule(data, Result.FAIL)
})
})

describe('GCP CIS 1.16 Ensure Essential Contacts is Configured for Organizations', () => {
const testRule = async (
data: CIS1xQueryResponse,
expectedResult: Result
): Promise<void> => {
// Act
const [processedRule] = await rulesEngine.processRule(
Gcp_CIS_130_116 as Rule,
{ ...data }
)

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

test('Emails subscribed all required categories', async () => {
const data: CIS1xQueryResponse = {
querygcpEssentialContact: [
{
id: cuid(),
notificationCategorySubscriptions: ['LEGAL', 'TECHNICAL', 'SUSPENSION', 'SECURITY'],
email: 'a@gmail.com'
},
{
id: cuid(),
notificationCategorySubscriptions: ['TECHNICAL_INCIDENTS', 'SECURITY', 'BILLING'],
email: 'b@gmail.com'
},
],
}
await testRule(data, Result.PASS)
})
test('Emails missed one required subscription category', async () => {
const data: CIS1xQueryResponse = {
querygcpEssentialContact: [
{
id: cuid(),
notificationCategorySubscriptions: ['LEGAL', 'SUSPENSION', 'SECURITY'],
email: 'a@gmail.com'
},
{
id: cuid(),
notificationCategorySubscriptions: ['TECHNICAL_INCIDENTS', 'SECURITY', 'BILLING'],
email: 'b@gmail.com'
},
],
}
await testRule(data, Result.FAIL)
})
test('An email subscribed ALL category', async () => {
const data: CIS1xQueryResponse = {
querygcpEssentialContact: [
{
id: cuid(),
notificationCategorySubscriptions: ['LEGAL', 'TECHNICAL', 'SUSPENSION', 'SECURITY'],
email: 'a@gmail.com'
},
{
id: cuid(),
notificationCategorySubscriptions: ['ALL'],
email: 'b@gmail.com'
},
],
}
await testRule(data, Result.PASS)
})
})
})

0 comments on commit 286ea82

Please sign in to comment.