@cloud-copilot/iam-collect
Version:
Collect IAM information from AWS Accounts
296 lines • 11.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthorizationDetailsSync = void 0;
exports.getAuthorizationDetails = getAuthorizationDetails;
const client_iam_1 = require("@aws-sdk/client-iam");
const client_tools_js_1 = require("../../utils/client-tools.js");
const log_1 = require("@cloud-copilot/log");
const tags_js_1 = require("../../utils/tags.js");
const sync_js_1 = require("../sync.js");
exports.AuthorizationDetailsSync = {
awsService: 'iam',
name: 'authorizationDetails',
global: true,
execute: async (accountId, region, credentials, storage, endpoint, syncOptions) => {
const client = syncOptions.clientPool.client(client_iam_1.IAMClient, credentials, region, endpoint);
const authDetails = await getAuthorizationDetails(client, syncOptions.workerPool, syncOptions.customConfig);
const roles = authDetails.roles || [];
const roleData = roles.map((role) => {
return {
arn: role.Arn,
'managed-policies': role.AttachedManagedPolicies?.map((p) => p.PolicyArn),
'trust-policy': role.AssumeRolePolicyDocument,
'instance-profiles': role.InstanceProfileList?.map((i) => i.Arn),
'inline-policies': role.RolePolicyList,
tags: (0, tags_js_1.convertTagsToRecord)(role.Tags),
metadata: {
arn: role.Arn,
name: role.RoleName,
id: role.RoleId,
path: role.Path,
created: role.CreateDate,
permissionBoundary: role.PermissionsBoundary?.PermissionsBoundaryArn
}
};
});
await (0, sync_js_1.syncData)(roleData, storage, accountId, {
service: 'iam',
resourceType: 'role',
account: accountId
}, syncOptions.writeOnly);
const groupArns = {};
const groupData = authDetails.groups.map((group) => {
groupArns[group.GroupName] = group.Arn;
return {
arn: group.Arn,
'inline-policies': group.GroupPolicyList,
'managed-policies': group.AttachedManagedPolicies?.map((p) => p.PolicyArn),
metadata: {
arn: group.Arn,
path: group.Path,
name: group.GroupName,
id: group.GroupId,
created: group.CreateDate
}
};
});
await (0, sync_js_1.syncData)(groupData, storage, accountId, {
service: 'iam',
resourceType: 'group',
account: accountId
}, syncOptions.writeOnly);
const customerPolicyData = authDetails.policies.map((policy) => {
return {
arn: policy.Arn,
metadata: {
arn: policy.Arn,
name: policy.PolicyName,
id: policy.PolicyId,
description: policy.Description,
defaultVersionId: policy.DefaultVersionId,
path: policy.Path,
permissionsBoundaryUsageCount: policy.PermissionsBoundaryUsageCount,
isAttachable: policy.IsAttachable,
createDate: policy.CreateDate,
updateDate: policy.UpdateDate
},
'current-policy': policy.PolicyVersionList?.filter((version) => version.IsDefaultVersion).at(0)?.Document,
policy: undefined,
tags: (0, tags_js_1.convertTagsToRecord)(policy.Tags)
};
});
await (0, sync_js_1.syncData)(customerPolicyData, storage, accountId, {
service: 'iam',
resourceType: 'policy',
account: accountId
}, syncOptions.writeOnly);
const awsManagedPolicyData = authDetails.awsManagedPolicies.map((policy) => {
return {
arn: policy.Arn,
metadata: {
arn: policy.Arn,
name: policy.PolicyName,
id: policy.PolicyId,
description: policy.Description,
defaultVersionId: policy.DefaultVersionId,
path: policy.Path,
permissionsBoundaryUsageCount: policy.PermissionsBoundaryUsageCount,
isAttachable: policy.IsAttachable,
createDate: policy.CreateDate,
updateDate: policy.UpdateDate
},
'current-policy': policy.PolicyVersionList?.filter((version) => version.IsDefaultVersion).at(0)?.Document,
policy: undefined
};
});
await (0, sync_js_1.syncData)(awsManagedPolicyData, storage, accountId, {
service: 'iam',
resourceType: 'policy',
account: 'aws'
}, syncOptions.writeOnly);
const userData = authDetails.users.map((user) => {
return {
arn: user.Arn,
'managed-policies': user.AttachedManagedPolicies?.map((p) => p.PolicyArn),
'inline-policies': user.UserPolicyList,
groups: user.GroupList?.map((g) => groupArns[g]),
tags: (0, tags_js_1.convertTagsToRecord)(user.Tags),
metadata: {
arn: user.Arn,
path: user.Path,
permissionBoundary: user.PermissionsBoundary?.PermissionsBoundaryArn,
id: user.UserId,
name: user.UserName,
created: user.CreateDate
}
};
});
(0, sync_js_1.syncData)(userData, storage, accountId, {
service: 'iam',
resourceType: 'user',
account: accountId
}, syncOptions.writeOnly);
}
};
/**
* Return the results of the Authorization Details call for this account.
* Excludes users and AWS managed policies.
*
* @param credentials The credentials to use for the API call
* @returns Returns the results of the Authorization Details call for this account
*/
async function getAuthorizationDetails(client, concurrentWorkerPool, customConfig) {
let isTruncated = false;
let getDetailsCommand;
let response;
let marker;
const groupDetails = [];
const roleDetails = [];
const policyDetails = [];
const awsManagedPolicies = [];
const userDetails = [];
do {
getDetailsCommand = new client_iam_1.GetAccountAuthorizationDetailsCommand({
Marker: marker,
Filter: ['Role', 'Group', 'LocalManagedPolicy', 'AWSManagedPolicy', 'User']
});
response = await client.send(getDetailsCommand);
groupDetails.push(...(response.GroupDetailList?.map(parseGroupDocs) || []));
roleDetails.push(...(response.RoleDetailList?.map(parseRoleDocs) || []));
userDetails.push(...(response.UserDetailList?.map(parseUserDocs) || []));
for (const policy of response.Policies || []) {
const policyDetail = parsePolicyDocs(policy);
if (policyDetail.Arn?.startsWith('arn:aws:iam::aws:policy/')) {
awsManagedPolicies.push(policyDetail);
}
else {
policyDetails.push(policyDetail);
}
}
isTruncated = !!response.IsTruncated;
marker = response.Marker;
} while (isTruncated);
let policiesWithTags = policyDetails;
if (customConfig?.includePolicyTags) {
log_1.log.info('Including policy tags in authorization details sync');
policiesWithTags = await getTagsForManagedPolicies(client, policyDetails, concurrentWorkerPool);
}
return {
groups: groupDetails,
roles: roleDetails,
policies: policiesWithTags,
awsManagedPolicies,
users: userDetails
};
}
/**
* Download the tags for the managed policies.
*
* @param client the IAM client to use for the API call
* @param policies the policies to get the tags for
* @returns the policies with the tags added
*/
async function getTagsForManagedPolicies(client, policies, concurrentWorkerPool) {
const policiesWithTags = [];
const execute = async (context) => {
const { policy } = context.properties;
const command = new client_iam_1.ListPolicyTagsCommand({ PolicyArn: policy.Arn });
const tags = await (0, client_tools_js_1.runAndCatch404)(async () => {
const result = await client.send(command);
return result.Tags;
});
return {
...policy,
Tags: tags
};
};
const jobs = policies.map((policy) => ({
properties: {
policy
},
execute
}));
const jobResults = await Promise.all(concurrentWorkerPool.enqueueAll(jobs));
for (const jobResult of jobResults) {
if (jobResult.status === 'fulfilled') {
policiesWithTags.push(jobResult.value);
}
else {
// Log the error but continue processing other policies
const policyArn = jobResult.properties.policy.Arn;
log_1.log.error('Failed to get tags for policy', jobResult.reason, {
policyArn
});
throw new Error(`Failed to get tags for policy ${policyArn}. See logs for details.`);
}
}
return policiesWithTags;
}
/**
* Decodes and parses the policy documents in the group.
*
* @param group The GroupDetail object to parse the policy documents for
* @returns Returns the GroupDetail object with the policy documents decoded and parsed
*/
function parseGroupDocs(group) {
if (group.GroupPolicyList) {
group.GroupPolicyList.forEach((policy) => {
if (policy.PolicyDocument) {
policy.PolicyDocument = JSON.parse(decodeURIComponent(policy.PolicyDocument));
}
});
}
return group;
}
/**
* Decodes and parses the policy documents in the role.
*
* @param role the RoleDetail object to parse the policy documents for
* @returns Returns the RoleDetail object with the policy documents decoded and parsed
*/
function parseRoleDocs(role) {
if (role.AssumeRolePolicyDocument) {
role.AssumeRolePolicyDocument = JSON.parse(decodeURIComponent(role.AssumeRolePolicyDocument));
}
if (role.RolePolicyList) {
role.RolePolicyList.forEach((policy) => {
if (policy.PolicyDocument) {
policy.PolicyDocument = JSON.parse(decodeURIComponent(policy.PolicyDocument));
}
});
}
return role;
}
/**
* Decodes and parses the policy documents in the managed policy.
*
* @param policy The ManagedPolicyDetail object to parse the policy documents for
* @returns Returns the ManagedPolicyDetail object with the policy documents decoded and parsed
*/
function parsePolicyDocs(policy) {
if (policy.PolicyVersionList) {
policy.PolicyVersionList.forEach((version) => {
if (version.Document) {
version.Document = JSON.parse(decodeURIComponent(version.Document));
}
});
}
return policy;
}
/**
* Decodes and parses the policy documents attached directly to a user.
*
* @param user The userDetail object to parse the policy documents for
* @returns Returns the UserDetail object with the policy documents decoded and parsed
*/
function parseUserDocs(user) {
if (user.UserPolicyList) {
user.UserPolicyList.forEach((policy) => {
if (policy.PolicyDocument) {
policy.PolicyDocument = JSON.parse(decodeURIComponent(policy.PolicyDocument));
}
});
}
return user;
}
//# sourceMappingURL=authorizationDetails.js.map