Skip to content

Commit 68442ae

Browse files
committed
Merge branch 'feature/CG-822' into 'master'
feat(services): add new service guardDutyDetector Closes CG-822 See merge request auto-cloud/cloudgraph/provider/cloudgraph-provider-aws!212
2 parents f0d1b64 + 4a147bf commit 68442ae

14 files changed

Lines changed: 460 additions & 143 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,14 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi
112112
| flowLog | vpc, iamRole, subnet, networkInterface |
113113
| glueJob | iamRole |
114114
| glueRegistry | |
115+
| guardDutyDetector | iamRole |
115116
| iamPasswordPolicy | |
116117
| iamSamlProvider | |
117118
| iamOpenIdConnectProvider | |
118119
| iamServerCertificate | |
119120
| iamUser | iamGroup |
120121
| iamPolicy | iamRole, iamGroup |
121-
| iamRole | codebuild, configurationRecorder, iamPolicy, eksCluster, ecsService, flowLog, glueJob, managedAirflow |
122+
| iamRole | codebuild, configurationRecorder, iamPolicy, eksCluster, ecsService, flowLog, glueJob, managedAirflow, guardDutyDetector |
122123
| iamGroup | iamUser, iamPolicy |
123124
| igw | vpc |
124125
| iot | |

src/enums/schemasMap.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export default {
4747
[services.flowLog]: 'awsFlowLog',
4848
[services.glueJob]: 'awsGlueJob',
4949
[services.glueRegistry]: 'awsGlueRegistry',
50+
[services.guardDutyDetector]: 'awsGuardDutyDetector',
5051
[services.emrCluster]: 'awsEmrCluster',
5152
[services.emrInstance]: 'awsEmrInstance',
5253
[services.emrStep]: 'awsEmrStep',

src/enums/serviceMap.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ import SageMakerProject from '../services/sageMakerProject'
8686
import SageMakerExperiment from '../services/sageMakerExperiment'
8787
import ManagedAirflow from '../services/managedAirflow'
8888
import WafV2WebAcl from '../services/wafV2WebAcl'
89+
import GuardDutyDetector from '../services/guardDutyDetector'
8990

9091
/**
9192
* serviceMap is an object that contains all currently supported services for AWS
@@ -126,6 +127,7 @@ export default {
126127
[services.elb]: ELB,
127128
[services.flowLog]: FlowLog,
128129
[services.glueJob]: GlueJob,
130+
[services.guardDutyDetector]: GuardDutyDetector,
129131
[services.glueRegistry]: GlueRegistry,
130132
[services.emrCluster]: EmrCluster,
131133
[services.emrInstance]: EmrInstance,

src/enums/services.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export default {
4242
flowLog: 'flowLog',
4343
glueJob: 'glueJob',
4444
glueRegistry: 'glueRegistry',
45+
guardDutyDetector: 'guardDutyDetector',
4546
emrCluster: 'emrCluster',
4647
emrInstance: 'emrInstance',
4748
emrStep: 'emrStep',
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { Config } from 'aws-sdk/lib/config'
2+
import GUARDDUTY from 'aws-sdk/clients/guardduty'
3+
import isEmpty from 'lodash/isEmpty'
4+
import groupBy from 'lodash/groupBy'
5+
import { convertToPromise, fetchAllPaginatedData } from '../../utils/fetchUtils'
6+
import { initTestEndpoint } from '../../utils'
7+
import ErrorLog from '../../utils/errorLog'
8+
9+
const serviceName = 'guardDuty'
10+
const errorLog = new ErrorLog(serviceName)
11+
const endpoint = initTestEndpoint(serviceName)
12+
13+
export interface RawAwsGuardDutyDetector extends GUARDDUTY.GetDetectorResponse {
14+
id: string
15+
region: string
16+
members: GUARDDUTY.Members
17+
}
18+
19+
/**
20+
* GuardDutyDetector
21+
*/
22+
23+
export default async ({
24+
regions,
25+
config,
26+
}: {
27+
regions: string
28+
config: Config
29+
}): Promise<{ [region: string]: RawAwsGuardDutyDetector[] }> => {
30+
const result: RawAwsGuardDutyDetector[] = []
31+
32+
const activeRegions = regions.split(',')
33+
34+
for (const region of activeRegions) {
35+
let guardDutyDetectorList: GUARDDUTY.DetectorId[]
36+
const client = new GUARDDUTY({ ...config, region, endpoint })
37+
try {
38+
guardDutyDetectorList = await fetchAllPaginatedData({
39+
getResourcesFn: convertToPromise({
40+
sdkContext: client,
41+
fnName: 'listDetectors',
42+
}),
43+
accessor: '',
44+
})
45+
} catch (err) {
46+
errorLog.generateAwsErrorLog({ functionName: 'listDetectors', err })
47+
}
48+
49+
if (!isEmpty(guardDutyDetectorList)) {
50+
for (const detector of guardDutyDetectorList) {
51+
let detectorData: GUARDDUTY.GetDetectorResponse
52+
let members: GUARDDUTY.Members
53+
try {
54+
detectorData = await client
55+
.getDetector({ DetectorId: detector })
56+
.promise()
57+
members = await fetchAllPaginatedData({
58+
getResourcesFn: convertToPromise({
59+
sdkContext: client,
60+
fnName: 'listMembers',
61+
}),
62+
accessor: '',
63+
initialParams: {
64+
DetectorId: detector,
65+
},
66+
})
67+
} catch (err) {
68+
errorLog.generateAwsErrorLog({ functionName: 'getDetector', err })
69+
}
70+
result.push({
71+
id: detector,
72+
...detectorData,
73+
members,
74+
region,
75+
})
76+
}
77+
}
78+
}
79+
80+
errorLog.reset()
81+
return groupBy(result, 'region')
82+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import cuid from 'cuid'
2+
import { formatTagsFromMap } from '../../utils/format'
3+
import { AwsGuardDutyDetector } from '../../types/generated'
4+
import { RawAwsGuardDutyDetector } from './data'
5+
6+
/**
7+
* GuardDutyDetector
8+
*/
9+
10+
export default ({
11+
account,
12+
service: rawData,
13+
region,
14+
}: {
15+
account: string
16+
service: RawAwsGuardDutyDetector
17+
region: string
18+
}): AwsGuardDutyDetector => {
19+
const {
20+
id,
21+
CreatedAt: createdAt,
22+
FindingPublishingFrequency: findingPublishingFrequency,
23+
ServiceRole: serviceRole,
24+
Status: status,
25+
UpdatedAt: updatedAt,
26+
DataSources: dataSources,
27+
members = [],
28+
Tags
29+
} = rawData
30+
31+
const formattedDataSources = {
32+
cloudTrail: {
33+
status: dataSources?.CloudTrail?.Status
34+
},
35+
dnsLogs: {
36+
status: dataSources?.DNSLogs?.Status
37+
},
38+
flowLogs: {
39+
status: dataSources?.FlowLogs?.Status
40+
},
41+
s3Logs: {
42+
status: dataSources?.S3Logs?.Status
43+
},
44+
// kubernetes: { TODO: k8s logs support, maybe need to update aws sdk?
45+
// auditLogs: {
46+
// status: dataSources?.
47+
// }
48+
// }
49+
}
50+
51+
const mappedMembers = members?.map(member => ({
52+
id: cuid(),
53+
accountId: member?.AccountId,
54+
detectorId: member?.DetectorId,
55+
masterId: member?.MasterId,
56+
email: member?.Email,
57+
relationshipStatus: member?.RelationshipStatus,
58+
invitedAt: new Date(member?.InvitedAt)?.toISOString(),
59+
updatedAt: new Date(member?.UpdatedAt)?.toISOString()
60+
}))
61+
62+
return {
63+
id,
64+
region,
65+
accountId: account,
66+
createdAt: new Date(createdAt)?.toISOString(),
67+
updatedAt: new Date(updatedAt)?.toISOString(),
68+
findingPublishingFrequency,
69+
serviceRole,
70+
status,
71+
members: mappedMembers,
72+
dataSources: formattedDataSources,
73+
tags: formatTagsFromMap(Tags ?? {})
74+
}
75+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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 GuardDutyDetector extends BaseService implements Service {
8+
format = format.bind(this)
9+
10+
getData = getData.bind(this)
11+
12+
mutation = mutation
13+
}
14+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default `mutation($input: [AddawsGuardDutyDetectorInput!]!) {
2+
addawsGuardDutyDetector(input: $input, upsert: true) {
3+
numUids
4+
}
5+
}`;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
type awsGuardDutyDetector @key(fields: "id") {
2+
id: String! @id @search(by: [hash])
3+
accountId: String! @search(by: [hash])
4+
region: String @search(by: [hash, regexp])
5+
createdAt: DateTime
6+
updatedAt: DateTime
7+
findingPublishingFrequency: String @search(by: [hash, regexp])
8+
serviceRole: String @search(by: [hash, regexp])
9+
status: String @search(by: [hash, regexp])
10+
members: [awsGuardDutyMember]
11+
dataSources: awsGuardDutyDataSources
12+
tags: [awsRawTag]
13+
iamRole: awsIamRole @hasInverse(field: guardDutyDetectors)
14+
}
15+
16+
type awsGuardDutyMember {
17+
id: String! @id @search(by: [hash])
18+
accountId: String! @search(by: [hash])
19+
detectorId: String @search(by: [hash, regexp])
20+
masterId: String @search(by: [hash, regexp])
21+
email: String @search(by: [hash, regexp])
22+
relationshipStatus: String @search(by: [hash, regexp])
23+
invitedAt: DateTime
24+
updatedAt: DateTime
25+
}
26+
27+
type awsGuardDutyDataSources {
28+
cloudTrail: awsGuardDutyDataSource
29+
dnsLogs: awsGuardDutyDataSource
30+
flowLogs: awsGuardDutyDataSource
31+
s3Logs: awsGuardDutyDataSource
32+
}
33+
34+
type awsGuardDutyDataSource {
35+
status: String @search(by: [hash, regexp])
36+
}

0 commit comments

Comments
 (0)