Skip to content

Commit 4ff22ec

Browse files
committed
feat: Added IamRole connection to ec2
1 parent 07652b8 commit 4ff22ec

8 files changed

Lines changed: 109 additions & 39 deletions

File tree

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi
9090
| dynamodb | appSync |
9191
| dmsReplicationInstance | securityGroup, subnet, vpc, kms |
9292
| ebs | asg, ec2, emrInstance |
93-
| ec2 | alb, asg, ebs, eip, emrInstance, networkInterface, securityGroup, subnet, systemsManagerInstance, vpc, ecsContainer |
93+
| ec2 | alb, asg, ebs, eip, emrInstance, eksCluster, elasticBeanstalkEnv, iamInstanceProfile, iamRole, networkInterface, securityGroup, subnet, systemsManagerInstance, vpc, ecsContainer |
9494
| ecr | |
9595
| ecsCluster | ecsService, ecsTask, ecsTaskSet |
9696
| ecsContainer | ecsTask, ec2 |
@@ -101,11 +101,11 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi
101101
| efs | kms |
102102
| efsMountTarget | networkInterface, subnet, vpc |
103103
| eip | ec2, networkInterface, vpc |
104-
| eksCluster | iamRole, kms, securityGroup, subnet, vpc |
104+
| eksCluster | ec2, iamRole, kms, securityGroup, subnet, vpc |
105105
| elastiCacheCluster | securityGroup, subnet, vpc |
106106
| elastiCacheReplicationGroup | kms |
107107
| elasticBeanstalkApp | elasticBeanstalkEnv |
108-
| elasticBeanstalkEnv | elasticBeanstalkApp |
108+
| elasticBeanstalkEnv | ec2, elasticBeanstalkApp |
109109
| elasticSearchDomain | kms, securityGroup, subnet, vpc |
110110
| elb | cloudfront, ecsService, securityGroup, subnet, vpc |
111111
| emrCluster | kms, subnet |
@@ -115,14 +115,14 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi
115115
| glueJob | iamRole |
116116
| glueRegistry | |
117117
| guardDutyDetector | iamRole |
118-
| iamInstanceProfile | iamRole |
118+
| iamInstanceProfile | ec2, iamRole |
119119
| iamPasswordPolicy | |
120120
| iamSamlProvider | |
121121
| iamOpenIdConnectProvider | |
122122
| iamServerCertificate | |
123123
| iamUser | iamGroup |
124124
| iamPolicy | iamRole, iamGroup |
125-
| iamRole | codebuild, configurationRecorder, iamInstanceProfile, iamPolicy, eksCluster, ecsService, flowLog, glueJob, managedAirflow, sageMakerNotebookInstance, systemsManagerInstance guardDutyDetector |
125+
| iamRole | codebuild, configurationRecorder, ec2, iamInstanceProfile, iamPolicy, eksCluster, ecsService, flowLog, glueJob, managedAirflow, sageMakerNotebookInstance, systemsManagerInstance guardDutyDetector |
126126
| iamGroup | iamUser, iamPolicy |
127127
| igw | vpc |
128128
| iot | |

src/enums/relations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export default {
88
route53HostedZone: ['route53Record'],
99
emrCluster: ['emrInstance', 'emrStep'],
1010
ecsService: ['ecsTaskSet', 'ecsTaskDefinition'],
11+
iamInstanceProfile: ['ec2Instance'],
1112
}

src/services/ec2/connections.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { RawAwsEksCluster } from '../eksCluster/data'
2121
import { getEksClusterName, getElasticBeanstalkEnvId } from './utils'
2222
import { RawAwsInstanceProfile } from '../iamInstanceProfile/data'
2323
import { globalRegionName } from '../../enums/regions'
24+
import { RawAwsIamRole } from '../iamRole/data'
2425

2526
/**
2627
* EC2
@@ -40,6 +41,7 @@ export default ({
4041
KeyPairName?: string
4142
Tags?: TagList
4243
IamInstanceProfile: IamInstanceProfile
44+
IamRolesArn?: string[]
4345
}
4446
region: string
4547
}): { [key: string]: ServiceConnection[] } => {
@@ -51,6 +53,7 @@ export default ({
5153
SubnetId: subnetId,
5254
Tags: tags,
5355
IamInstanceProfile: iamInstanceProfile,
56+
IamRolesArn: rolesArn,
5457
} = instance
5558

5659
/**
@@ -339,6 +342,31 @@ export default ({
339342
}
340343
}
341344

345+
/**
346+
* Find IAM Roles
347+
* related to this EC2 instance
348+
*/
349+
const roles: { name: string; data: { [property: string]: any[] } } =
350+
data.find(({ name }) => name === services.iamRole)
351+
352+
if (roles?.data?.[globalRegionName]) {
353+
const dataAtRegion: RawAwsIamRole[] = roles.data[globalRegionName].filter(
354+
({ Arn }: RawAwsIamRole) => rolesArn?.includes(Arn)
355+
)
356+
if (!isEmpty(dataAtRegion)) {
357+
for (const iamRole of dataAtRegion) {
358+
const { Arn: arn } :RawAwsIamRole = iamRole
359+
360+
connections.push({
361+
id: arn,
362+
resourceType: services.iamRole,
363+
relation: 'child',
364+
field: 'iamRole',
365+
})
366+
}
367+
}
368+
}
369+
342370
const ec2Result = {
343371
[id]: connections,
344372
}

