UNPKG

cdk-nag

Version:

Check CDK v2 applications for best practices using a combination on available rule packs.

94 lines 14.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ const path_1 = require("path"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const aws_applicationautoscaling_1 = require("aws-cdk-lib/aws-applicationautoscaling"); const aws_dynamodb_1 = require("aws-cdk-lib/aws-dynamodb"); const nag_rules_1 = require("../../nag-rules"); /** * Provisioned capacity DynamoDB tables have auto-scaling enabled on their indexes * @param node the CfnResource to check */ exports.default = Object.defineProperty((node) => { if (node instanceof aws_dynamodb_1.CfnTable) { if (nag_rules_1.NagRules.resolveResourceFromIntrinsic(node, node.billingMode) !== aws_dynamodb_1.BillingMode.PAY_PER_REQUEST) { const indexWriteMatches = ['']; const indexReadMatches = ['']; const tableLogicalId = nag_rules_1.NagRules.resolveResourceFromIntrinsic(node, node.ref); const tableName = aws_cdk_lib_1.Stack.of(node).resolve(node.tableName); const globalSecondaryIndexes = aws_cdk_lib_1.Stack.of(node).resolve(node.globalSecondaryIndexes); if (Array.isArray(globalSecondaryIndexes)) { globalSecondaryIndexes.forEach((gsi) => { const resolvedGsi = aws_cdk_lib_1.Stack.of(node).resolve(gsi); indexWriteMatches.push(resolvedGsi.indexName); indexReadMatches.push(resolvedGsi.indexName); }); } for (const child of aws_cdk_lib_1.Stack.of(node).node.findAll()) { if (child instanceof aws_applicationautoscaling_1.CfnScalableTarget) { const writeMatchIndex = isMatchingScalableTarget(child, 'WriteCapacityUnits', tableLogicalId, tableName, indexWriteMatches); if (writeMatchIndex !== -1) { indexWriteMatches.splice(writeMatchIndex, 1); continue; } const readMatchIndex = isMatchingScalableTarget(child, 'ReadCapacityUnits', tableLogicalId, tableName, indexReadMatches); if (readMatchIndex !== -1) { indexReadMatches.splice(readMatchIndex, 1); } } } if (indexWriteMatches.length != 0 || indexReadMatches.length != 0) { return nag_rules_1.NagRuleCompliance.NON_COMPLIANT; } } return nag_rules_1.NagRuleCompliance.COMPLIANT; } else { return nag_rules_1.NagRuleCompliance.NOT_APPLICABLE; } }, 'name', { value: (0, path_1.parse)(__filename).name }); /** * Helper function to check whether the CfnScalableTarget is related to the given Table index * @param node the CfnScalableTarget to check * @param dimension the dimension of the CfnScalableTarget to check * @param tableLogicalId the Cfn Logical ID of the table * @param tableName the name of the table * @param indexNames the names of the indexes to check against * returns the location in the indexNames array of the matching index or -1 if no match is found */ function isMatchingScalableTarget(node, dimension, tableLogicalId, tableName, indexNames) { if (node.serviceNamespace === 'dynamodb') { let scalableDimension = ''; const resourceId = JSON.stringify(aws_cdk_lib_1.Stack.of(node).resolve(node.resourceId)); for (let i = 0; i < indexNames.length; i++) { const regexes = Array(); const indexName = indexNames[i]; if (indexName === '') { regexes.push(`${tableLogicalId}.*`); if (tableName !== undefined) { regexes.push(`${tableName}.*`); } scalableDimension = `dynamodb:table:${dimension}`; } else { regexes.push(`${tableLogicalId}.*index\/${indexName}(?![\\w\\-_\\.])`); if (tableName !== undefined) { regexes.push(`${tableName}.*index\/${indexName}(?![\\w\\-_\\.])`); } scalableDimension = `dynamodb:index:${dimension}`; } const regex = new RegExp(regexes.join('|'), 'gm'); if (node.scalableDimension === scalableDimension && regex.test(resourceId)) { return i; } } } return -1; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRHluYW1vREJBdXRvU2NhbGluZ0VuYWJsZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcnVsZXMvZHluYW1vZGIvRHluYW1vREJBdXRvU2NhbGluZ0VuYWJsZWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQTs7O0VBR0U7QUFDRiwrQkFBNkI7QUFDN0IsNkNBQWlEO0FBQ2pELHVGQUEyRTtBQUMzRSwyREFBaUU7QUFDakUsK0NBQThEO0FBRTlEOzs7R0FHRztBQUVILGtCQUFlLE1BQU0sQ0FBQyxjQUFjLENBQ2xDLENBQUMsSUFBaUIsRUFBcUIsRUFBRTtJQUN2QyxJQUFJLElBQUksWUFBWSx1QkFBUSxFQUFFLENBQUM7UUFDN0IsSUFDRSxvQkFBUSxDQUFDLDRCQUE0QixDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDO1lBQzdELDBCQUFXLENBQUMsZUFBZSxFQUMzQixDQUFDO1lBQ0QsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQy9CLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUM5QixNQUFNLGNBQWMsR0FBRyxvQkFBUSxDQUFDLDRCQUE0QixDQUMxRCxJQUFJLEVBQ0osSUFBSSxDQUFDLEdBQUcsQ0FDVCxDQUFDO1lBQ0YsTUFBTSxTQUFTLEdBQUcsbUJBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUN6RCxNQUFNLHNCQUFzQixHQUFHLG1CQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FDbkQsSUFBSSxDQUFDLHNCQUFzQixDQUM1QixDQUFDO1lBQ0YsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLHNCQUFzQixDQUFDLEVBQUUsQ0FBQztnQkFDMUMsc0JBQXNCLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUU7b0JB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cEQsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxjQUFjLFlBQVksU0FBUyxrQkFBa0IsQ0FBQyxDQUFDO2dCQUN2RSxJQUFJLFNBQVMsS0FBSyxTQUFTLEVBQUUsQ0FBQztvQkFDNUIsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLFNBQVMsWUFBWSxTQUFTLGtCQUFrQixDQUFDLENBQUM7Z0JBQ3BFLENBQUM7Z0JBQ0QsaUJBQWlCLEdBQUcsa0JBQWtCLFNBQVMsRUFBRSxDQUFDO1lBQ3BELENBQUM7WUFDRCxNQUFNLEtBQUssR0FBRyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQ2xELElBQ0UsSUFBSSxDQUFDLGlCQUFpQixLQUFLLGlCQUFpQjtnQkFDNUMsS0FBSyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFDdEIsQ0FBQztnQkFDRCxPQUFPLENBQUMsQ0FBQztZQUNYLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sQ0FBQyxDQUFDLENBQUM7QUFDWixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCBBbWF6b24uY29tLCBJbmMuIG9yIGl0cyBhZmZpbGlhdGVzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcbiovXG5pbXBvcnQgeyBwYXJzZSB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgQ2ZuUmVzb3VyY2UsIFN0YWNrIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgQ2ZuU2NhbGFibGVUYXJnZXQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtYXBwbGljYXRpb25hdXRvc2NhbGluZyc7XG5pbXBvcnQgeyBDZm5UYWJsZSwgQmlsbGluZ01vZGUgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZHluYW1vZGInO1xuaW1wb3J0IHsgTmFnUnVsZUNvbXBsaWFuY2UsIE5hZ1J1bGVzIH0gZnJvbSAnLi4vLi4vbmFnLXJ1bGVzJztcblxuLyoqXG4gKiBQcm92aXNpb25lZCBjYXBhY2l0eSBEeW5hbW9EQiB0YWJsZXMgaGF2ZSBhdXRvLXNjYWxpbmcgZW5hYmxlZCBvbiB0aGVpciBpbmRleGVzXG4gKiBAcGFyYW0gbm9kZSB0aGUgQ2ZuUmVzb3VyY2UgdG8gY2hlY2tcbiAqL1xuXG5leHBvcnQgZGVmYXVsdCBPYmplY3QuZGVmaW5lUHJvcGVydHkoXG4gIChub2RlOiBDZm5SZXNvdXJjZSk6IE5hZ1J1bGVDb21wbGlhbmNlID0+IHtcbiAgICBpZiAobm9kZSBpbnN0YW5jZW9mIENmblRhYmxlKSB7XG4gICAgICBpZiAoXG4gICAgICAgIE5hZ1J1bGVzLnJlc29sdmVSZXNvdXJjZUZyb21JbnRyaW5zaWMobm9kZSwgbm9kZS5iaWxsaW5nTW9kZSkgIT09XG4gICAgICAgIEJpbGxpbmdNb2RlLlBBWV9QRVJfUkVRVUVTVFxuICAgICAgKSB7XG4gICAgICAgIGNvbnN0IGluZGV4V3JpdGVNYXRjaGVzID0gWycnXTtcbiAgICAgICAgY29uc3QgaW5kZXhSZWFkTWF0Y2hlcyA9IFsnJ107XG4gICAgICAgIGNvbnN0IHRhYmxlTG9naWNhbElkID0gTmFnUnVsZXMucmVzb2x2ZVJlc291cmNlRnJvbUludHJpbnNpYyhcbiAgICAgICAgICBub2RlLFxuICAgICAgICAgIG5vZGUucmVmXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHRhYmxlTmFtZSA9IFN0YWNrLm9mKG5vZGUpLnJlc29sdmUobm9kZS50YWJsZU5hbWUpO1xuICAgICAgICBjb25zdCBnbG9iYWxTZWNvbmRhcnlJbmRleGVzID0gU3RhY2sub2Yobm9kZSkucmVzb2x2ZShcbiAgICAgICAgICBub2RlLmdsb2JhbFNlY29uZGFyeUluZGV4ZXNcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoZ2xvYmFsU2Vjb25kYXJ5SW5kZXhlcykpIHtcbiAgICAgICAgICBnbG9iYWxTZWNvbmRhcnlJbmRleGVzLmZvckVhY2goKGdzaSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgcmVzb2x2ZWRHc2kgPSBTdGFjay5vZihub2RlKS5yZXNvbHZlKGdzaSk7XG4gICAgICAgICAgICBpbmRleFdyaXRlTWF0Y2hlcy5wdXNoKHJlc29sdmVkR3NpLmluZGV4TmFtZSk7XG4gICAgICAgICAgICBpbmRleFJlYWRNYXRjaGVzLnB1c2gocmVzb2x2ZWRHc2kuaW5kZXhOYW1lKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIFN0YWNrLm9mKG5vZGUpLm5vZGUuZmluZEFsbCgpKSB7XG4gICAgICAgICAgaWYgKGNoaWxkIGluc3RhbmNlb2YgQ2ZuU2NhbGFibGVUYXJnZXQpIHtcbiAgICAgICAgICAgIGNvbnN0IHdyaXRlTWF0Y2hJbmRleCA9IGlzTWF0Y2hpbmdTY2FsYWJsZVRhcmdldChcbiAgICAgICAgICAgICAgY2hpbGQsXG4gICAgICAgICAgICAgICdXcml0ZUNhcGFjaXR5VW5pdHMnLFxuICAgICAgICAgICAgICB0YWJsZUxvZ2ljYWxJZCxcbiAgICAgICAgICAgICAgdGFibGVOYW1lLFxuICAgICAgICAgICAgICBpbmRleFdyaXRlTWF0Y2hlc1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmICh3cml0ZU1hdGNoSW5kZXggIT09IC0xKSB7XG4gICAgICAgICAgICAgIGluZGV4V3JpdGVNYXRjaGVzLnNwbGljZSh3cml0ZU1hdGNoSW5kZXgsIDEpO1xuICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHJlYWRNYXRjaEluZGV4ID0gaXNNYXRjaGluZ1NjYWxhYmxlVGFyZ2V0KFxuICAgICAgICAgICAgICBjaGlsZCxcbiAgICAgICAgICAgICAgJ1JlYWRDYXBhY2l0eVVuaXRzJyxcbiAgICAgICAgICAgICAgdGFibGVMb2dpY2FsSWQsXG4gICAgICAgICAgICAgIHRhYmxlTmFtZSxcbiAgICAgICAgICAgICAgaW5kZXhSZWFkTWF0Y2hlc1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmIChyZWFkTWF0Y2hJbmRleCAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgaW5kZXhSZWFkTWF0Y2hlcy5zcGxpY2UocmVhZE1hdGNoSW5kZXgsIDEpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoaW5kZXhXcml0ZU1hdGNoZXMubGVuZ3RoICE9IDAgfHwgaW5kZXhSZWFkTWF0Y2hlcy5sZW5ndGggIT0gMCkge1xuICAgICAgICAgIHJldHVybiBOYWdSdWxlQ29tcGxpYW5jZS5OT05fQ09NUExJQU5UO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gTmFnUnVsZUNvbXBsaWFuY2UuQ09NUExJQU5UO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gTmFnUnVsZUNvbXBsaWFuY2UuTk9UX0FQUExJQ0FCTEU7XG4gICAgfVxuICB9LFxuICAnbmFtZScsXG4gIHsgdmFsdWU6IHBhcnNlKF9fZmlsZW5hbWUpLm5hbWUgfVxuKTtcblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdG8gY2hlY2sgd2hldGhlciB0aGUgQ2ZuU2NhbGFibGVUYXJnZXQgaXMgcmVsYXRlZCB0byB0aGUgZ2l2ZW4gVGFibGUgaW5kZXhcbiAqIEBwYXJhbSBub2RlIHRoZSBDZm5TY2FsYWJsZVRhcmdldCB0byBjaGVja1xuICogQHBhcmFtIGRpbWVuc2lvbiB0aGUgZGltZW5zaW9uIG9mIHRoZSBDZm5TY2FsYWJsZVRhcmdldCB0byBjaGVja1xuICogQHBhcmFtIHRhYmxlTG9naWNhbElkIHRoZSBDZm4gTG9naWNhbCBJRCBvZiB0aGUgdGFibGVcbiAqIEBwYXJhbSB0YWJsZU5hbWUgdGhlIG5hbWUgb2YgdGhlIHRhYmxlXG4gKiBAcGFyYW0gaW5kZXhOYW1lcyB0aGUgbmFtZXMgb2YgdGhlIGluZGV4ZXMgdG8gY2hlY2sgYWdhaW5zdFxuICogcmV0dXJucyB0aGUgbG9jYXRpb24gaW4gdGhlIGluZGV4TmFtZXMgYXJyYXkgb2YgdGhlIG1hdGNoaW5nIGluZGV4IG9yIC0xIGlmIG5vIG1hdGNoIGlzIGZvdW5kXG4gKi9cbmZ1bmN0aW9uIGlzTWF0Y2hpbmdTY2FsYWJsZVRhcmdldChcbiAgbm9kZTogQ2ZuU2NhbGFibGVUYXJnZXQsXG4gIGRpbWVuc2lvbjogc3RyaW5nLFxuICB0YWJsZUxvZ2ljYWxJZDogc3RyaW5nLFxuICB0YWJsZU5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgaW5kZXhOYW1lczogc3RyaW5nW11cbik6IG51bWJlciB7XG4gIGlmIChub2RlLnNlcnZpY2VOYW1lc3BhY2UgPT09ICdkeW5hbW9kYicpIHtcbiAgICBsZXQgc2NhbGFibGVEaW1lbnNpb24gPSAnJztcbiAgICBjb25zdCByZXNvdXJjZUlkID0gSlNPTi5zdHJpbmdpZnkoU3RhY2sub2Yobm9kZSkucmVzb2x2ZShub2RlLnJlc291cmNlSWQpKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGluZGV4TmFtZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IHJlZ2V4ZXMgPSBBcnJheTxzdHJpbmc+KCk7XG4gICAgICBjb25zdCBpbmRleE5hbWUgPSBpbmRleE5hbWVzW2ldO1xuICAgICAgaWYgKGluZGV4TmFtZSA9PT0gJycpIHtcbiAgICAgICAgcmVnZXhlcy5wdXNoKGAke3RhYmxlTG9naWNhbElkfS4qYCk7XG4gICAgICAgIGlmICh0YWJsZU5hbWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHJlZ2V4ZXMucHVzaChgJHt0YWJsZU5hbWV9LipgKTtcbiAgICAgICAgfVxuICAgICAgICBzY2FsYWJsZURpbWVuc2lvbiA9IGBkeW5hbW9kYjp0YWJsZToke2RpbWVuc2lvbn1gO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVnZXhlcy5wdXNoKGAke3RhYmxlTG9naWNhbElkfS4qaW5kZXhcXC8ke2luZGV4TmFtZX0oPyFbXFxcXHdcXFxcLV9cXFxcLl0pYCk7XG4gICAgICAgIGlmICh0YWJsZU5hbWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHJlZ2V4ZXMucHVzaChgJHt0YWJsZU5hbWV9LippbmRleFxcLyR7aW5kZXhOYW1lfSg/IVtcXFxcd1xcXFwtX1xcXFwuXSlgKTtcbiAgICAgICAgfVxuICAgICAgICBzY2FsYWJsZURpbWVuc2lvbiA9IGBkeW5hbW9kYjppbmRleDoke2RpbWVuc2lvbn1gO1xuICAgICAgfVxuICAgICAgY29uc3QgcmVnZXggPSBuZXcgUmVnRXhwKHJlZ2V4ZXMuam9pbignfCcpLCAnZ20nKTtcbiAgICAgIGlmIChcbiAgICAgICAgbm9kZS5zY2FsYWJsZURpbWVuc2lvbiA9PT0gc2NhbGFibGVEaW1lbnNpb24gJiZcbiAgICAgICAgcmVnZXgudGVzdChyZXNvdXJjZUlkKVxuICAgICAgKSB7XG4gICAgICAgIHJldHVybiBpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gLTE7XG59XG4iXX0=