UNPKG

@cloud-copilot/iam-lens

Version:

Visibility in IAM in and across AWS accounts

161 lines 6.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createJobForWhoCanWorkItem = createJobForWhoCanWorkItem; exports.executeWhoCan = executeWhoCan; const iam_data_1 = require("@cloud-copilot/iam-data"); const iam_simulate_1 = require("@cloud-copilot/iam-simulate"); const simulate_js_1 = require("../simulate/simulate.js"); const log_1 = require("@cloud-copilot/log"); function createJobForWhoCanWorkItem(workItem, collectClient, whoCanOptions) { return { properties: {}, execute: async (context) => { return executeWhoCan(workItem, collectClient, whoCanOptions); } }; } async function executeWhoCan(workItem, collectClient, whoCanOptions) { const { principal, resource, resourceAccount, action } = workItem; const [service, serviceAction] = action.split(':'); const discoveryResult = await (0, simulate_js_1.simulateRequest)({ principal, resourceArn: resource, resourceAccount: resourceAccount, action, customContextKeys: {}, simulationMode: 'Discovery', s3AbacOverride: whoCanOptions.s3AbacOverride, additionalStrictContextKeys: whoCanOptions.strictContextKeys }, collectClient); if (discoveryResult.result.resultType === 'error') { log_1.log.error({ mode: 'discovery', simulationErrors: true, errors: discoveryResult.result.errors, resource }); throw new Error('Discovery simulation failed: ' + JSON.stringify(discoveryResult.result.errors)); } const actionType = await getActionLevel(service, serviceAction); if (discoveryResult?.result.overallResult === 'Allowed') { const strictResult = await (0, simulate_js_1.simulateRequest)({ principal, resourceArn: resource, resourceAccount, action, customContextKeys: {}, simulationMode: 'Strict', s3AbacOverride: whoCanOptions.s3AbacOverride, additionalStrictContextKeys: whoCanOptions.strictContextKeys }, collectClient); if (strictResult.result.resultType === 'error') { log_1.log.error({ mode: 'strict', simulationErrors: true, errors: strictResult.result.errors, resource }); throw new Error('Strict simulation failed: ' + JSON.stringify(strictResult.result.errors)); } if (strictResult?.result.overallResult === 'Allowed') { return mapSimulationResultToWhoCanExecutionResult(workItem, service, serviceAction, actionType, strictResult.result, !!whoCanOptions.collectDenyDetails, !!whoCanOptions.collectGrantDetails); } } else { return mapSimulationResultToWhoCanExecutionResult(workItem, service, serviceAction, actionType, discoveryResult.result, !!whoCanOptions.collectDenyDetails, !!whoCanOptions.collectGrantDetails); } return mapSimulationResultToWhoCanExecutionResult(workItem, service, serviceAction, actionType, discoveryResult.result, !!whoCanOptions.collectDenyDetails, !!whoCanOptions.collectGrantDetails); } /** * Get the action level for a specific service action, will fail if the service or action does not exist. * * @param service the service the action belongs to * @param action the action to get the level for * @returns the access level of the action, e.g. 'Read', 'Write', 'List', 'Tagging', 'Permissions management', 'Other' */ async function getActionLevel(service, action) { const details = await (0, iam_data_1.iamActionDetails)(service, action); return details.accessLevel; } function mapSimulationResultToWhoCanExecutionResult(workItem, service, action, actionType, simulationResponse, collectDenyDetails, collectGrantDetails) { const { principal } = workItem; if (simulationResponse.overallResult === 'Allowed') { // Build allowed result const allowed = { principal, service, action, level: actionType.toLowerCase() }; if (simulationResponse.resultType === 'single') { const analysis = simulationResponse.result.analysis; if (analysis.ignoredConditions && Object.keys(analysis.ignoredConditions).length > 0) { allowed.conditions = analysis.ignoredConditions; } if (analysis.ignoredRoleSessionName) { allowed.dependsOnSessionName = true; } if (simulationResponse.result.resourceType) { allowed.resourceType = simulationResponse.result.resourceType; } if (collectGrantDetails) { allowed.details = (0, iam_simulate_1.getGrantReasons)(analysis); } } else { // Wildcard result - collect allowed patterns with per-pattern grant details const allowedPatterns = []; for (const r of simulationResponse.results) { if (r.analysis.result === 'Allowed') { allowedPatterns.push({ pattern: r.resourcePattern, resourceType: r.resourceType, conditions: r.analysis.ignoredConditions, dependsOnSessionName: r.analysis.ignoredRoleSessionName ? true : undefined, ...(collectGrantDetails && { details: (0, iam_simulate_1.getGrantReasons)(r.analysis) }) }); } } if (allowedPatterns.length > 0) { allowed.allowedPatterns = allowedPatterns; } } return { type: 'allowed', workItem, allowed }; } // Denied result if (!collectDenyDetails) { // If we don't need to collect deny details, we can return a simple denied result without analysis return { type: 'denied', workItem }; } if (simulationResponse.resultType === 'single') { return { type: 'denied_single', workItem, analysis: simulationResponse.result.analysis }; } else { // Wildcard denial - collect denied patterns const deniedPatterns = simulationResponse.results .filter((r) => r.analysis.result !== 'Allowed') .map((r) => ({ pattern: r.resourcePattern, resourceType: r.resourceType, analysis: r.analysis })); return { type: 'denied_wildcard', overallResult: simulationResponse.overallResult, workItem, deniedPatterns }; } } //# sourceMappingURL=WhoCanWorker.js.map