src/services/ec2/data.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ import awsLoggerText from '../../properties/logger'
3131
import { initTestEndpoint } from '../../utils'
3232
import AwsErrorLog from '../../utils/errorLog'
3333
import { convertAwsTagsToTagMap } from '../../utils/format'
34+
import getIamInstanceProfiles, {
35+
RawAwsInstanceProfile,
36+
} from '../iamInstanceProfile/data'
3437

3538
const lt = { ...awsLoggerText }
3639
const { logger } = CloudGraph
@@ -54,6 +57,7 @@ export interface RawAwsEC2 extends Omit<Instance, 'Tags'> {
5457
IamInstanceProfile?: IamInstanceProfile
5558
cloudWatchMetricData?: any
5659
PlatformDetails?: string
60+
IamRolesArn?: string[]
5761
}
5862

5963
/**
@@ -63,9 +67,11 @@ export interface RawAwsEC2 extends Omit<Instance, 'Tags'> {
6367
export default async ({
6468
regions,
6569
config,
70+
rawData,
6671
}: {
6772
regions: string
6873
config: Config
74+
rawData: any
6975
}): Promise<{
7076
[region: string]: RawAwsEC2[]
7177
}> =>
@@ -625,6 +631,25 @@ export default async ({
625631
iamInstanceProfile[InstanceId] || {}
626632
})
627633

634+
// populate ec2Instances with the iamRoles Arn
635+
const iamInstancesProfiles: RawAwsInstanceProfile[] =
636+
Object.values(
637+
await getIamInstanceProfiles({
638+
config,
639+
rawData,
640+
})
641+
)?.reduce((acc, val) => acc.concat(val), []) || []
642+
643+
ec2Instances.map(({ IamInstanceProfile: instanceProfile }, ec2Idx) => {
644+
const instance = iamInstancesProfiles.find(
645+
i => i.Arn === instanceProfile?.Arn
646+
)
647+
if (instance) {
648+
ec2Instances[ec2Idx].IamRolesArn =
649+
instance?.Roles?.map(r => r.Arn) || []
650+
}
651+
})
652+
628653
errorLog.reset()
629654

630655
/**

src/services/ec2/schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,5 @@ type awsEc2 implements awsBaseService @key(fields: "arn") {
118118
eksCluster: [awsEksCluster] @hasInverse(field: ec2Instances)
119119
elasticBeanstalkEnv: [awsElasticBeanstalkEnv] @hasInverse(field: ec2Instances)
120120
iamInstanceProfile: [awsIamInstanceProfile] @hasInverse(field: ec2Instances)
121+
iamRole: [awsIamRole] @hasInverse(field: ec2Instances)
121122
}

src/services/iamInstanceProfile/data.ts

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import IAM, {
1010

1111
import { Config } from 'aws-sdk/lib/config'
1212
import { AWSError } from 'aws-sdk/lib/error'
13+
import { flatMap } from 'lodash'
1314
import { convertAwsTagsToTagMap } from '../../utils/format'
1415
import { AwsTag, TagMap } from '../../types'
1516

1617
import awsLoggerText from '../../properties/logger'
1718
import { initTestEndpoint, setAwsRetryOptions } from '../../utils'
1819
import AwsErrorLog from '../../utils/errorLog'
1920
import { globalRegionName } from '../../enums/regions'
21+
import services from '../../enums/services'
2022

2123
import {
2224
IAM_CUSTOM_DELAY,
@@ -111,49 +113,60 @@ export interface RawAwsInstanceProfile extends Omit<InstanceProfile, 'Tags'> {
111113

112114
export default async ({
113115
config,
116+
rawData,
114117
}: {
115-
regions: string
116118
config: Config
119+
rawData: any
117120
}): Promise<{
118121
[region: string]: RawAwsInstanceProfile[]
119122
}> =>
120123
new Promise(async resolve => {
121-
const instancesProfilesResult: RawAwsInstanceProfile[] = []
124+
let instancesProfilesResult: RawAwsInstanceProfile[] = []
122125
const tagsPromises = []
123126

124-
const client = new IAM({
125-
...config,
126-
region: globalRegionName,
127-
endpoint,
128-
...customRetrySettings,
129-
})
130-
131-
const instancesProfiles = await listInstancesProfiles(client)
132-
133-
if (!isEmpty(instancesProfiles)) {
134-
instancesProfiles.map(
135-
({ Tags, InstanceProfileName, ...instancesProfile }, idx) => {
136-
instancesProfilesResult.push({
137-
InstanceProfileName,
138-
...instancesProfile,
139-
region: globalRegionName,
140-
})
141-
142-
const tagsPromise = new Promise<void>(async resolveTags => {
143-
instancesProfilesResult[idx].Tags = await getTags({
144-
iam: client,
145-
name: InstanceProfileName,
127+
const existingData: RawAwsInstanceProfile[] =
128+
flatMap(
129+
rawData.find(({ name }) => name === services.iamInstanceProfile)?.data
130+
) || []
131+
132+
if (isEmpty(existingData)) {
133+
const client = new IAM({
134+
...config,
135+
region: globalRegionName,
136+
endpoint,
137+
...customRetrySettings,
138+
})
139+
140+
const instancesProfiles = await listInstancesProfiles(client)
141+
142+
if (!isEmpty(instancesProfiles)) {
143+
instancesProfiles.map(
144+
({ Tags, InstanceProfileName, ...instancesProfile }, idx) => {
145+
instancesProfilesResult.push({
146+
InstanceProfileName,
147+
...instancesProfile,
148+
region: globalRegionName,
146149
})
147-
resolveTags()
148-
})
149-
tagsPromises.push(tagsPromise)
150-
}
151-
)
152-
}
153150

154-
logger.debug(lt.foundInstanceProfiles(instancesProfiles.length))
155-
await Promise.all(tagsPromises)
156-
errorLog.reset()
151+
const tagsPromise = new Promise<void>(async resolveTags => {
152+
instancesProfilesResult[idx].Tags = await getTags({
153+
iam: client,
154+
name: InstanceProfileName,
155+
})
156+
resolveTags()
157+
})
158+
tagsPromises.push(tagsPromise)
159+
}
160+
)
161+
}
162+
163+
logger.debug(lt.foundInstanceProfiles(instancesProfiles.length))
164+
await Promise.all(tagsPromises)
165+
errorLog.reset()
166+
} else {
167+
// Uses existing data
168+
instancesProfilesResult = existingData
169+
}
157170

158171
resolve(groupBy(instancesProfilesResult, 'region'))
159172
})

src/services/iamRole/schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ type awsIamRole implements awsBaseService @key(fields: "id") {
2222
systemsManagerInstances: [awsSystemsManagerInstance]
2323
@hasInverse(field: iamRole)
2424
iamInstanceProfiles: [awsIamInstanceProfile] @hasInverse(field: iamRole)
25+
ec2Instances: [awsEc2] @hasInverse(field: iamRole)
2526
}

src/types/generated.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1441,7 +1441,7 @@ export type AwsEc2 = AwsBaseService & {
14411441
ephemeralBlockDevices?: Maybe<Array<Maybe<AwsEc2Blockdevice>>>;
14421442
hibernation?: Maybe<Scalars['String']>;
14431443
iamInstanceProfile?: Maybe<Array<Maybe<AwsIamInstanceProfile>>>;
1444-
id: Scalars['String'];
1444+
iamRole?: Maybe<Array<Maybe<AwsIamRole>>>;
14451445
instanceLifecycle?: Maybe<Scalars['String']>;
14461446
instanceState?: Maybe<Scalars['String']>;
14471447
instanceType?: Maybe<Scalars['String']>;
@@ -3020,6 +3020,7 @@ export type AwsIamRole = AwsBaseService & {
30203020
configurationRecorder?: Maybe<Array<Maybe<AwsConfigurationRecorder>>>;
30213021
createdAt?: Maybe<Scalars['String']>;
30223022
description?: Maybe<Scalars['String']>;
3023+
ec2Instances?: Maybe<Array<Maybe<AwsEc2>>>;
30233024
ecsService?: Maybe<Array<Maybe<AwsEcsService>>>;
30243025
eksCluster?: Maybe<Array<Maybe<AwsEksCluster>>>;
30253026
flowLogs?: Maybe<Array<Maybe<AwsFlowLog>>>;

0 commit comments

Comments
 (0)