Skip to content

Commit efaa940

Browse files
authored
Merge pull request #155 from cloudgraphdev/feat/EP-3207
feat: add securityHub missing services
2 parents c6de583 + 734d0c1 commit efaa940

File tree

17 files changed

+446
-126
lines changed

17 files changed

+446
-126
lines changed

README.md

Lines changed: 128 additions & 126 deletions
Large diffs are not rendered by default.

src/enums/serviceAliases.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ export default {
8585
[services.secretsManager]: 'secretsManager',
8686
[services.sg]: 'securityGroups',
8787
[services.securityHub]: 'securityHubs',
88+
[services.securityHubMember]: 'securityHubMembers',
89+
[services.securityHubStandardSubscription]:
90+
'securityHubStandardSubscriptions',
8891
[services.subnet]: 'subnets',
8992
[services.systemsManagerDocument]: 'systemsManagerDocuments',
9093
[services.systemsManagerInstance]: 'systemsManagerInstances',

src/enums/serviceMap.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ import SageMakerProject from '../services/sageMakerProject'
104104
import SecretsManager from '../services/secretsManager'
105105
import AwsSecurityGroup from '../services/securityGroup'
106106
import SecurityHub from '../services/securityHub'
107+
import SecurityHubMember from '../services/securityHubMember'
108+
import SecurityHubStandardSubscription from '../services/securityHubStandardSubscription'
107109
import SES from '../services/ses'
108110
import SESReceiptRuleSet from '../services/sesReceiptRuleSet'
109111
import SESEmail from '../services/sesEmail'
@@ -230,6 +232,8 @@ export default {
230232
[services.s3]: S3,
231233
[services.secretsManager]: SecretsManager,
232234
[services.securityHub]: SecurityHub,
235+
[services.securityHubMember]: SecurityHubMember,
236+
[services.securityHubStandardSubscription]: SecurityHubStandardSubscription,
233237
[services.ses]: SES,
234238
[services.sesReceiptRuleSet]: SESReceiptRuleSet,
235239
[services.sesEmail]: SESEmail,

src/enums/services.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ export default {
106106
s3: 's3',
107107
secretsManager: 'secretsManager',
108108
securityHub: 'securityHub',
109+
securityHubMember: 'securityHubMember',
110+
securityHubStandardSubscription: 'securityHubStandardSubscription',
109111
ses: 'ses',
110112
sesReceiptRuleSet: 'sesReceiptRuleSet',
111113
sesEmail: 'sesEmail',

src/properties/logger.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,10 @@ export default {
762762
`Security Hub found/enabled for region: ${region}`,
763763
fetchingSecurityHub:
764764
'Fetching Security Hub data for this AWS account via the AWS SDK...',
765+
fetchedSecurityHubMembers: (num: number): string =>
766+
`Found ${num} Security Hub Members`,
767+
fetchedSecurityHubStandardSubscriptions: (num: number): string =>
768+
`Found ${num} Security Hub Standard Subscription`,
765769
/**
766770
* Msk
767771
*/

src/services/account/schema.graphql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ type awsAccount implements awsOptionalService @key(fields: "id") {
104104
secretsManager: [awsSecretsManager]
105105
securityGroups: [awsSecurityGroup]
106106
securityHub: [awsSecurityHub]
107+
securityHubMember: [awsSecurityHubMember]
108+
securityHubStandardSubscription: [awsSecurityHubStandardSubscription]
107109
systemsManagerDocuments: [awsSystemsManagerDocument]
108110
systemsManagerInstances: [awsSystemsManagerInstance]
109111
systemsManagerParameters: [awsSystemsManagerParameter]
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import CloudGraph from '@cloudgraph/sdk'
2+
import SecurityHub, {
3+
ListMembersRequest,
4+
ListMembersResponse,
5+
Member,
6+
MemberList,
7+
} from 'aws-sdk/clients/securityhub'
8+
import { AWSError } from 'aws-sdk/lib/error'
9+
import groupBy from 'lodash/groupBy'
10+
import isEmpty from 'lodash/isEmpty'
11+
import { Config } from 'aws-sdk/lib/config'
12+
import { initTestEndpoint } from '../../utils'
13+
import AwsErrorLog from '../../utils/errorLog'
14+
import awsLoggerText from '../../properties/logger'
15+
16+
const { logger } = CloudGraph
17+
const lt = { ...awsLoggerText }
18+
const serviceName = 'SecurityHub Member'
19+
const errorLog = new AwsErrorLog(serviceName)
20+
const endpoint = initTestEndpoint(serviceName)
21+
22+
export interface RawAwsSecurityHubMember extends Member {
23+
region: string
24+
}
25+
26+
const getMembersForRegion = async ({
27+
securityHub,
28+
}: {
29+
securityHub: SecurityHub
30+
}): Promise<MemberList> =>
31+
new Promise<MemberList>(resolve => {
32+
const memberList: MemberList = []
33+
const listMemberOpts: ListMembersRequest = {}
34+
const listAllMembers = (token?: string): void => {
35+
if (token) {
36+
listMemberOpts.NextToken = token
37+
}
38+
try {
39+
securityHub.listMembers(
40+
listMemberOpts,
41+
(err: AWSError, data: ListMembersResponse) => {
42+
const { NextToken: nextToken, Members = [] } = data || {}
43+
if (err) {
44+
errorLog.generateAwsErrorLog({
45+
functionName: 'securityHub:listMembers',
46+
err,
47+
})
48+
}
49+
50+
memberList.push(...Members)
51+
52+
if (nextToken) {
53+
listAllMembers(nextToken)
54+
} else {
55+
resolve(memberList)
56+
}
57+
}
58+
)
59+
} catch (err) {
60+
resolve([])
61+
}
62+
}
63+
listAllMembers()
64+
})
65+
66+
export default async ({
67+
regions,
68+
config,
69+
}: {
70+
regions: string
71+
config: Config
72+
}): Promise<{ [property: string]: RawAwsSecurityHubMember[] }> =>
73+
new Promise(async resolve => {
74+
const memberData: RawAwsSecurityHubMember[] = []
75+
const regionPromises = []
76+
77+
regions.split(',').forEach(region => {
78+
const securityHub = new SecurityHub({ ...config, region, endpoint })
79+
80+
const regionPromise = new Promise<void>(async resolveRegion => {
81+
const members = await getMembersForRegion({ securityHub })
82+
if (!isEmpty(members)) {
83+
memberData.push(
84+
...members.map(member => ({
85+
...member,
86+
region,
87+
}))
88+
)
89+
}
90+
resolveRegion()
91+
})
92+
regionPromises.push(regionPromise)
93+
})
94+
95+
await Promise.all(regionPromises)
96+
logger.debug(lt.fetchedSecurityHubMembers(memberData.length))
97+
errorLog.reset()
98+
99+
resolve(groupBy(memberData, 'region'))
100+
})
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { RawAwsSecurityHubMember } from './data'
2+
import { AwsSecurityHubMember } from '../../types/generated'
3+
4+
/**
5+
* Security Hub Member
6+
*/
7+
8+
export default ({
9+
service,
10+
account,
11+
region,
12+
}: {
13+
service: RawAwsSecurityHubMember
14+
account: string
15+
region: string
16+
}): AwsSecurityHubMember => {
17+
const { AccountId: accountId } = service
18+
19+
return {
20+
id: accountId,
21+
accountId: account,
22+
arn: accountId,
23+
region,
24+
}
25+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Service } from '@cloudgraph/sdk'
2+
import BaseService from '../base'
3+
import format from './format'
4+
import getData from './data'
5+
import mutation from './mutation'
6+
7+
export default class SecurityHubMember extends BaseService implements Service {
8+
format = format.bind(this)
9+
10+
getData = getData.bind(this)
11+
12+
mutation = mutation
13+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default `mutation($input: [AddawsSecurityHubMemberInput!]!) {
2+
addawsSecurityHubMember(input: $input, upsert: true) {
3+
numUids
4+
}
5+
}`

0 commit comments

Comments
 (0)