UNPKG

@csermet/multiprovider

Version:

cloud-graph provider plugin for AWS used to fetch AWS cloud data.

339 lines (338 loc) 13 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getCredentialReportData = exports.listIamUsers = exports.listVirtualMFADevices = exports.listMFADevicesByUsername = void 0; const sdk_1 = __importDefault(require("@cloudgraph/sdk")); const groupBy_1 = __importDefault(require("lodash/groupBy")); const isEmpty_1 = __importDefault(require("lodash/isEmpty")); const cuid_1 = __importDefault(require("cuid")); const iam_1 = __importDefault(require("aws-sdk/clients/iam")); const logger_1 = __importDefault(require("../../properties/logger")); const utils_1 = require("../../utils"); const errorLog_1 = __importDefault(require("../../utils/errorLog")); const regions_1 = require("../../enums/regions"); const format_1 = require("../../utils/format"); const constants_1 = require("../../config/constants"); const lt = { ...logger_1.default }; const { logger } = sdk_1.default; const serviceName = 'IAM User'; const errorLog = new errorLog_1.default(serviceName); const endpoint = utils_1.initTestEndpoint(serviceName); const customRetrySettings = utils_1.setAwsRetryOptions({ maxRetries: constants_1.MAX_FAILED_AWS_REQUEST_RETRIES, baseDelay: constants_1.IAM_CUSTOM_DELAY, }); const tagsByUsername = async (iam, { UserName }) => new Promise(resolve => { iam.listUserTags({ UserName }, (err, data) => { if (err) { errorLog.generateAwsErrorLog({ functionName: 'iam:listUserTags', err, }); } if (!isEmpty_1.default(data)) { const { Tags: tags = [] } = data; resolve({ UserName, Tags: format_1.convertAwsTagsToTagMap(tags) }); } resolve(null); }); }); const groupsByUsername = async (iam, { UserName }) => new Promise(resolve => { iam.listGroupsForUser({ UserName }, (err, data) => { if (err) { errorLog.generateAwsErrorLog({ functionName: 'iam:listGroupsForUser', err, }); } if (!isEmpty_1.default(data)) { const { Groups = [] } = data; const userGroups = Groups.map(({ GroupId }) => GroupId); resolve({ UserName, Groups: userGroups }); } resolve(null); }); }); const policiesByUsername = async (iam, { UserName }) => new Promise(resolve => { iam.listUserPolicies({ UserName }, (err, data) => { if (err) { errorLog.generateAwsErrorLog({ functionName: 'iam:listGroupsForUser', err, }); } if (!isEmpty_1.default(data)) { const { PolicyNames = [] } = data; resolve({ UserName, Policies: PolicyNames }); } resolve(null); }); }); const managedPoliciesByUsername = async (iam, { UserName }) => new Promise(resolve => { iam.listAttachedUserPolicies({ UserName }, (err, data) => { if (err) { errorLog.generateAwsErrorLog({ functionName: 'iam:listAttachedUserPolicies', err, }); } if (!isEmpty_1.default(data)) { const { AttachedPolicies = [] } = data; resolve({ UserName, ManagedPolicies: AttachedPolicies, }); } resolve(null); }); }); const accessKeyByUsername = async (iam, { UserName }) => new Promise(resolveAccessKeyFetch => { const promises = []; iam.listAccessKeys({ UserName, }, async (err, data) => { if (err) { errorLog.generateAwsErrorLog({ functionName: 'iam:listAccessKeys', err, }); return resolveAccessKeyFetch(null); } const { AccessKeyMetadata: accessKeyMetadata } = data ?? {}; if (!isEmpty_1.default(accessKeyMetadata)) { accessKeyMetadata.map(({ AccessKeyId, ...Metadata }) => { const lastUsedPromise = new Promise(resolveLastUsedData => { iam.getAccessKeyLastUsed({ AccessKeyId, }, (err, data) => { const { AccessKeyLastUsed: accessKeyLastUsed } = data || {}; if (err) { errorLog.generateAwsErrorLog({ functionName: 'iam:getAccessKeyLastUsed', err, }); } if (!isEmpty_1.default(accessKeyLastUsed)) { resolveLastUsedData({ AccessKeyId, ...Metadata, AccessKeyLastUsed: accessKeyLastUsed, }); } resolveLastUsedData(null); }); }); promises.push(lastUsedPromise); }); const accessKeys = await Promise.all(promises); resolveAccessKeyFetch({ UserName, AccessKeys: accessKeys }); } resolveAccessKeyFetch(null); }); }); const listMFADevicesByUsername = async (iam, user, marker) => new Promise(resolve => { const { UserName } = user; iam.listMFADevices({ UserName, Marker: marker, }, async (err, data) => { if (err) { errorLog.generateAwsErrorLog({ functionName: 'iam:listMFADevices', err, }); } if (!isEmpty_1.default(data)) { const { MFADevices = [] } = data; resolve({ UserName, MFADevices }); } resolve(null); }); }); exports.listMFADevicesByUsername = listMFADevicesByUsername; const listVirtualMFADevices = async (iam) => new Promise(resolve => { const virtualMFADeviceList = []; let args = {}; const listAllVirtualMFADevices = (marker) => { if (marker) { args = { ...args, Marker: marker }; } try { iam.listVirtualMFADevices(args, (err, data) => { if (err) { errorLog.generateAwsErrorLog({ functionName: 'iam:listVirtualMFADevices', err, }); } if (isEmpty_1.default(data)) { return resolve([]); } const { VirtualMFADevices = [], IsTruncated, Marker } = data; virtualMFADeviceList.push(...VirtualMFADevices); if (IsTruncated) { listAllVirtualMFADevices(Marker); } else { resolve(virtualMFADeviceList); } }); } catch (error) { resolve([]); } }; listAllVirtualMFADevices(); }); exports.listVirtualMFADevices = listVirtualMFADevices; const listIamUsers = async (iam, marker) => new Promise(resolve => { const result = []; const groupsByNamePromises = []; const policiesByNamePromise = []; const managedPoliciesByNamePromise = []; const accessKeysByUser = []; const mfaDevicesPromises = []; const tagsByNamePromises = []; iam.listUsers({ Marker: marker }, async (err, data) => { if (err) { errorLog.generateAwsErrorLog({ functionName: 'iam:listUsers', err, }); } // No data if (isEmpty_1.default(data)) { return resolve(result); } const { Users: users = [], IsTruncated, Marker } = data; users.map(user => { groupsByNamePromises.push(groupsByUsername(iam, user)); policiesByNamePromise.push(policiesByUsername(iam, user)); managedPoliciesByNamePromise.push(managedPoliciesByUsername(iam, user)); accessKeysByUser.push(accessKeyByUsername(iam, user)); mfaDevicesPromises.push(exports.listMFADevicesByUsername(iam, user)); tagsByNamePromises.push(tagsByUsername(iam, user)); }); const groups = await Promise.all(groupsByNamePromises); const policies = await Promise.all(policiesByNamePromise); const managedPolicies = await Promise.all(managedPoliciesByNamePromise); const accessKeys = await Promise.all(accessKeysByUser); const mfaDevices = await Promise.all(mfaDevicesPromises); const tags = await Promise.all(tagsByNamePromises); result.push(...users.map(({ UserName, ...user }) => { return { UserName, ...user, region: regions_1.globalRegionName, Groups: groups ?.filter(g => g?.UserName === UserName) .map(g => g.Groups) .reduce((current, acc) => [...acc, ...current], []) || [], Policies: policies ?.filter(p => p?.UserName === UserName) .map(p => p.Policies) .reduce((current, acc) => [...acc, ...current], []) || [], ManagedPolicies: managedPolicies ?.filter(p => p?.UserName === UserName) .map(p => p.ManagedPolicies) .reduce((current, acc) => [...acc, ...current], []) || [], AccessKeyLastUsedData: accessKeys ?.filter(k => k?.UserName === UserName) .map(k => k.AccessKeys) .reduce((current, acc) => [...acc, ...current], []) || [], MFADevices: mfaDevices ?.filter(d => d?.UserName === UserName) .map(d => d.MFADevices) .reduce((current, acc) => [...acc, ...current], []) || [], Tags: tags.find(t => t?.UserName === UserName)?.Tags || {}, }; })); if (IsTruncated) { result.push(...(await exports.listIamUsers(iam, Marker))); } resolve(result); }); }); exports.listIamUsers = listIamUsers; const getCredentialReportData = async (iam) => new Promise(resolve => { iam.generateCredentialReport((err) => { if (err) { errorLog.generateAwsErrorLog({ functionName: 'iam:generateCredentialReport', err, }); return resolve([]); } iam.getCredentialReport(async (err, data) => { if (err) { errorLog.generateAwsErrorLog({ functionName: 'iam:getCredentialReport', err, }); } if (!isEmpty_1.default(data)) { const report = await format_1.parseCSV(data.Content.toString()); resolve(report); } resolve([]); }); }); }); exports.getCredentialReportData = getCredentialReportData; /** * IAM User */ exports.default = async ({ config, }) => new Promise(async (resolve) => { let usersData = []; const client = new iam_1.default({ ...config, region: regions_1.globalRegionName, endpoint, ...customRetrySettings, }); logger.debug(lt.lookingForIamUsers); // Fetch IAM Users const iamUsers = await exports.listIamUsers(client); // Fetch IAM Report Credential const credentialReport = await exports.getCredentialReportData(client); // Fetch all virtual MFA Devices const virtualMFADevices = await exports.listVirtualMFADevices(client); usersData = credentialReport .map(userReport => { const user = iamUsers.find(u => u.Arn === userReport.Arn); if (userReport.User.includes('root')) { return { Path: '/', UserName: 'root', UserId: cuid_1.default(), Arn: userReport.Arn, CreateDate: new Date(), AccessKeyLastUsedData: [], MFADevices: [], VirtualMFADevices: virtualMFADevices?.filter(d => d.User?.Arn === userReport.Arn) || [], Groups: [], Policies: [], ManagedPolicies: [], ReportData: userReport, region: regions_1.globalRegionName, }; } if (!user) { return undefined; } const { Arn, ...rest } = user; return { Arn, VirtualMFADevices: virtualMFADevices?.filter(d => d.User?.Arn === Arn) || [], ...rest, ReportData: userReport, }; }) .filter(Boolean); errorLog.reset(); logger.debug(lt.fetchedIamUsers(usersData.length)); resolve(groupBy_1.default(usersData, 'region')); });