Skip to content

Commit 067bf70

Browse files
feat(CG-1311): add AWS security hub
1 parent 775786f commit 067bf70

File tree

13 files changed

+145
-0
lines changed

13 files changed

+145
-0
lines changed

src/enums/resources.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export default {
4444
dynamoDbTable: 'aws_dynamodb_table',
4545
kinesisStream: 'aws_kinesis_stream',
4646
securityGroup: 'aws_security_group',
47+
securityHub: 'aws_security_hub',
4748
iamRolePolicy: 'aws_iam_role_policy',
4849
efsMountTarget: 'aws_efs_mount_target',
4950
route53ZRecord: 'aws_route53_record',

src/enums/schemasMap.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export default {
7878
[services.nat]: 'awsNatGateway',
7979
[services.networkInterface]: 'awsNetworkInterface',
8080
[services.sg]: 'awsSecurityGroup',
81+
[services.securityHub]: 'awsSecurityHub',
8182
[services.subnet]: 'awsSubnet',
8283
[services.vpc]: 'awsVpc',
8384
[services.vpcEndpoint]: 'awsVpcEndpoint',

src/enums/serviceAliases.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export default {
6767
[services.sageMakerProject]: 'sageMakerProjects',
6868
[services.secretsManager]: 'secretsManager',
6969
[services.sg]: 'securityGroups',
70+
[services.securityHub]: 'securityHubs',
7071
[services.subnet]: 'subnets',
7172
[services.systemsManagerDocument]: 'systemsManagerDocuments',
7273
[services.systemsManagerInstance]: 'systemsManagerInstances',

src/enums/serviceMap.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import Route53HostedZone from '../services/route53HostedZone'
5353
import Route53Record from '../services/route53Record'
5454
import RouteTable from '../services/routeTable'
5555
import SecretsManager from '../services/secretsManager'
56+
import SecurityHub from '../services/securityHub'
5657
import S3 from '../services/s3'
5758
import SES from '../services/ses'
5859
import SQS from '../services/sqs'
@@ -182,6 +183,7 @@ export default {
182183
[services.sageMakerProject]: SageMakerProject,
183184
[services.s3]: S3,
184185
[services.secretsManager]: SecretsManager,
186+
[services.securityHub]: SecurityHub,
185187
[services.ses]: SES,
186188
[services.iamAccessAnalyzer]: IamAccessAnalyzer,
187189
[services.iamUser]: IamUser,

src/enums/services.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export default {
8484
sageMakerProject: 'sageMakerProject',
8585
s3: 's3',
8686
secretsManager: 'secretsManager',
87+
securityHub: 'securityHub',
8788
ses: 'ses',
8889
sg: 'sg',
8990
sns: 'sns',

src/properties/logger.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,4 +689,10 @@ export default {
689689
* Vpc Peering Connections
690690
*/
691691
fetchedVpcPeeringConnections: (num: number): string => `Found ${num} Vpc Peering Connections`,
692+
/**
693+
* Security Hub
694+
*/
695+
securityHubNotFound: (region: string): string => `Security Hub not found/disabled for region: ${region}`,
696+
fetchedSecurityHub: (region: string): string => `Security Hub found/enabled for region: ${region}`,
697+
fetchingSecurityHub: 'Fetching Security Hub data for this AWS account via the AWS SDK...',
692698
}

src/services/account/schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ type awsAccount implements awsOptionalService @key(fields: "id") {
8686
sageMakerProjects: [awsSageMakerProject]
8787
secretsManager: [awsSecretsManager]
8888
securityGroups: [awsSecurityGroup]
89+
securityHub: [awsSecurityHub]
8990
systemsManagerDocuments: [awsSystemsManagerDocument]
9091
systemsManagerInstances: [awsSystemsManagerInstance]
9192
ses: [awsSes]

src/services/securityHub/data.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import CloudGraph from '@cloudgraph/sdk'
2+
import SecurityHub, { DescribeHubResponse } from 'aws-sdk/clients/securityhub'
3+
import { AWSError } from 'aws-sdk/lib/error'
4+
import groupBy from 'lodash/groupBy'
5+
import isEmpty from 'lodash/isEmpty'
6+
import { Config } from 'aws-sdk/lib/config'
7+
import { initTestEndpoint } from '../../utils'
8+
import AwsErrorLog from '../../utils/errorLog'
9+
import awsLoggerText from '../../properties/logger'
10+
11+
const { logger } = CloudGraph
12+
const lt = { ...awsLoggerText }
13+
const serviceName = 'SecurityHub'
14+
const errorLog = new AwsErrorLog(serviceName)
15+
const endpoint = initTestEndpoint(serviceName)
16+
17+
export interface RawAwsSecurityHub {
18+
HubArn: string;
19+
SubscribedAt: string;
20+
AutoEnableControls?: boolean;
21+
region: string;
22+
}
23+
24+
export default async ({
25+
regions,
26+
config,
27+
}: {
28+
regions: string
29+
config: Config
30+
}): Promise<{ [property: string]: RawAwsSecurityHub[] }> =>
31+
new Promise(async resolve => {
32+
const hubData: RawAwsSecurityHub[] = []
33+
34+
const regionPromises = regions.split(',').map(region => {
35+
const securityHub = new SecurityHub({ ...config, region, endpoint })
36+
return new Promise<void>(resolveRegion =>
37+
securityHub.describeHub(
38+
{},
39+
(err: AWSError, data: DescribeHubResponse) => {
40+
if (err) {
41+
errorLog.generateAwsErrorLog({
42+
functionName: 'securityHub:describeHub',
43+
err,
44+
})
45+
}
46+
47+
if (isEmpty(data) || !data) {
48+
logger.debug(lt.securityHubNotFound(region))
49+
return resolveRegion()
50+
}
51+
52+
logger.debug(lt.fetchedSecurityHub(region))
53+
hubData.push({
54+
HubArn: data.HubArn,
55+
SubscribedAt: data.SubscribedAt,
56+
AutoEnableControls: data.AutoEnableControls,
57+
region,
58+
})
59+
resolveRegion()
60+
}
61+
)
62+
)
63+
})
64+
65+
logger.debug(lt.fetchingSecurityHub)
66+
await Promise.all(regionPromises)
67+
errorLog.reset()
68+
69+
resolve(groupBy(hubData, 'region'))
70+
})

src/services/securityHub/format.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { RawAwsSecurityHub } from './data'
2+
import {
3+
AwsSecurityHub
4+
} from '../../types/generated'
5+
6+
7+
/**
8+
* Security Hub
9+
*/
10+
11+
export default ({
12+
service,
13+
account,
14+
region,
15+
}: {
16+
service: RawAwsSecurityHub
17+
account: string
18+
region: string
19+
}): AwsSecurityHub => {
20+
const {
21+
HubArn: arn,
22+
SubscribedAt: subscribedAt,
23+
AutoEnableControls: autoEnableControls,
24+
} = service
25+
26+
return {
27+
id: arn,
28+
accountId: account,
29+
arn,
30+
region,
31+
subscribedAt,
32+
autoEnableControls,
33+
}
34+
}

src/services/securityHub/index.ts

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 SecurityHub extends BaseService implements Service {
8+
format = format.bind(this)
9+
10+
getData = getData.bind(this)
11+
12+
mutation = mutation
13+
}

0 commit comments

Comments
 (0)