UNPKG

@cloud-copilot/iam-lens

Version:

Visibility in IAM in and across AWS accounts

191 lines 7.9 kB
#!/usr/bin/env node "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const cli_1 = require("@cloud-copilot/cli"); const canWhat_js_1 = require("./canWhat/canWhat.js"); const collect_js_1 = require("./collect/collect.js"); const simulate_js_1 = require("./simulate/simulate.js"); const packageVersion_js_1 = require("./utils/packageVersion.js"); const whoCan_js_1 = require("./whoCan/whoCan.js"); const main = async () => { const version = await (0, packageVersion_js_1.iamLensVersion)(); const cli = (0, cli_1.parseCliArguments)('iam-lens', { simulate: { description: 'Simulate an IAM request', options: { principal: { type: 'string', values: 'single', description: 'The principal to simulate. Can be a user, role, session, or AWS service' }, resource: { type: 'string', values: 'single', description: 'The ARN of the resource to simulate access to. Ignore for wildcard actions' }, resourceAccount: { type: 'string', values: 'single', description: 'The account ID of the resource, only required if it cannot be determined from the resource ARN.' }, action: { type: 'string', values: 'single', description: 'The action to simulate; must be a valid IAM service and action such as `s3:ListBucket`' }, context: { type: 'string', values: 'multiple', description: 'The context keys to use for the simulation. Keys are formatted as key=value. Multiple values can be separated by commas (key=value1,value2,value3)' }, verbose: { type: 'boolean', description: 'Enable verbose output for the simulation', character: 'v' }, expect: { type: 'enum', values: 'single', validValues: ['Allowed', 'ImplicitlyDenied', 'ExplicitlyDenied', 'AnyDeny'], description: 'The expected result of the simulation, if the result does not match the expected response a non-zero exit code will be returned' } } }, 'who-can': { description: 'Find who can perform an action on a resource', options: { resource: { type: 'string', values: 'single', description: 'The ARN of the resource to check permissions for. Ignore for wildcard actions' }, resourceAccount: { type: 'string', values: 'single', description: 'The account ID of the resource, only required if it cannot be determined from the resource ARN. Required for wildcard actions' }, actions: { type: 'string', values: 'multiple', description: 'The action to check permissions for; must be a valid IAM service and action such as `s3:GetObject`' } } }, 'principal-can': { description: 'ALPHA: Create a consolidated view of all permissions for a principal', options: { principal: { type: 'string', values: 'single', description: 'The principal to check permissions for. Can be a user or role' }, shrinkActionLists: { type: 'boolean', character: 's', description: 'Shrink action lists to reduce policy size' } } } }, { collectConfigs: { type: 'string', description: 'The iam-collect configuration files to use', values: 'multiple' }, partition: { type: 'string', description: 'The AWS partition to use (aws, aws-cn, aws-us-gov). Defaults to aws.', values: 'single' } }, { envPrefix: 'IAM_LENS', showHelpIfNoArgs: true, requireSubcommand: true, version }); if (cli.args.collectConfigs.length === 0) { cli.args.collectConfigs.push('./iam-collect.jsonc'); } const thePartition = cli.args.partition || 'aws'; const collectConfigs = await (0, collect_js_1.loadCollectConfigs)(cli.args.collectConfigs); const collectClient = (0, collect_js_1.getCollectClient)(collectConfigs, thePartition); if (cli.subcommand === 'simulate') { const { principal, resource, resourceAccount, action, context } = cli.args; const contextKeys = convertContextKeysToMap(context); const { request, result } = await (0, simulate_js_1.simulateRequest)({ principal: principal, resourceArn: resource, resourceAccount: resourceAccount, action: action, customContextKeys: contextKeys, simulationMode: 'Strict' }, collectClient); if (result.errors) { console.error('Simulation Errors:'); console.log(JSON.stringify(result.errors, null, 2)); process.exit(1); } console.log(`Simulation Result: ${result.analysis?.result}`); if (cli.args.verbose) { console.log(JSON.stringify({ request, result }, null, 2)); } if (!(0, simulate_js_1.resultMatchesExpectation)(cli.args.expect, result.analysis?.result)) { process.exit(1); } } else if (cli.subcommand === 'who-can') { const { resource, resourceAccount, actions } = cli.args; if (!resourceAccount && !resource && actions.length === 0) { console.error('Error: At least 1) resource or 2) resource-account and actions must be provided for who-can command'); process.exit(1); } const results = await (0, whoCan_js_1.whoCan)(collectClient, { resource: cli.args.resource, actions: cli.args.actions, resourceAccount: cli.args.resourceAccount }); console.log(JSON.stringify(results, null, 2)); } else if (cli.subcommand === 'principal-can') { const { principal, shrinkActionLists } = cli.args; if (!principal) { console.error('Error: Principal must be provided for principal-can command'); process.exit(1); } const results = await (0, canWhat_js_1.canWhat)(collectClient, { principal: principal, shrinkActionLists }); console.log(JSON.stringify(results, null, 2)); } }; main() .catch((e) => { console.error(e); process.exit(1); }) .then(() => { }) .finally(() => { }); /** * Convert the context keys from the CLI arguments into a map. * * @param contextKeys the context keys from the CLI arguments, formatted as key=value1,value2,... * @returns a map of context keys where each key is associated with a single value or an array of values */ function convertContextKeysToMap(contextKeys) { const contextMap = {}; for (const key of contextKeys) { const [keyName, value] = key.split('='); if (value) { const values = value.split(','); if (values.length > 1) { contextMap[keyName] = values; } else { contextMap[keyName] = values[0]; } } } return contextMap; } //# sourceMappingURL=cli.js.map