@csermet/multiprovider
Version:
cloud-graph provider plugin for AWS used to fetch AWS cloud data.
339 lines (338 loc) • 13 kB
JavaScript
;
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'));
});