Skip to content

Commit ac96bc4

Browse files
committed
Merge branch 'fix/CG-910' into 'master'
fix: CG-910 Add virtualMFADevices to iamPolicies needed for aws cis 1.14 Closes CG-910 See merge request auto-cloud/cloudgraph/provider/cloudgraph-provider-aws!220
2 parents f6dd1e9 + 05be9df commit ac96bc4

4 files changed

Lines changed: 70 additions & 1 deletion

File tree

src/services/iamUser/data.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ import IAM, {
1717
ListUserPoliciesResponse,
1818
ListUsersResponse,
1919
ListUserTagsResponse,
20+
ListVirtualMFADevicesRequest,
21+
ListVirtualMFADevicesResponse,
2022
MFADevice,
2123
User,
24+
VirtualMFADevice,
2225
} from 'aws-sdk/clients/iam'
2326
import { Config } from 'aws-sdk/lib/config'
2427

@@ -75,6 +78,7 @@ export interface RawAwsIamUserReport {
7578
export interface RawAwsIamUser extends Omit<User, 'Tags'> {
7679
AccessKeyLastUsedData: RawAwsAccessKey[]
7780
MFADevices: MFADevice[]
81+
VirtualMFADevices?: VirtualMFADevice[]
7882
Groups: string[]
7983
Policies: string[]
8084
ManagedPolicies: AttachedPolicy[]
@@ -286,6 +290,45 @@ export const listMFADevicesByUsername = async (
286290
)
287291
})
288292

293+
export const listVirtualMFADevices = async (
294+
iam: IAM
295+
): Promise<VirtualMFADevice[]> =>
296+
new Promise(resolve => {
297+
const virtualMFADeviceList: VirtualMFADevice[] = []
298+
let args: ListVirtualMFADevicesRequest = {}
299+
const listAllVirtualMFADevices = (marker?: string) => {
300+
if (marker) {
301+
args = { ...args, Marker: marker }
302+
}
303+
try {
304+
iam.listVirtualMFADevices(
305+
args,
306+
async (err: AWSError, data: ListVirtualMFADevicesResponse) => {
307+
if (err) {
308+
errorLog.generateAwsErrorLog({
309+
functionName: 'iam:listVirtualMFADevices',
310+
err,
311+
})
312+
}
313+
314+
const { VirtualMFADevices = [], IsTruncated, Marker } = data
315+
316+
virtualMFADeviceList.push(...VirtualMFADevices)
317+
318+
if (IsTruncated) {
319+
listAllVirtualMFADevices(Marker)
320+
}
321+
322+
resolve(virtualMFADeviceList)
323+
}
324+
)
325+
} catch (error) {
326+
resolve([])
327+
}
328+
}
329+
listAllVirtualMFADevices()
330+
})
331+
289332
export const listIamUsers = async (
290333
iam: IAM,
291334
marker?: string
@@ -446,6 +489,9 @@ export default async ({
446489
// Fetch IAM Report Credential
447490
const credentialReport = await getCredentialReportData(client)
448491

492+
// Fetch all virtual MFA Devices
493+
const virtualMFADevices = await listVirtualMFADevices(client)
494+
449495
usersData = credentialReport
450496
.map(userReport => {
451497
const user = iamUsers.find(u => u.Arn === userReport.Arn)
@@ -459,6 +505,9 @@ export default async ({
459505
CreateDate: new Date(),
460506
AccessKeyLastUsedData: [],
461507
MFADevices: [],
508+
VirtualMFADevices:
509+
virtualMFADevices?.filter(d => d.User?.Arn === userReport.Arn) ||
510+
[],
462511
Groups: [],
463512
Policies: [],
464513
ManagedPolicies: [],
@@ -471,8 +520,13 @@ export default async ({
471520
return undefined
472521
}
473522

523+
const { Arn, ...rest } = user
524+
474525
return {
475-
...user,
526+
Arn,
527+
VirtualMFADevices:
528+
virtualMFADevices?.filter(d => d.User?.Arn === Arn) || [],
529+
...rest,
476530
ReportData: userReport,
477531
}
478532
})

src/services/iamUser/format.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export default ({
2424
PasswordLastUsed: passwordLastUsed,
2525
AccessKeyLastUsedData: accessKeys = [],
2626
MFADevices: mfaDevices = [],
27+
VirtualMFADevices: virtualMfaDevices = [],
2728
Groups: groups = [],
2829
Policies: inlinePolicies = [],
2930
ReportData: {
@@ -79,6 +80,17 @@ export default ({
7980
})
8081
}
8182

83+
// Virtual MFA Devices
84+
const virtualMfaData = []
85+
if (!isEmpty(virtualMfaDevices)) {
86+
virtualMfaDevices.map(({ SerialNumber, EnableDate }) => {
87+
virtualMfaData.push({
88+
serialNumber: SerialNumber,
89+
enableDate: EnableDate?.toISOString(),
90+
})
91+
})
92+
}
93+
8294
// Format User Tags
8395
const userTags = formatTagsFromMap(tags)
8496

@@ -108,6 +120,7 @@ export default ({
108120
creationTime: creationTime?.toISOString() || '',
109121
accessKeyData,
110122
mfaDevices: mfaData,
123+
virtualMfaDevices: virtualMfaData,
111124
accessKeysActive:
112125
accessKey1Active === 'true' || accessKey2Active === 'true',
113126
passwordLastUsed: passwordLastUsed?.toISOString() || '',

src/services/iamUser/schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type awsIamUser @key(fields: "id") {
1313
accessKeysActive: Boolean @search
1414
accessKeyData: [awsIamAccessKey]
1515
mfaDevices: [awsIamMfaDevice]
16+
virtualMfaDevices: [awsIamMfaDevice]
1617
groups: [String]
1718
tags: [awsRawTag]
1819
inlinePolicies: [String]

src/types/generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,6 +3213,7 @@ export type AwsIamUser = {
32133213
passwordNextRotation?: Maybe<Scalars['String']>;
32143214
path?: Maybe<Scalars['String']>;
32153215
tags?: Maybe<Array<Maybe<AwsRawTag>>>;
3216+
virtualMfaDevices?: Maybe<Array<Maybe<AwsIamMfaDevice>>>;
32163217
};
32173218

32183219
export type AwsIgw = {

0 commit comments

Comments
 (0)