UNPKG

@k9securityio/k9-cdk

Version:

Provision strong AWS security policies easily using the AWS CDK.

137 lines 22.6 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.makeKeyPolicy = exports.CloudFrontOACReadAccessGenerator = exports.SID_DENY_EVERYONE_ELSE = exports.SID_ALLOW_ROOT_AND_IDENTITY_POLICIES = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const iam = require("aws-cdk-lib/aws-iam"); const aws_iam_1 = require("aws-cdk-lib/aws-iam"); const k9policy_1 = require("./k9policy"); let SUPPORTED_CAPABILITIES = new Array(k9policy_1.AccessCapability.ADMINISTER_RESOURCE, k9policy_1.AccessCapability.READ_CONFIG, k9policy_1.AccessCapability.READ_DATA, k9policy_1.AccessCapability.WRITE_DATA, k9policy_1.AccessCapability.DELETE_DATA); exports.SID_ALLOW_ROOT_AND_IDENTITY_POLICIES = 'Allow Root User to Administer Key And Identity Policies'; exports.SID_DENY_EVERYONE_ELSE = 'DenyEveryoneElse'; /** * Generate key policy statements to enable the CloudFront service to read encrypted S3 bucket object data (only) * from within a <a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html#sse-kms">CloudFront OAC integration</a>. */ class CloudFrontOACReadAccessGenerator { constructor(distributionArn) { this.distributionArn = distributionArn; } makeAllowStatements() { return [new aws_iam_1.PolicyStatement({ sid: CloudFrontOACReadAccessGenerator.SID_ALLOW_CLOUDFRONT_SVC_READ_DATA, effect: aws_iam_1.Effect.ALLOW, principals: [new aws_iam_1.ServicePrincipal('cloudfront.amazonaws.com')], actions: ['kms:Decrypt'], resources: ['*'], conditions: { StringEquals: { 'aws:SourceArn': this.distributionArn }, }, }), new aws_iam_1.PolicyStatement({ sid: CloudFrontOACReadAccessGenerator.SID_ALLOW_CLOUDFRONT_IAM_ROLE_READ_DATA, effect: aws_iam_1.Effect.ALLOW, principals: [new aws_iam_1.AnyPrincipal()], actions: ['kms:Decrypt'], resources: ['*'], conditions: { // use ArnEquals condition instead of a plain Principal element in case // the CloudFront service recreates the role. // conditions bind against the principal ARN at runtime. // the principal element binds (once) to the principal's canonical userid at policy definition time. ArnEquals: { 'aws:PrincipalArn': 'arn:aws:iam::856369053181:role/OriginAccessControlRole', }, }, })]; } makeConditionsToExceptFromDenyEveryoneElse() { // return a (TypeScript) Record of the form: // {"Operator": { "keyInRequestContext": "value" } } return { StringNotEqualsIfExists: { 'aws:PrincipalServiceName': 'cloudfront.amazonaws.com' } }; } } exports.CloudFrontOACReadAccessGenerator = CloudFrontOACReadAccessGenerator; _a = JSII_RTTI_SYMBOL_1; CloudFrontOACReadAccessGenerator[_a] = { fqn: "@k9securityio/k9-cdk.kms.CloudFrontOACReadAccessGenerator", version: "2.1.3" }; CloudFrontOACReadAccessGenerator.SID_ALLOW_CLOUDFRONT_SVC_READ_DATA = 'Allow CloudFront Service read-data'; CloudFrontOACReadAccessGenerator.SID_ALLOW_CLOUDFRONT_IAM_ROLE_READ_DATA = 'Allow CloudFront IAM role read-data'; function makeKeyPolicy(props) { const policyFactory = new k9policy_1.K9PolicyFactory(); const policy = new iam.PolicyDocument(); const resourceArns = ['*']; let accessSpecsByCapabilityRecs = policyFactory.mergeDesiredAccessSpecsByCapability(SUPPORTED_CAPABILITIES, props.k9DesiredAccess); let accessSpecsByCapability = new Map(); for (let [capabilityStr, accessSpec] of Object.entries(accessSpecsByCapabilityRecs)) { accessSpecsByCapability.set((0, k9policy_1.getAccessCapabilityFromValue)(capabilityStr), accessSpec); } if (!(0, k9policy_1.canPrincipalsManageResources)(accessSpecsByCapability)) { throw Error('At least one principal must be able to administer and read-config for keys' + ' so encrypted data remains accessible; found:\n' + `administer-resource: '${accessSpecsByCapability.get(k9policy_1.AccessCapability.ADMINISTER_RESOURCE)?.allowPrincipalArns}'\n` + `read-config: '${accessSpecsByCapability.get(k9policy_1.AccessCapability.READ_CONFIG)?.allowPrincipalArns}'`); } const allowStatements = policyFactory.makeAllowStatements('KMS', SUPPORTED_CAPABILITIES, Array.from(accessSpecsByCapability.values()), resourceArns); policy.addStatements(...allowStatements); if (props.awsServiceAccessGenerators) { for (let serviceAccessSpec of props.awsServiceAccessGenerators) { policy.addStatements(...serviceAccessSpec.makeAllowStatements()); } } //console.log(`trustAccountIdentities: ${props.trustAccountIdentities}`); // Allow root user and control access via Identity policy by aligning to Key's behavior: if (props.trustAccountIdentities) { //console.log('Adding Allow root and DenyEveryoneElse statements'); const denyEveryoneElseStatement = new aws_iam_1.PolicyStatement({ sid: exports.SID_DENY_EVERYONE_ELSE, effect: aws_iam_1.Effect.DENY, principals: policyFactory.makeDenyEveryoneElsePrincipals(), actions: ['kms:*'], resources: resourceArns, }); denyEveryoneElseStatement.addCondition('Bool', { 'aws:PrincipalIsAWSService': ['false'], 'kms:GrantIsForAWSResource': ['false'], }); const denyEveryoneElseTest = policyFactory.wasLikeUsed(props.k9DesiredAccess) ? 'ArnNotLike' : 'ArnNotEquals'; const allAllowedPrincipalArns = policyFactory.getAllowedPrincipalArns(props.k9DesiredAccess); const accountRootPrincipal = new aws_iam_1.AccountRootPrincipal(); denyEveryoneElseStatement.addCondition(denyEveryoneElseTest, { 'aws:PrincipalArn': [ // Place Root Principal arn in stable, prominent position; // will render as an object Fn::Join'ing Partition & AccountId accountRootPrincipal.arn, ...allAllowedPrincipalArns, ], }); policy.addStatements( // add AllowRootUserToAdministerKey statement and enable access granted via Identity policies new aws_iam_1.PolicyStatement({ sid: exports.SID_ALLOW_ROOT_AND_IDENTITY_POLICIES, effect: aws_iam_1.Effect.ALLOW, principals: [accountRootPrincipal], actions: ['kms:*'], resources: resourceArns, }), denyEveryoneElseStatement); } else { // Omit Allow Root & DenyEveryoneElse statement // // Instead, implement least privilege by relying on KMS' special behavior that // enables granting access solely via a KMS key policy, *irrespective of* Identity policy. // // See: https://docs.aws.amazon.com/kms/latest/developerguide/control-access-overview.html#managing-access // "To allow access to a KMS key, you must use the key policy, // *either alone* or in combination with IAM policies or grants. // IAM policies by themselves are not sufficient to allow access to a KMS key, // though you can use them in combination with a key policy." // //console.log('Omitting Allow root and DenyEveryoneElse statements'); } policy.validateForResourcePolicy(); return policy; } exports.makeKeyPolicy = makeKeyPolicy; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia21zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2ttcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDJDQUEyQztBQUMzQyxpREFPNkI7QUFDN0IseUNBT29CO0FBY3BCLElBQUksc0JBQXNCLEdBQUcsSUFBSSxLQUFLLENBQ3BDLDJCQUFnQixDQUFDLG1CQUFtQixFQUNwQywyQkFBZ0IsQ0FBQyxXQUFXLEVBQzVCLDJCQUFnQixDQUFDLFNBQVMsRUFDMUIsMkJBQWdCLENBQUMsVUFBVSxFQUMzQiwyQkFBZ0IsQ0FBQyxXQUFXLENBQzdCLENBQUM7QUFFVyxRQUFBLG9DQUFvQyxHQUFHLHlEQUF5RCxDQUFDO0FBQ2pHLFFBQUEsc0JBQXNCLEdBQUcsa0JBQWtCLENBQUM7QUFFekQ7OztHQUdHO0FBQ0gsTUFBYSxnQ0FBZ0M7SUFPM0MsWUFBWSxlQUF1QjtRQUNqQyxJQUFJLENBQUMsZUFBZSxHQUFHLGVBQWUsQ0FBQztJQUN6QyxDQUFDO0lBRUQsbUJBQW1CO1FBQ2pCLE9BQU8sQ0FBQyxJQUFJLHlCQUFlLENBQUM7Z0JBQzFCLEdBQUcsRUFBRSxnQ0FBZ0MsQ0FBQyxrQ0FBa0M7Z0JBQ3hFLE1BQU0sRUFBRSxnQkFBTSxDQUFDLEtBQUs7Z0JBQ3BCLFVBQVUsRUFBRSxDQUFDLElBQUksMEJBQWdCLENBQUMsMEJBQTBCLENBQUMsQ0FBQztnQkFDOUQsT0FBTyxFQUFFLENBQUMsYUFBYSxDQUFDO2dCQUN4QixTQUFTLEVBQUUsQ0FBQyxHQUFHLENBQUM7Z0JBQ2hCLFVBQVUsRUFBRTtvQkFDVixZQUFZLEVBQUUsRUFBRSxlQUFlLEVBQUUsSUFBSSxDQUFDLGVBQWUsRUFBRTtpQkFDeEQ7YUFDRixDQUFDO1lBQ0YsSUFBSSx5QkFBZSxDQUFDO2dCQUNsQixHQUFHLEVBQUUsZ0NBQWdDLENBQUMsdUNBQXVDO2dCQUM3RSxNQUFNLEVBQUUsZ0JBQU0sQ0FBQyxLQUFLO2dCQUNwQixVQUFVLEVBQUUsQ0FBQyxJQUFJLHNC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Q0FBQyx5QkFBeUIsRUFBRSxDQUFDO0lBRW5DLE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUE5RkQsc0NBOEZDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgaWFtIGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0IHtcbiAgQWNjb3VudFJvb3RQcmluY2lwYWwsIEFueVByaW5jaXBhbCxcbiAgQ29uZGl0aW9ucyxcbiAgRWZmZWN0LFxuICBQb2xpY3lEb2N1bWVudCxcbiAgUG9saWN5U3RhdGVtZW50LFxuICBTZXJ2aWNlUHJpbmNpcGFsLFxufSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcbmltcG9ydCB7XG4gIEFjY2Vzc0NhcGFiaWxpdHksXG4gIGNhblByaW5jaXBhbHNNYW5hZ2VSZXNvdXJjZXMsXG4gIGdldEFjY2Vzc0NhcGFiaWxpdHlGcm9tVmFsdWUsXG4gIElBY2Nlc3NTcGVjLFxuICBJQVdTU2VydmljZUFjY2Vzc0dlbmVyYXRvcixcbiAgSzlQb2xpY3lGYWN0b3J5LFxufSBmcm9tICcuL2s5cG9saWN5JztcblxuZXhwb3J0IGludGVyZmFjZSBLOUtleVBvbGljeVByb3BzIHtcbiAgcmVhZG9ubHkgazlEZXNpcmVkQWNjZXNzOiBBcnJheTxJQWNjZXNzU3BlYz47XG4gIHJlYWRvbmx5IHRydXN0QWNjb3VudElkZW50aXRpZXM/OiBib29sZWFuO1xuICAvKipcbiAgICogQW4gKG9wdGlvbmFsKSBhcnJheSBvZiBJQVdTU2VydmljZUFjY2Vzc0dlbmVyYXRvciBpbnN0YW5jZXMgd2hpY2ggd2lsbCBnZW5lcmF0ZSBzdGF0ZW1lbnRzIHRvIGFsbG93IGFjY2VzcyB0byB0aGVcbiAgICoga2V5IGJ5IGFuIEFXUyBzZXJ2aWNlIGxpa2UgQ2xvdWRGcm9udCBvciBLaW5lc2lzLlxuICAgKlxuICAgKiBAZGVmYXVsdCB1bmRlZmluZWRcbiAgICovXG4gIHJlYWRvbmx5IGF3c1NlcnZpY2VBY2Nlc3NHZW5lcmF0b3JzPzogQXJyYXk8SUFXU1NlcnZpY2VBY2Nlc3NHZW5lcmF0b3I+O1xufVxuXG5sZXQgU1VQUE9SVEVEX0NBUEFCSUxJVElFUyA9IG5ldyBBcnJheTxBY2Nlc3NDYXBhYmlsaXR5PihcbiAgQWNjZXNzQ2FwYWJpbGl0eS5BRE1JTklTVEVSX1JFU09VUkNFLFxuICBBY2Nlc3NDYXBhYmlsaXR5LlJFQURfQ09ORklHLFxuICBBY2Nlc3NDYXBhYmlsaXR5LlJFQURfREFUQSxcbiAgQWNjZXNzQ2FwYWJpbGl0eS5XUklURV9EQVRBLFxuICBBY2Nlc3NDYXBhYmlsaXR5LkRFTEVURV9EQVRBLFxuKTtcblxuZXhwb3J0IGNvbnN0IFNJRF9BTExPV19ST09UX0FORF9JREVOVElUWV9QT0xJQ0lFUyA9ICdBbGxvdyBSb290IFVzZXIgdG8gQWRtaW5pc3RlciBLZXkgQW5kIElkZW50aXR5IFBvbGljaWVzJztcbmV4cG9ydCBjb25zdCBTSURfREVOWV9FVkVSWU9ORV9FTFNFID0gJ0RlbnlFdmVyeW9uZUVsc2UnO1xuXG4vKipcbiAqIEdlbmVyYXRlIGtleSBwb2xpY3kgc3RhdGVtZW50cyB0byBlbmFibGUgdGhlIENsb3VkRnJvbnQgc2VydmljZSB0byByZWFkIGVuY3J5cHRlZCBTMyBidWNrZXQgb2JqZWN0IGRhdGEgKG9ubHkpXG4gKiBmcm9tIHdpdGhpbiBhIDxhIGhyZWY9XCJodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRGcm9udC9sYXRlc3QvRGV2ZWxvcGVyR3VpZGUvcHJpdmF0ZS1jb250ZW50LXJlc3RyaWN0aW5nLWFjY2Vzcy10by1zMy5odG1sI3NzZS1rbXNcIj5DbG91ZEZyb250IE9BQyBpbnRlZ3JhdGlvbjwvYT4uXG4gKi9cbmV4cG9ydCBjbGFzcyBDbG91ZEZyb250T0FDUmVhZEFjY2Vzc0dlbmVyYXRvciBpbXBsZW1lbnRzIElBV1NTZXJ2aWNlQWNjZXNzR2VuZXJhdG9yIHtcblxuICBzdGF0aWMgcmVhZG9ubHkgU0lEX0FMTE9XX0NMT1VERlJPTlRfU1ZDX1JFQURfREFUQSA9ICdBbGxvdyBDbG91ZEZyb250IFNlcnZpY2UgcmVhZC1kYXRhJztcbiAgc3RhdGljIHJlYWRvbmx5IFNJRF9BTExPV19DTE9VREZST05UX0lBTV9ST0xFX1JFQURfREFUQSA9ICdBbGxvdyBDbG91ZEZyb250IElBTSByb2xlIHJlYWQtZGF0YSc7XG5cbiAgcmVhZG9ubHkgZGlzdHJpYnV0aW9uQXJuOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3IoZGlzdHJpYnV0aW9uQXJuOiBzdHJpbmcpIHtcbiAgICB0aGlzLmRpc3RyaWJ1dGlvbkFybiA9IGRpc3RyaWJ1dGlvbkFybjtcbiAgfVxuXG4gIG1ha2VBbGxvd1N0YXRlbWVudHMoKTogQXJyYXk8UG9saWN5U3RhdGVtZW50PiB7XG4gICAgcmV0dXJuIFtuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIHNpZDogQ2xvdWRGcm9udE9BQ1JlYWRBY2Nlc3NHZW5lcmF0b3IuU0lEX0FMTE9XX0NMT1VERlJPTlRfU1ZDX1JFQURfREFUQSxcbiAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgcHJpbmNpcGFsczogW25ldyBTZXJ2aWNlUHJpbmNpcGFsKCdjbG91ZGZyb250LmFtYXpvbmF3cy5jb20nKV0sXG4gICAgICBhY3Rpb25zOiBbJ2ttczpEZWNyeXB0J10sXG4gICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgY29uZGl0aW9uczoge1xuICAgICAgICBTdHJpbmdFcXVhbHM6IHsgJ2F3czpTb3VyY2VBcm4nOiB0aGlzLmRpc3RyaWJ1dGlvbkFybiB9LFxuICAgICAgfSxcbiAgICB9KSxcbiAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIHNpZDogQ2xvdWRGcm9udE9BQ1JlYWRBY2Nlc3NHZW5lcmF0b3IuU0lEX0FMTE9XX0NMT1VERlJPTlRfSUFNX1JPTEVfUkVBRF9EQVRBLFxuICAgICAgZWZmZWN0OiBFZmZlY3QuQUxMT1csXG4gICAgICBwcmluY2lwYWxzOiBbbmV3IEFueVByaW5jaXBhbCgpXSxcbiAgICAgIGFjdGlvbnM6IFsna21zOkRlY3J5cHQnXSxcbiAgICAgIHJlc291cmNlczogWycqJ10sXG4gICAgICBjb25kaXRpb25zOiB7XG4gICAgICAgIC8vIHVzZSBBcm5FcXVhbHMgY29uZGl0aW9uIGluc3RlYWQgb2YgYSBwbGFpbiBQcmluY2lwYWwgZWxlbWVudCBpbiBjYXNlXG4gICAgICAgIC8vIHRoZSBDbG91ZEZyb250IHNlcnZpY2UgcmVjcmVhdGVzIHRoZSByb2xlLlxuICAgICAgICAvLyBjb25kaXRpb25zIGJpbmQgYWdhaW5zdCB0aGUgcHJpbmNpcGFsIEFSTiBhdCBydW50aW1lLlxuICAgICAgICAvLyB0aGUgcHJpbmNpcGFsIGVsZW1lbnQgYmluZHMgKG9uY2UpIHRvIHRoZSBwcmluY2lwYWwncyBjYW5vbmljYWwgdXNlcmlkIGF0IHBvbGljeSBkZWZpbml0aW9uIHRpbWUuXG4gICAgICAgIEFybkVxdWFsczoge1xuICAgICAgICAgICdhd3M6UHJpbmNpcGFsQXJuJzogJ2Fybjphd3M6aWFtOjo4NTYzNjkwNTMxODE6cm9sZS9PcmlnaW5BY2Nlc3NDb250cm9sUm9sZScsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pXTtcbiAgfVxuXG4gIG1ha2VDb25kaXRpb25zVG9FeGNlcHRGcm9tRGVueUV2ZXJ5b25lRWxzZSgpOiBDb25kaXRpb25zIHtcbiAgICAvLyByZXR1cm4gYSAoVHlwZVNjcmlwdCkgUmVjb3JkIG9mIHRoZSBmb3JtOlxuICAgIC8vICAgICB7XCJPcGVyYXRvclwiOiB7IFwia2V5SW5SZXF1ZXN0Q29udGV4dFwiOiBcInZhbHVlXCIgfSB9XG4gICAgcmV0dXJuIHsgU3RyaW5nTm90RXF1YWxzSWZFeGlzdHM6IHsgJ2F3czpQcmluY2lwYWxTZXJ2aWNlTmFtZSc6ICdjbG91ZGZyb250LmFtYXpvbmF3cy5jb20nIH0gfTtcbiAgfVxufVxuXG5cbmV4cG9ydCBmdW5jdGlvbiBtYWtlS2V5UG9saWN5KHByb3BzOiBLOUtleVBvbGljeVByb3BzKTogUG9saWN5RG9jdW1lbnQge1xuICBjb25zdCBwb2xpY3lGYWN0b3J5ID0gbmV3IEs5UG9saWN5RmFjdG9yeSgpO1xuICBjb25zdCBwb2xpY3kgPSBuZXcgaWFtLlBvbGljeURvY3VtZW50KCk7XG5cbiAgY29uc3QgcmVzb3VyY2VBcm5zID0gWycqJ107XG5cbiAgbGV0IGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5UmVjcyA9IHBvbGljeUZhY3RvcnkubWVyZ2VEZXNpcmVkQWNjZXNzU3BlY3NCeUNhcGFiaWxpdHkoU1VQUE9SVEVEX0NBUEFCSUxJVElFUywgcHJvcHMuazlEZXNpcmVkQWNjZXNzKTtcbiAgbGV0IGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5OiBNYXA8QWNjZXNzQ2FwYWJpbGl0eSwgSUFjY2Vzc1NwZWM+ID0gbmV3IE1hcCgpO1xuXG4gIGZvciAobGV0IFtjYXBhYmlsaXR5U3RyLCBhY2Nlc3NTcGVjXSBvZiBPYmplY3QuZW50cmllcyhhY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eVJlY3MpKSB7XG4gICAgYWNjZXNzU3BlY3NCeUNhcGFiaWxpdHkuc2V0KGdldEFjY2Vzc0NhcGFiaWxpdHlGcm9tVmFsdWUoY2FwYWJpbGl0eVN0ciksIGFjY2Vzc1NwZWMpO1xuICB9XG5cbiAgaWYgKCFjYW5QcmluY2lwYWxzTWFuYWdlUmVzb3VyY2VzKGFjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5KSkge1xuICAgIHRocm93IEVycm9yKCdBdCBsZWFzdCBvbmUgcHJpbmNpcGFsIG11c3QgYmUgYWJsZSB0byBhZG1pbmlzdGVyIGFuZCByZWFkLWNvbmZpZyBmb3Iga2V5cycgK1xuICAgICAgICAgICAgJyBzbyBlbmNyeXB0ZWQgZGF0YSByZW1haW5zIGFjY2Vzc2libGU7IGZvdW5kOlxcbicgK1xuICAgICAgICAgICAgYGFkbWluaXN0ZXItcmVzb3VyY2U6ICcke2FjY2Vzc1NwZWNzQnlDYXBhYmlsaXR5LmdldChBY2Nlc3NDYXBhYmlsaXR5LkFETUlOSVNURVJfUkVTT1VSQ0UpPy5hbGxvd1ByaW5jaXBhbEFybnN9J1xcbmAgK1xuICAgICAgICAgICAgYHJlYWQtY29uZmlnOiAnJHthY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eS5nZXQoQWNjZXNzQ2FwYWJpbGl0eS5SRUFEX0NPTkZJRyk/LmFsbG93UHJpbmNpcGFsQXJuc30nYCxcbiAgICApO1xuICB9XG5cbiAgY29uc3QgYWxsb3dTdGF0ZW1lbnRzID0gcG9saWN5RmFjdG9yeS5tYWtlQWxsb3dTdGF0ZW1lbnRzKCdLTVMnLFxuICAgIFNVUFBPUlRFRF9DQVBBQklMSVRJRVMsXG4gICAgQXJyYXkuZnJvbShhY2Nlc3NTcGVjc0J5Q2FwYWJpbGl0eS52YWx1ZXMoKSksXG4gICAgcmVzb3VyY2VBcm5zKTtcbiAgcG9saWN5LmFkZFN0YXRlbWVudHMoLi4uYWxsb3dTdGF0ZW1lbnRzKTtcblxuICBpZiAocHJvcHMuYXdzU2VydmljZUFjY2Vzc0dlbmVyYXRvcnMpIHtcbiAgICBmb3IgKGxldCBzZXJ2aWNlQWNjZXNzU3BlYyBvZiBwcm9wcy5hd3NTZXJ2aWNlQWNjZXNzR2VuZXJhdG9ycykge1xuICAgICAgcG9saWN5LmFkZFN0YXRlbWVudHMoLi4uc2VydmljZUFjY2Vzc1NwZWMubWFrZUFsbG93U3RhdGVtZW50cygpKTtcbiAgICB9XG4gIH1cblxuICAvL2NvbnNvbGUubG9nKGB0cnVzdEFjY291bnRJZGVudGl0aWVzOiAke3Byb3BzLnRydXN0QWNjb3VudElkZW50aXRpZXN9YCk7XG5cbiAgLy8gQWxsb3cgcm9vdCB1c2VyIGFuZCBjb250cm9sIGFjY2VzcyB2aWEgSWRlbnRpdHkgcG9saWN5IGJ5IGFsaWduaW5nIHRvIEtleSdzIGJlaGF2aW9yOlxuICBpZiAocHJvcHMudHJ1c3RBY2NvdW50SWRlbnRpdGllcykge1xuICAgIC8vY29uc29sZS5sb2coJ0FkZGluZyBBbGxvdyByb290IGFuZCBEZW55RXZlcnlvbmVFbHNlIHN0YXRlbWVudHMnKTtcbiAgICBjb25zdCBkZW55RXZlcnlvbmVFbHNlU3RhdGVtZW50ID0gbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICBzaWQ6IFNJRF9ERU5ZX0VWRVJZT05FX0VMU0UsXG4gICAgICBlZmZlY3Q6IEVmZmVjdC5ERU5ZLFxuICAgICAgcHJpbmNpcGFsczogcG9saWN5RmFjdG9yeS5tYWtlRGVueUV2ZXJ5b25lRWxzZVByaW5jaXBhbHMoKSxcbiAgICAgIGFjdGlvbnM6IFsna21zOionXSxcbiAgICAgIHJlc291cmNlczogcmVzb3VyY2VBcm5zLFxuICAgIH0pO1xuICAgIGRlbnlFdmVyeW9uZUVsc2VTdGF0ZW1lbnQuYWRkQ29uZGl0aW9uKCdCb29sJywge1xuICAgICAgJ2F3czpQcmluY2lwYWxJc0FXU1NlcnZpY2UnOiBbJ2ZhbHNlJ10sXG4gICAgICAna21zOkdyYW50SXNGb3JBV1NSZXNvdXJjZSc6IFsnZmFsc2UnXSxcbiAgICB9KTtcbiAgICBjb25zdCBkZW55RXZlcnlvbmVFbHNlVGVzdCA9IHBvbGljeUZhY3Rvcnkud2FzTGlrZVVzZWQocHJvcHMuazlEZXNpcmVkQWNjZXNzKSA/XG4gICAgICAnQXJuTm90TGlrZScgOlxuICAgICAgJ0Fybk5vdEVxdWFscyc7XG4gICAgY29uc3QgYWxsQWxsb3dlZFByaW5jaXBhbEFybnMgPSBwb2xpY3lGYWN0b3J5LmdldEFsbG93ZWRQcmluY2lwYWxBcm5zKHByb3BzLms5RGVzaXJlZEFjY2Vzcyk7XG4gICAgY29uc3QgYWNjb3VudFJvb3RQcmluY2lwYWwgPSBuZXcgQWNjb3VudFJvb3RQcmluY2lwYWwoKTtcbiAgICBkZW55RXZlcnlvbmVFbHNlU3RhdGVtZW50LmFkZENvbmRpdGlvbihkZW55RXZlcnlvbmVFbHNlVGVzdCwge1xuICAgICAgJ2F3czpQcmluY2lwYWxBcm4nOiBbXG4gICAgICAgIC8vIFBsYWNlIFJvb3QgUHJpbmNpcGFsIGFybiBpbiBzdGFibGUsIHByb21pbmVudCBwb3NpdGlvbjtcbiAgICAgICAgLy8gd2lsbCByZW5kZXIgYXMgYW4gb2JqZWN0IEZuOjpKb2luJ2luZyBQYXJ0aXRpb24gJiBBY2NvdW50SWRcbiAgICAgICAgYWNjb3VudFJvb3RQcmluY2lwYWwuYXJuLFxuICAgICAgICAuLi5hbGxBbGxvd2VkUHJpbmNpcGFsQXJucyxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBwb2xpY3kuYWRkU3RhdGVtZW50cyhcbiAgICAgIC8vIGFkZCBBbGxvd1Jvb3RVc2VyVG9BZG1pbmlzdGVyS2V5IHN0YXRlbWVudCBhbmQgZW5hYmxlIGFjY2VzcyBncmFudGVkIHZpYSBJZGVudGl0eSBwb2xpY2llc1xuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIHNpZDogU0lEX0FMTE9XX1JPT1RfQU5EX0lERU5USVRZX1BPTElDSUVTLFxuICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgcHJpbmNpcGFsczogW2FjY291bnRSb290UHJpbmNpcGFsXSxcbiAgICAgICAgYWN0aW9uczogWydrbXM6KiddLFxuICAgICAgICByZXNvdXJjZXM6IHJlc291cmNlQXJucyxcbiAgICAgIH0pXG4gICAgICAsIGRlbnlFdmVyeW9uZUVsc2VTdGF0ZW1lbnQsXG4gICAgKTtcbiAgfSBlbHNlIHtcblxuICAgIC8vIE9taXQgQWxsb3cgUm9vdCAmIERlbnlFdmVyeW9uZUVsc2Ugc3RhdGVtZW50XG4gICAgLy9cbiAgICAvLyBJbnN0ZWFkLCBpbXBsZW1lbnQgbGVhc3QgcHJpdmlsZWdlIGJ5IHJlbHlpbmcgb24gS01TJyBzcGVjaWFsIGJlaGF2aW9yIHRoYXRcbiAgICAvLyBlbmFibGVzIGdyYW50aW5nIGFjY2VzcyBzb2xlbHkgdmlhIGEgS01TIGtleSBwb2xpY3ksICppcnJlc3BlY3RpdmUgb2YqIElkZW50aXR5IHBvbGljeS5cbiAgICAvL1xuICAgIC8vIFNlZTogaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2ttcy9sYXRlc3QvZGV2ZWxvcGVyZ3VpZGUvY29udHJvbC1hY2Nlc3Mtb3ZlcnZpZXcuaHRtbCNtYW5hZ2luZy1hY2Nlc3NcbiAgICAvLyBcIlRvIGFsbG93IGFjY2VzcyB0byBhIEtNUyBrZXksIHlvdSBtdXN0IHVzZSB0aGUga2V5IHBvbGljeSxcbiAgICAvLyAgKmVpdGhlciBhbG9uZSogb3IgaW4gY29tYmluYXRpb24gd2l0aCBJQU0gcG9saWNpZXMgb3IgZ3JhbnRzLlxuICAgIC8vICBJQU0gcG9saWNpZXMgYnkgdGhlbXNlbHZlcyBhcmUgbm90IHN1ZmZpY2llbnQgdG8gYWxsb3cgYWNjZXNzIHRvIGEgS01TIGtleSxcbiAgICAvLyAgdGhvdWdoIHlvdSBjYW4gdXNlIHRoZW0gaW4gY29tYmluYXRpb24gd2l0aCBhIGtleSBwb2xpY3kuXCJcbiAgICAvL1xuXG4gICAgLy9jb25zb2xlLmxvZygnT21pdHRpbmcgQWxsb3cgcm9vdCBhbmQgRGVueUV2ZXJ5b25lRWxzZSBzdGF0ZW1lbnRzJyk7XG4gIH1cblxuICBwb2xpY3kudmFsaWRhdGVGb3JSZXNvdXJjZVBvbGljeSgpO1xuXG4gIHJldHVybiBwb2xpY3k7XG59XG4iXX0=