Skip to content

Commit 592400d

Browse files
committed
Merge branch 'alpha' into feature/CG-1062
2 parents 1e3e66d + 2ee61ff commit 592400d

File tree

14 files changed

+396
-38
lines changed

14 files changed

+396
-38
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
# [0.79.0-alpha.4](https://github.com/cloudgraphdev/cloudgraph-provider-aws/compare/0.79.0-alpha.3...0.79.0-alpha.4) (2022-04-08)
2+
3+
4+
### Features
5+
6+
* Handle TODOs for dynamoDB ([d2b42ce](https://github.com/cloudgraphdev/cloudgraph-provider-aws/commit/d2b42cec491776ecebbedc30f691a49960cfd47e))
7+
* Handle TODOs for dynamoDB ([9b3ae42](https://github.com/cloudgraphdev/cloudgraph-provider-aws/commit/9b3ae425097f06972f292f3c82930bd7f97bb5ac))
8+
9+
# [0.79.0-alpha.3](https://github.com/cloudgraphdev/cloudgraph-provider-aws/compare/0.79.0-alpha.2...0.79.0-alpha.3) (2022-04-08)
10+
11+
12+
### Features
13+
14+
* **appSync:** add iamRole/wafV2WebAcl connections ([36b90f2](https://github.com/cloudgraphdev/cloudgraph-provider-aws/commit/36b90f256445568dd33d9f0fcbed8dc66531407a))
15+
116
# [0.79.0-alpha.2](https://github.com/cloudgraphdev/cloudgraph-provider-aws/compare/0.79.0-alpha.1...0.79.0-alpha.2) (2022-04-08)
217

318

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi
7171
| apiGatewayRestApi | apiGatewayResource, apiGatewayStage, route53Record |
7272
| apiGatewayStage | apiGatewayRestApi |
7373
| apiGatewayResource | apiGatewayRestApi |
74-
| appSync | cognitoUserPool, dynamodb, lambda, rdsCluster |
74+
| appSync | cognitoUserPool, dynamodb, iamRole, lambda, rdsCluster, wafV2WebAcl |
7575
| asg | ebs, ec2, securityGroup, subnet |
7676
| athenaDataCatalog | |
7777
| clientVpnEndpoint | securityGroup |
@@ -87,7 +87,7 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi
8787
| cognitoUserPool | appSync, lambda |
8888
| configurationRecorder | iamRole |
8989
| customerGateway | vpnConnection |
90-
| dynamodb | appSync |
90+
| dynamodb | appSync, iamRole, kms |
9191
| dmsReplicationInstance | securityGroup, subnet, vpc, kms |
9292
| ebs | asg, ec2, emrInstance |
9393
| ec2 | alb, asg, ebs, eip, emrInstance, eksCluster, elasticBeanstalkEnv, iamInstanceProfile, iamRole, networkInterface, securityGroup, subnet, systemsManagerInstance, vpc, ecsContainer |
@@ -122,7 +122,7 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi
122122
| iamServerCertificate | |
123123
| iamUser | iamGroup |
124124
| iamPolicy | iamRole, iamGroup |
125-
| iamRole | codebuild, configurationRecorder, ec2, iamInstanceProfile, iamPolicy, eksCluster, ecsService, flowLog, glueJob, managedAirflow, sageMakerNotebookInstance, systemsManagerInstance guardDutyDetector |
125+
| iamRole | appSync, codebuild, configurationRecorder, ec2, iamInstanceProfile, iamPolicy, eksCluster, ecsService, flowLog, glueJob, managedAirflow, sageMakerNotebookInstance, systemsManagerInstance guardDutyDetector |
126126
| iamGroup | iamUser, iamPolicy |
127127
| igw | vpc |
128128
| iot | |
@@ -159,5 +159,5 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi
159159
| vpc | alb, codebuild, dmsReplicationInstance, ec2, eip, elb, ecsService, efsMountTarget, eksCluster igw, elastiCacheCluster, elasticSearchDomain, lambda, nacl, natGateway, networkInterface, rdsClusterSnapshot, rdsDbInstance, redshiftCluster, route53HostedZone, routeTable, subnet, flowLog, vpnGateway, transitGatewayAttachment |
160160
| vpnConnection | customerGateway, transitGateway, transitGatewayAttachment, vpnGateway |
161161
| vpnGateway | vpc, vpnConnection |
162-
| wafV2WebAcl | |
162+
| wafV2WebAcl | appSync |
163163

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@cloudgraph/cg-provider-aws",
3-
"version": "0.79.0-alpha.2",
3+
"version": "0.79.0-alpha.4",
44
"description": "cloud-graph provider plugin for AWS used to fetch AWS cloud data.",
55
"publishConfig": {
66
"registry": "https://registry.npmjs.org/",

src/services/appSync/connections.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import { RawAwsDynamoDbTable } from '../dynamodb/data'
1010
import { RawAwsLambdaFunction } from '../lambda/data'
1111
import { RawAwsCognitoUserPool } from '../cognitoUserPool/data'
1212
import { RawAwsRdsCluster } from '../rdsCluster/data'
13+
import { RawAwsIamRole } from '../iamRole/data'
14+
import { globalRegionName } from '../../enums/regions'
15+
import { RawAwsWafV2WebAcl } from '../wafV2WebAcl/data'
1316

1417
/**
1518
* AppSync
@@ -27,7 +30,7 @@ export default ({
2730
region: string
2831
}): { [key: string]: ServiceConnection[] } => {
2932
const connections: ServiceConnection[] = []
30-
const { apiId: id, awsDataSources, userPoolConfig } = appSync
33+
const { apiId: id, awsDataSources, userPoolConfig, wafWebAclArn } = appSync
3134

3235
/**
3336
* Find cognito user pools
@@ -153,6 +156,60 @@ export default ({
153156
}
154157
}
155158

159+
/**
160+
* Find related IAM Roles
161+
*/
162+
const roles: { name: string; data: { [property: string]: any[] } } =
163+
data.find(({ name }) => name === services.iamRole)
164+
165+
const roleArns = awsDataSources?.map(
166+
({ serviceRoleArn }) => serviceRoleArn
167+
)
168+
169+
if (roles?.data?.[globalRegionName]) {
170+
const dataAtRegion: RawAwsIamRole[] = roles.data[globalRegionName].filter(
171+
role => roleArns.includes(role.Arn)
172+
)
173+
if (!isEmpty(dataAtRegion)) {
174+
for (const instance of dataAtRegion) {
175+
const { Arn: arn }: RawAwsIamRole = instance
176+
177+
connections.push({
178+
id: arn,
179+
resourceType: services.iamRole,
180+
relation: 'child',
181+
field: 'iamRoles',
182+
})
183+
}
184+
}
185+
}
186+
187+
/**
188+
* Find wafV2WebAcls
189+
*/
190+
const acls: {
191+
name: string
192+
data: { [property: string]: RawAwsWafV2WebAcl[] }
193+
} = data.find(({ name }) => name === services.wafV2WebAcl)
194+
195+
if (acls?.data) {
196+
const allAcls = Object.values(acls.data).flat()
197+
const dataInRegion: RawAwsWafV2WebAcl[] = allAcls.filter(
198+
({ ARN }: RawAwsWafV2WebAcl) => ARN === wafWebAclArn
199+
)
200+
201+
if (!isEmpty(dataInRegion)) {
202+
for (const acl of dataInRegion) {
203+
connections.push({
204+
id: acl.Id,
205+
resourceType: services.wafV2WebAcl,
206+
relation: 'child',
207+
field: 'webAcl',
208+
})
209+
}
210+
}
211+
}
212+
156213
const appSyncResult = {
157214
[id]: connections,
158215
}

src/services/appSync/schema.graphql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,7 @@ type awsAdditionalAuthenticationProvider
124124
userPoolAwsRegion: String @search(by: [hash, regexp])
125125
userPoolAppIdClientRegex: String @search(by: [hash, regexp])
126126
}
127-
# TODO: add iam role connection
128-
# TODO: waf web acl connection
129-
# TODO: add cloudwatchLog connection
127+
130128
type awsAppSync implements awsBaseService @key(fields: "arn") {
131129
name: String @search(by: [hash, regexp])
132130
authenticationType: String @search(by: [hash, regexp])
@@ -158,4 +156,6 @@ type awsAppSync implements awsBaseService @key(fields: "arn") {
158156
dynamodb: [awsDynamoDbTable] @hasInverse(field: appSync)
159157
lambda: [awsLambda] @hasInverse(field: appSync)
160158
rdsCluster: [awsRdsCluster] @hasInverse(field: appSync)
159+
iamRoles: [awsIamRole] @hasInverse(field: appSync)
160+
webAcl: [awsWafV2WebAcl] @hasInverse(field: appSync)
161161
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { ServiceConnection } from '@cloudgraph/sdk'
2+
import { isEmpty } from 'lodash'
3+
import services from '../../enums/services'
4+
import { RawAwsDynamoDbTable } from './data'
5+
import { AwsKms } from '../kms/data'
6+
import { RawAwsIamRole } from '../iamRole/data'
7+
import { globalRegionName } from '../../enums/regions'
8+
9+
/**
10+
* Dynamo DB
11+
*/
12+
13+
export default ({
14+
service: dynamoDbTable,
15+
data,
16+
region,
17+
}: {
18+
account: string
19+
data: { name: string; data: { [property: string]: any[] } }[]
20+
service: RawAwsDynamoDbTable
21+
region: string
22+
}): { [key: string]: ServiceConnection[] } => {
23+
const connections: ServiceConnection[] = []
24+
25+
const {
26+
TableId: id,
27+
SSEDescription: sseDescription,
28+
Replicas: replicas,
29+
} = dynamoDbTable
30+
31+
/**
32+
* Find KMS
33+
* related to this dynamo db table
34+
*/
35+
const kmsMasterKeyArn = sseDescription?.KMSMasterKeyArn
36+
const kms = data.find(({ name }) => name === services.kms)
37+
38+
if (kmsMasterKeyArn && kms?.data?.[region]) {
39+
const kmsInRegion: AwsKms = kms.data[region].find(
40+
({ Arn }: AwsKms) => kmsMasterKeyArn === Arn
41+
)
42+
43+
if (kmsInRegion) {
44+
connections.push({
45+
id: kmsInRegion.KeyId,
46+
resourceType: services.kms,
47+
relation: 'child',
48+
field: 'kms',
49+
})
50+
}
51+
}
52+
53+
/**
54+
* Find IAM Roles
55+
* related to this dynamo db table
56+
*/
57+
const roleArns: string[] = []
58+
replicas?.map(({ AutoScaling: autoScaling }) => {
59+
roleArns.push(
60+
autoScaling?.ReplicaProvisionedReadCapacityAutoScalingSettings
61+
?.AutoScalingRoleArn
62+
)
63+
roleArns.push(
64+
autoScaling?.ReplicaProvisionedWriteCapacityAutoScalingSettings
65+
?.AutoScalingRoleArn
66+
)
67+
})
68+
69+
const roles: { name: string; data: { [property: string]: any[] } } =
70+
data.find(({ name }) => name === services.iamRole)
71+
if (roles?.data?.[globalRegionName]) {
72+
const dataAtRegion: RawAwsIamRole[] = roles.data[globalRegionName].filter(
73+
({ Arn }: RawAwsIamRole) => roleArns?.includes(Arn)
74+
)
75+
if (!isEmpty(dataAtRegion)) {
76+
for (const iamRole of dataAtRegion) {
77+
const { Arn: arn }: RawAwsIamRole = iamRole
78+
79+
connections.push({
80+
id: arn,
81+
resourceType: services.iamRole,
82+
relation: 'child',
83+
field: 'iamRoles',
84+
})
85+
}
86+
}
87+
}
88+
89+
const dynamoDbResult = {
90+
[id]: connections,
91+
}
92+
return dynamoDbResult
93+
}

src/services/dynamodb/data.ts

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import DynamoDB, {
1313
TableNameList,
1414
ListTablesInput,
1515
ContinuousBackupsDescription,
16+
DescribeTableReplicaAutoScalingOutput,
17+
TableAutoScalingDescription,
18+
ReplicaAutoScalingDescription,
19+
ReplicaDescription,
1620
} from 'aws-sdk/clients/dynamodb'
1721
import { Config } from 'aws-sdk/lib/config'
1822
import { AWSError } from 'aws-sdk/lib/error'
@@ -31,11 +35,17 @@ const serviceName = 'DynamoDB'
3135
const errorLog = new AwsErrorLog(serviceName)
3236
const endpoint = initTestEndpoint(serviceName)
3337

34-
export interface RawAwsDynamoDbTable extends TableDescription {
38+
export interface RawAwsReplicaDescription extends ReplicaDescription {
39+
AutoScaling?: ReplicaAutoScalingDescription
40+
}
41+
42+
export interface RawAwsDynamoDbTable
43+
extends Omit<TableDescription, 'Replicas'> {
3544
region: string
3645
ttlEnabled?: boolean
3746
pointInTimeRecoveryEnabled?: boolean
3847
Tags?: TagMap
48+
Replicas?: RawAwsReplicaDescription[]
3949
}
4050

4151
const checkIfEnabled = (status: string): boolean =>
@@ -220,6 +230,30 @@ const getTableBackupsDescription = async (
220230
)
221231
})
222232

233+
const getTableReplicaAutoScaling = async (
234+
dynamoDb: DynamoDB,
235+
tableName: TableName
236+
): Promise<TableAutoScalingDescription> =>
237+
new Promise(resolve => {
238+
dynamoDb.describeTableReplicaAutoScaling(
239+
{
240+
TableName: tableName,
241+
},
242+
(err: AWSError, data: DescribeTableReplicaAutoScalingOutput) => {
243+
if (err) {
244+
errorLog.generateAwsErrorLog({
245+
functionName: 'dynamodb:describeTableReplicaAutoScaling',
246+
err,
247+
})
248+
}
249+
if (!isEmpty(data)) {
250+
resolve(data.TableAutoScalingDescription)
251+
}
252+
resolve({})
253+
}
254+
)
255+
})
256+
223257
export default async ({
224258
regions,
225259
config,
@@ -235,6 +269,7 @@ export default async ({
235269
const tagsPromises = []
236270
const ttlInfoPromises = []
237271
const backupInfoPromises = []
272+
const tableReplicaAutoScalingPromises = []
238273

239274
// First we get all table name for all regions
240275
regions.split(',').map(region => {
@@ -306,7 +341,7 @@ export default async ({
306341
logger.debug(lt.gettingTableTtlInfo)
307342
await Promise.all(ttlInfoPromises)
308343

309-
// Finally we get the backup information for each table
344+
// Get the backup information for each table
310345
tableData.map(({ TableName, region }, idx) => {
311346
const dynamoDb = new DynamoDB({ ...config, region, endpoint })
312347
const backupInfoPromise = new Promise<void>(async resolveBackupInfo => {
@@ -320,6 +355,36 @@ export default async ({
320355
})
321356
logger.debug(lt.gettingTableBackupInfo)
322357
await Promise.all(backupInfoPromises)
358+
359+
// Finally we get the auto scaling settings for each table
360+
tableData.map(({ TableName: tableName, region }, idx) => {
361+
const dynamoDb = new DynamoDB({ ...config, region, endpoint })
362+
const tableReplicaAutoScalingPromise = new Promise<void>(
363+
async resolveTableReplicaAutoScaling => {
364+
const globalSettings: TableAutoScalingDescription =
365+
await getTableReplicaAutoScaling(dynamoDb, tableName)
366+
tableData[idx].Replicas = tableData[idx].Replicas?.map(
367+
({ RegionName: regionName, ...rest }) => {
368+
const autoScaling: ReplicaAutoScalingDescription =
369+
globalSettings?.Replicas?.find(
370+
r => r.RegionName === regionName
371+
) || {}
372+
return {
373+
AutoScaling: autoScaling,
374+
RegionName: regionName,
375+
...rest,
376+
}
377+
}
378+
)
379+
resolveTableReplicaAutoScaling()
380+
}
381+
)
382+
tableReplicaAutoScalingPromises.push(tableReplicaAutoScalingPromise)
383+
})
384+
385+
logger.debug(lt.gettingTableBackupInfo)
386+
await Promise.all(tableReplicaAutoScalingPromises)
387+
323388
errorLog.reset()
324389

325390
resolve(groupBy(tableData, 'region'))

0 commit comments

Comments
 (0)