Skip to content

Commit 3a713f6

Browse files
committed
fix(iamRole): added iamBoundaryPermissionPolicy relation and inline policies json documents
1 parent 0895b29 commit 3a713f6

6 files changed

Lines changed: 99 additions & 9 deletions

File tree

src/services/iamPolicy/schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type awsIamPolicy implements awsBaseService @key(fields: "id") {
88
iamRoles: [awsIamRole] @hasInverse(field: iamAttachedPolicies)
99
iamGroups: [awsIamGroup] @hasInverse(field: iamAttachedPolicies)
1010
iamUsers: [awsIamUser] @hasInverse(field: iamAttachedPolicies)
11+
permissionboundaryOf: [awsIamRole] @hasInverse(field: iamPermissionBoundaryPolicy)
1112
}
1213

1314
type awsIamJSONPolicy

src/services/iamRole/connections.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,35 @@ export default ({
3434
region: string
3535
}): { [key: string]: ServiceConnection[] } => {
3636
const connections: ServiceConnection[] = []
37-
const { Arn: id, ManagedPolicies: managedPolicies } = role
37+
const {
38+
Arn: id,
39+
ManagedPolicies: managedPolicies,
40+
PermissionsBoundaryArn,
41+
} = role
3842

3943
const policies: RawAwsIamPolicy[] =
4044
flatMap(
4145
data.find(({ name: serviceName }) => serviceName === services.iamPolicy)
4246
?.data
4347
) || []
4448

49+
/** Find Permission Boundary Policy
50+
* related to this IAM Role
51+
*/
52+
53+
const permissionBoundaryPolicy = policies.find(
54+
({ Arn: arn }: RawAwsIamPolicy) => PermissionsBoundaryArn === arn
55+
)
56+
57+
if (permissionBoundaryPolicy) {
58+
connections.push({
59+
id: PermissionsBoundaryArn,
60+
resourceType: services.iamPolicy,
61+
relation: 'child',
62+
field: 'iamPermissionBoundaryPolicy',
63+
})
64+
}
65+
4566
/**
4667
* Find Managed Policies
4768
* related to this IAM Role

src/services/iamRole/data.ts

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ import { AWSError } from 'aws-sdk/lib/error'
66

77
import IAM, {
88
AttachedPolicy,
9+
GetAccountAuthorizationDetailsResponse,
910
GetRoleResponse,
1011
ListAttachedRolePoliciesResponse,
1112
ListRolePoliciesResponse,
1213
ListRolesResponse,
1314
ListRoleTagsResponse,
1415
Role,
16+
RoleDetail,
1517
} from 'aws-sdk/clients/iam'
1618
import { Config } from 'aws-sdk/lib/config'
1719

@@ -38,10 +40,12 @@ const customRetrySettings = setAwsRetryOptions({
3840
})
3941

4042
export interface RawAwsIamRole extends Omit<Role, 'Tags'> {
41-
Policies: string[]
4243
ManagedPolicies: AttachedPolicy[]
4344
region: string
4445
Tags?: TagMap
46+
PermissionsBoundaryArn: string
47+
InlinePoliciesName: string[]
48+
InlinePoliciesDocuments: string[]
4549
}
4650

4751
const roleByRoleName = async (
@@ -154,10 +158,42 @@ const managedPoliciesByRoleName = async (
154158
)
155159
})
156160

157-
export const listIamRoles = async (
161+
export const getAccountAuthorizationDetails = async (
158162
iam: IAM,
159163
marker?: string
160-
): Promise<RawAwsIamRole[]> =>
164+
): Promise<RoleDetail[]> =>
165+
new Promise(resolve => {
166+
const result: RoleDetail[] = []
167+
iam.getAccountAuthorizationDetails(
168+
{ Filter: ['Role'], Marker: marker },
169+
async (err: AWSError, data: GetAccountAuthorizationDetailsResponse) => {
170+
if (err) {
171+
errorLog.generateAwsErrorLog({
172+
functionName: 'iam:getAccountAuthorizationDetails',
173+
err,
174+
})
175+
}
176+
if (!isEmpty(data) && !isEmpty(data.RoleDetailList)) {
177+
const { Marker, IsTruncated, RoleDetailList } = data
178+
result.push(...RoleDetailList)
179+
if (IsTruncated) {
180+
result.push(...(await getAccountAuthorizationDetails(iam, Marker)))
181+
}
182+
resolve(result)
183+
}
184+
}
185+
)
186+
})
187+
188+
export const listIamRoles = async ({
189+
iam,
190+
marker,
191+
roleAuthorizationDetails,
192+
}: {
193+
iam: IAM
194+
marker?: string
195+
roleAuthorizationDetails: RoleDetail[]
196+
}): Promise<RawAwsIamRole[]> =>
161197
new Promise(resolve => {
162198
const result: RawAwsIamRole[] = []
163199
const policiesByRoleNamePromises = []
@@ -196,7 +232,13 @@ export const listIamRoles = async (
196232

197233
result.push(
198234
...roles.map(
199-
({ RoleName, AssumeRolePolicyDocument, Tags, ...role }) => {
235+
({
236+
RoleName,
237+
AssumeRolePolicyDocument,
238+
PermissionsBoundary,
239+
Tags,
240+
...role
241+
}) => {
200242
return {
201243
RoleName,
202244
AssumeRolePolicyDocument: decodeURIComponent(
@@ -207,7 +249,7 @@ export const listIamRoles = async (
207249
RoleLastUsed: detailedRoles?.find(
208250
r => r?.RoleName === RoleName
209251
)?.Role.RoleLastUsed,
210-
Policies:
252+
InlinePoliciesName:
211253
policies
212254
?.filter(p => p?.RoleName === RoleName)
213255
.map(p => p.Policies)
@@ -218,13 +260,24 @@ export const listIamRoles = async (
218260
.map(p => p.ManagedPolicies)
219261
.reduce((current, acc) => [...acc, ...current], []) || [],
220262
Tags: tags.find(t => t?.RoleName === RoleName)?.Tags || {},
263+
PermissionsBoundaryArn:
264+
PermissionsBoundary.PermissionsBoundaryArn,
265+
InlinePoliciesDocuments: roleAuthorizationDetails
266+
.find(rAD => rAD.RoleName === RoleName)
267+
.RolePolicyList.map(rPl => rPl.PolicyDocument),
221268
}
222269
}
223270
)
224271
)
225272

226273
if (IsTruncated) {
227-
result.push(...(await listIamRoles(iam, Marker)))
274+
result.push(
275+
...(await listIamRoles({
276+
iam,
277+
marker: Marker,
278+
roleAuthorizationDetails,
279+
}))
280+
)
228281
}
229282

230283
resolve(result)
@@ -259,8 +312,12 @@ export default async ({
259312

260313
logger.debug(lt.lookingForIamRoles)
261314

315+
// Fetch role authorization details first
316+
const roleAuthorizationDetails = await getAccountAuthorizationDetails(
317+
client
318+
)
262319
// Fetch IAM Roles
263-
rolesData = await listIamRoles(client)
320+
rolesData = await listIamRoles({ iam: client, roleAuthorizationDetails })
264321

265322
errorLog.reset()
266323
logger.debug(lt.foundRoles(rolesData.length))

src/services/iamRole/format.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ export default ({
2424
RoleLastUsed,
2525
AssumeRolePolicyDocument: assumeRolePolicy = '',
2626
MaxSessionDuration: maxSessionDuration = 0,
27-
Policies: inlinePolicies = [],
27+
InlinePoliciesName: inlinePolicies = [],
28+
InlinePoliciesDocuments: inlineFormattedPolicies,
2829
Tags: tags = {},
2930
} = rawData
3031

@@ -44,6 +45,9 @@ export default ({
4445
assumeRolePolicy: formatIamJsonPolicy(assumeRolePolicy),
4546
maxSessionDuration,
4647
inlinePolicies,
48+
inlineFormattedPolicies: inlineFormattedPolicies.map(p =>
49+
formatIamJsonPolicy(p)
50+
),
4751
tags: roleTags,
4852
}
4953
return role

src/services/iamRole/schema.graphql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ type awsIamRole implements awsBaseService @key(fields: "id") {
99
maxSessionDuration: Int @search
1010
tags: [awsRawTag]
1111
inlinePolicies: [String]
12+
rawInlinePolicies: [String] @search(by: [hash, regexp])
13+
inlineFormattedPolicies: [awsIamJSONPolicy]
1214
cloudFormationStack: [awsCloudFormationStack] @hasInverse(field: iamRole)
1315
codebuilds: [awsCodebuild] @hasInverse(field: iamRoles)
1416
configurationRecorder: [awsConfigurationRecorder] @hasInverse(field: iamRole)
@@ -20,6 +22,7 @@ type awsIamRole implements awsBaseService @key(fields: "id") {
2022
glueJobs: [awsGlueJob] @hasInverse(field: iamRole)
2123
guardDutyDetectors: [awsGuardDutyDetector] @hasInverse(field: iamRole)
2224
iamAttachedPolicies: [awsIamPolicy] @hasInverse(field: iamRoles)
25+
iamPermissionBoundaryPolicy: [awsIamPolicy] @hasInverse(field: permissionboundaryOf)
2326
iamInstanceProfiles: [awsIamInstanceProfile] @hasInverse(field: iamRole)
2427
managedAirflows: [awsManagedAirflow] @hasInverse(field: iamRoles)
2528
sageMakerNotebookInstances: [awsSageMakerNotebookInstance]

src/types/generated.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3150,6 +3150,7 @@ export type AwsIamPolicy = AwsBaseService & {
31503150
iamUsers?: Maybe<Array<Maybe<AwsIamUser>>>;
31513151
name?: Maybe<Scalars['String']>;
31523152
path?: Maybe<Scalars['String']>;
3153+
permissionboundaryOf?: Maybe<Array<Maybe<AwsIamRole>>>;
31533154
policyContent?: Maybe<AwsIamJsonPolicy>;
31543155
rawPolicy?: Maybe<Scalars['String']>;
31553156
tags?: Maybe<Array<Maybe<AwsRawTag>>>;
@@ -3182,6 +3183,8 @@ export type AwsIamRole = AwsBaseService & {
31823183
guardDutyDetectors?: Maybe<Array<Maybe<AwsGuardDutyDetector>>>;
31833184
iamAttachedPolicies?: Maybe<Array<Maybe<AwsIamPolicy>>>;
31843185
iamInstanceProfiles?: Maybe<Array<Maybe<AwsIamInstanceProfile>>>;
3186+
iamPermissionBoundaryPolicy?: Maybe<Array<Maybe<AwsIamPolicy>>>;
3187+
inlineFormattedPolicies?: Maybe<Array<Maybe<AwsIamJsonPolicy>>>;
31853188
inlinePolicies?: Maybe<Array<Maybe<Scalars['String']>>>;
31863189
kinesisFirehose?: Maybe<Array<Maybe<AwsKinesisFirehose>>>;
31873190
lambda?: Maybe<Array<Maybe<AwsLambda>>>;
@@ -3190,6 +3193,7 @@ export type AwsIamRole = AwsBaseService & {
31903193
maxSessionDuration?: Maybe<Scalars['Int']>;
31913194
name?: Maybe<Scalars['String']>;
31923195
path?: Maybe<Scalars['String']>;
3196+
rawInlinePolicies?: Maybe<Array<Maybe<Scalars['String']>>>;
31933197
rawPolicy?: Maybe<Scalars['String']>;
31943198
rdsCluster?: Maybe<Array<Maybe<AwsRdsCluster>>>;
31953199
rdsDbInstance?: Maybe<Array<Maybe<AwsRdsDbInstance>>>;

0 commit comments

Comments
 (0)