UNPKG

@cloud-copilot/iam-lens

Version:

Visibility in IAM in and across AWS accounts

119 lines 4.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.statementAppliesToPrincipal = statementAppliesToPrincipal; exports.makePrincipalOnlyPolicyFromStatement = makePrincipalOnlyPolicyFromStatement; const iam_policy_1 = require("@cloud-copilot/iam-policy"); const iam_simulate_1 = require("@cloud-copilot/iam-simulate"); const iam_utils_1 = require("@cloud-copilot/iam-utils"); const contextKeys_js_1 = require("../../simulate/contextKeys.js"); /** * Checks to see if a statement applies to a principal by running a simulation. * * If the principal is a match return 'PrincipalMatch' * If the account is a match return 'AccountMatch' * Otherwise return 'NoMatch' * * @param statement the statement to check * @param principalArn the arn of the principal to check * @param client the IAM collect client to use for retrieving principal information * @returns Whether the statement applies to the principal */ async function statementAppliesToPrincipal(statement, principalArn, client) { const principalAccount = (0, iam_utils_1.splitArnParts)(principalArn).accountId; const resourcePolicy = makePrincipalOnlyPolicyFromStatement(statement); const simulationRequest = { principal: principalArn, action: 'kms:DescribeKey', resourceAccount: principalAccount, resourceArn: undefined, customContextKeys: {}, simulationMode: 'Strict' }; // We use KMS, so we get kms:CallerAccount context key support const { contextKeys } = await (0, contextKeys_js_1.createContextKeys)(client, simulationRequest, 'kms', {}); const request = { action: 'kms:DescribeKey', resource: { resource: 'arn:aws:kms:us-east-1:123456789012:key/abcd1234-ab12-cd34-ef23-456789abcdef', accountId: principalAccount }, principal: principalArn, contextVariables: contextKeys }; const simulation = { request, identityPolicies: [], resourcePolicy: resourcePolicy.toJSON(), serviceControlPolicies: [], resourceControlPolicies: [] }; const result = await (0, iam_simulate_1.runSimulation)(simulation, { simulationMode: simulationRequest.simulationMode }); if (result.resultType === 'error') { return 'NoMatch'; } const analysis = result.resultType === 'single' ? result.result.analysis : undefined; if (analysis?.result === 'Allowed') { return 'PrincipalMatch'; } if (analysis?.resourceAnalysis?.result === 'AllowedForAccount') { return 'AccountMatch'; } return 'NoMatch'; } const principalKeys = new Set([ 'aws:PrincipalArn', 'aws:PrincipalAccount', 'aws:PrincipalOrgId', 'aws:PrincipalOrgPaths', 'aws:PrincipalType', 'aws:userid', 'aws:username', 'aws:PrincipalIsAWSService', 'kms:CallerAccount' ].map((k) => k.toLowerCase())); /** * Makes a policy that captures the principal and principal conditions from a statement * and allows all actions on all resources. * * The conditions returned are only those that relate to the principal. * * @param statement the statement to extract the principal from * @returns */ function makePrincipalOnlyPolicyFromStatement(statement) { const rawStatement = structuredClone(statement.toJSON()); const rawStatementValues = {}; if (statement.isPrincipalStatement()) { rawStatementValues.Principal = rawStatement.Principal; } else if (statement.isNotPrincipalStatement()) { rawStatementValues.NotPrincipal = rawStatement.NotPrincipal; } if (rawStatement.Condition) { for (const operator of Object.keys(rawStatement.Condition)) { for (const key of Object.keys(rawStatement.Condition[operator])) { if (!principalKeys.has(key.toLowerCase())) { delete rawStatement.Condition[operator][key]; } } if (Object.keys(rawStatement.Condition[operator]).length === 0) { delete rawStatement.Condition[operator]; } } if (Object.keys(rawStatement.Condition).length > 0) { rawStatementValues.Condition = rawStatement.Condition; } } return (0, iam_policy_1.loadPolicy)({ Version: '2012-10-17', Statement: { Effect: 'Allow', Resource: '*', Action: '*', ...rawStatementValues } }); } //# sourceMappingURL=statements.js.map