UNPKG

cdk-encrypted-secret

Version:

CDK Construct that creates an AWS Secret Manager Secret and sets the value from an encrypted Ciphertext.

130 lines 19.1 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.EncryptedSecret = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const crypto = require("crypto"); const path = require("path"); const util_arn_parser_1 = require("@aws-sdk/util-arn-parser"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const aws_iam_1 = require("aws-cdk-lib/aws-iam"); const aws_lambda_1 = require("aws-cdk-lib/aws-lambda"); const aws_logs_1 = require("aws-cdk-lib/aws-logs"); const aws_secretsmanager_1 = require("aws-cdk-lib/aws-secretsmanager"); const custom_resources_1 = require("aws-cdk-lib/custom-resources"); const constructs_1 = require("constructs"); /** * EncryptedSecret is a custom construct that creates a Secret in Secrets Manager and decrypts the ciphertext * using the KMS Key ARN provided and stores the decrypted value in the Secret. * * @class EncryptedSecret * @extends {Construct} * @param {Construct} scope - The scope of the construct. * @param {string} id - The id of the construct. * @param {EncryptedSecretProps} props - The EncryptedSecretProps for the EncryptedSecret construct. */ class EncryptedSecret extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); // Ensure keyId is valid if (!(0, util_arn_parser_1.validate)(props.keyId)) { throw new Error('Invalid keyId.'); } // Parse keyId as ARN const kmsKey = (0, util_arn_parser_1.parse)(props.keyId); // Ensure ciphertextBlob is non-empty if (!props.ciphertextBlob.length) { throw new Error('ciphertextBlob cannot be empty'); } if (props.existingSecretObj) { // If existingSecretObj is provided, use it this.secret = props.existingSecretObj; } else { // create a secret with the secretProps provided this.secret = new aws_secretsmanager_1.Secret(this, 'Secrets', props.secretProps); } // Create the Lambda Function to decrypt the ciphertext and store the value in the Secret const decryptSecretFunction = new aws_lambda_1.SingletonFunction(this, 'DecryptSecretFunction', { lambdaPurpose: 'DecryptSecret', uuid: crypto.createHash('md5').update(aws_cdk_lib_1.Stack.of(this).environment).digest('hex'), runtime: aws_lambda_1.Runtime.NODEJS_22_X, architecture: aws_lambda_1.Architecture.ARM_64, code: aws_lambda_1.Code.fromAsset(path.join(__dirname, 'lambda')), handler: 'index.handler', memorySize: 128, environment: { KMS_KEY_REGION: kmsKey.region, }, logGroup: new aws_logs_1.LogGroup(this, 'DecryptSecretFunctionLogGroup', { removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY, retention: props.logRetentionDays ?? aws_logs_1.RetentionDays.ONE_WEEK, }), }); // Add to the Policy Statement the ability to decrypt the cipherText with KMS against the kmsKeyArn in the props decryptSecretFunction.addToRolePolicy(new aws_iam_1.PolicyStatement({ actions: ['kms:Decrypt'], resources: [props.keyId], })); // Add to the Policy Statement the ability to put the secret value into Secrets Manager decryptSecretFunction.addToRolePolicy(new aws_iam_1.PolicyStatement({ actions: ['secretsmanager:PutSecretValue'], resources: [this.secret.secretArn], })); if (this.secret.encryptionKey) { // Add to the Lambda Function Policy Statement the ability to encrypt using the encryption key of the secret decryptSecretFunction.addToRolePolicy(new aws_iam_1.PolicyStatement({ actions: ['kms:Encrypt'], resources: [this.secret.encryptionKey.keyArn], })); // Modify Key Policy to allow the Lambda to use the KMS Key to encrypt the Secret this.secret.encryptionKey.grantEncrypt(decryptSecretFunction); } // Create the custom resource const lambdaInvokeAwsCustomResource = new custom_resources_1.AwsCustomResource(this, 'CustomResourceSecretLambdaInvoke', { onCreate: { service: 'Lambda', action: 'invoke', parameters: { FunctionName: decryptSecretFunction.functionName, Payload: '{"secretArn": "' + this.secret.secretArn + '","keyId": "' + props.keyId + '", "cipherText": "' + props.ciphertextBlob + '"}', }, physicalResourceId: custom_resources_1.PhysicalResourceId.of('CustomResourceSecretLambdaInvoke'), }, onUpdate: { service: 'Lambda', action: 'invoke', parameters: { FunctionName: decryptSecretFunction.functionName, Payload: '{"secretArn": "' + this.secret.secretArn + '","keyId": "' + props.keyId + '", "cipherText": "' + props.ciphertextBlob + '"}', }, physicalResourceId: custom_resources_1.PhysicalResourceId.of('CustomResourceSecretLambdaInvoke'), }, policy: custom_resources_1.AwsCustomResourcePolicy.fromSdkCalls({ resources: [decryptSecretFunction.functionArn], }), logGroup: new aws_logs_1.LogGroup(this, 'CustomResourceSecretLambdaInvokeLogGroup', { removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY, retention: props.logRetentionDays ?? aws_logs_1.RetentionDays.ONE_WEEK, }), }); // Grant the Lambda Invoke permissions to the lambdaInvoke custom resource decryptSecretFunction.grantInvoke(lambdaInvokeAwsCustomResource); } } exports.EncryptedSecret = EncryptedSecret; _a = JSII_RTTI_SYMBOL_1; EncryptedSecret[_a] = { fqn: "cdk-encrypted-secret.EncryptedSecret", version: "1.3.8" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxpQ0FBaUM7QUFDakMsNkJBQTZCO0FBQzdCLDhEQUFnRTtBQUNoRSw2Q0FBbUQ7QUFDbkQsaURBQXNEO0FBQ3RELHVEQUF3RjtBQUN4RixtREFBK0Q7QUFDL0QsdUVBQXFFO0FBQ3JFLG1FQUE4RztBQUM5RywyQ0FBdUM7QUFvQnZDOzs7Ozs7Ozs7R0FTRztBQUNILE1BQWEsZUFBZ0IsU0FBUSxzQkFBUztJQUU1QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQTJCO1FBQ25FLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsd0JBQXdCO1FBQ3hCLElBQUksQ0FBQyxJQUFBLDBCQUFRLEVBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3BDLENBQUM7UUFDRCxxQkFBcUI7UUFDckIsTUFBTSxNQUFNLEdBQVEsSUFBQSx1QkFBSyxFQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUV2QyxxQ0FBcUM7UUFDckMsSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDakMsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFFRCxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQzVCLDJDQUEyQztZQUMzQyxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQztRQUN4QyxDQUFDO2FBQU0sQ0FBQztZQUNOLGdEQUFnRDtZQUNoRCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksMkJBQU0sQ0FBQyxJQUFJLEVBQUUsU0FBUyxFQUFFLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUMvRCxDQUFDO1FBRUQseUZBQXlGO1FBQ3pGLE1BQU0scUJBQXFCLEdBQUcsSUFBSSw4QkFBaUIsQ0FBQyxJQUFJLEVBQUUsdUJBQXVCLEVBQUU7WUFDakYsYUFBYSxFQUFFLGVBQWU7WUFDOUIsSUFBSSxFQUFFLE1BQU0sQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLG1CQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUM7WUFDL0UsT0FBTyxFQUFFLG9CQUFPLENBQUMsV0FBVztZQUM1QixZQUFZLEVBQUUseUJBQVksQ0FBQyxNQUFNO1lBQ2pDLElBQUksRUFBRSxpQkFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUNwRCxPQUFPLEVBQUUsZUFBZTtZQUN4QixVQUFVLEVBQUUsR0FBRztZQUNmLFdBQVcsRUFBRTtnQkFDWCxjQUFjLEVBQUUsTUFBTSxDQUFDLE1BQU07YUFDOUI7WUFDRCxRQUFRLEVBQUUsSUFBSSxtQkFBUSxDQUFDLElBQUksRUFBRSwrQkFBK0IsRUFBRTtnQkFDNUQsYUFBYSxFQUFFLDJCQUFhLENBQUMsT0FBTztnQkFDcEMsU0FBUyxFQUFFLEtBQUssQ0FBQyxnQkFBZ0IsSUFBSSx3QkFBYSxDQUFDLFFBQVE7YUFDNUQsQ0FBQztTQUNILENBQUMsQ0FBQztRQUVILGdIQUFnSDtRQUNoSCxxQkFBcUIsQ0FBQyxlQUFlLENBQ25DLElBQUkseUJBQWUsQ0FBQztZQUNsQixPQUFPLEVBQUUsQ0FBQyxhQUFhLENBQUM7WUFDeEIsU0FBUyxFQUFFLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztTQUN6QixDQUFDLENBQ0gsQ0FBQztRQUVGLHVGQUF1RjtRQUN2RixxQkFBcUIsQ0FBQyxlQUFlLENBQ25DLElBQUkseUJBQWUsQ0FBQztZQUNsQixPQUFPLEVBQUUsQ0FBQywrQkFBK0IsQ0FBQztZQUMxQyxTQUFTLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQztTQUNuQyxDQUFDLENBQ0gsQ0FBQztRQUVGLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUM5Qiw0R0FBNEc7WUFDNUcscUJBQXFCLENBQUMsZUFBZSxDQUNuQyxJQUFJLHlCQUFlLENBQUM7Z0JBQ2xCLE9BQU8sRUFBRSxDQUFDLGFBQWEsQ0FBQztnQkFDeEIsU0FBUyxFQUFFLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDO2FBQzlDLENBQUMsQ0FDSCxDQUFDO1lBRUYsaUZBQWlGO1lBQ2pGLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1FBQ2hFLENBQUM7UUFFRCw2QkFBNkI7UUFDN0IsTUFBTSw2QkFBNkIsR0FBRyxJQUFJLG9DQUFpQixDQUFDLElBQUksRUFBRSxrQ0FBa0MsRUFBRTtZQUNwRyxRQUFRLEVBQUU7Z0JBQ1IsT0FBTyxFQUFFLFFBQVE7Z0JBQ2pCLE1BQU0sRUFBRSxRQUFRO2dCQUNoQixVQUFVLEVBQUU7b0JBQ1YsWUFBWSxFQUFFLHFCQUFxQixDQUFDLFlBQVk7b0JBQ2hELE9BQU8sRUFDTCxpQkFBaUI7d0JBQ2pCLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUzt3QkFDckIsY0FBYzt3QkFDZCxLQUFLLENBQUMsS0FBSzt3QkFDWCxvQkFBb0I7d0JBQ3BCLEtBQUssQ0FBQyxjQUFjO3dCQUNwQixJQUFJO2lCQUNQO2dCQUNELGtCQUFrQixFQUFFLHFDQUFrQixDQUFDLEVBQUUsQ0FBQyxrQ0FBa0MsQ0FBQzthQUM5RTtZQUNELFFBQVEsRUFBRTtnQkFDUixPQUFPLEVBQUUsUUFBUTtnQkFDakIsTUFBTSxFQUFFLFFBQVE7Z0JBQ2hCLFVBQVUsRUFBRTtvQkFDVixZQUFZLEVBQUUscUJBQXFCLENBQUMsWUFBWTtvQkFDaEQsT0FBTyxFQUNMLGlCQUFpQjt3QkFDakIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTO3dCQUNyQixjQUFjO3dCQUNkLEtBQUssQ0FBQyxLQUFLO3dCQUNYLG9CQUFvQjt3QkFDcEIsS0FBSyxDQUFDLGNBQWM7d0JBQ3BCLElBQUk7aUJBQ1A7Z0JBQ0Qsa0JBQWtCLEVBQUUscUNBQWtCLENBQUMsRUFBRSxDQUFDLGtDQUFrQyxDQUFDO2FBQzlFO1lBQ0QsTUFBTSxFQUFFLDBDQUF1QixDQUFDLFlBQVksQ0FBQztnQkFDM0MsU0FBUyxFQUFFLENBQUMscUJBQXFCLENBQUMsV0FBVyxDQUFDO2FBQy9DLENBQUM7WUFDRixRQUFRLEVBQUUsSUFBSSxtQkFBUSxDQUFDLElBQUksRUFBRSwwQ0FBMEMsRUFBRTtnQkFDdkUsYUFBYSxFQUFFLDJCQUFhLENBQUMsT0FBTztnQkFDcEMsU0FBUyxFQUFFLEtBQUssQ0FBQyxnQkFBZ0IsSUFBSSx3QkFBYSxDQUFDLFFBQVE7YUFDNUQsQ0FBQztTQUNILENBQUMsQ0FBQztRQUVILDBFQUEwRTtRQUMxRSxxQkFBcUIsQ0FBQyxXQUFXLENBQUMsNkJBQTZCLENBQUMsQ0FBQztJQUNuRSxDQUFDOztBQXJISCwwQ0FzSEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjcnlwdG8gZnJvbSAnY3J5cHRvJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBBUk4sIHBhcnNlLCB2YWxpZGF0ZSB9IGZyb20gJ0Bhd3Mtc2RrL3V0aWwtYXJuLXBhcnNlcic7XG5pbXBvcnQgeyBSZW1vdmFsUG9saWN5LCBTdGFjayB9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IFBvbGljeVN0YXRlbWVudCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0IHsgQXJjaGl0ZWN0dXJlLCBDb2RlLCBSdW50aW1lLCBTaW5nbGV0b25GdW5jdGlvbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgTG9nR3JvdXAsIFJldGVudGlvbkRheXMgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbG9ncyc7XG5pbXBvcnQgeyBTZWNyZXQsIFNlY3JldFByb3BzIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXNlY3JldHNtYW5hZ2VyJztcbmltcG9ydCB7IEF3c0N1c3RvbVJlc291cmNlLCBBd3NDdXN0b21SZXNvdXJjZVBvbGljeSwgUGh5c2ljYWxSZXNvdXJjZUlkIH0gZnJvbSAnYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlcyc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcblxuLyoqXG4gKiBFbmNyeXB0ZWRTZWNyZXRQcm9wcyBkZWZpbmVzIHRoZSBwcm9wZXJ0aWVzIGZvciB0aGUgRW5jcnlwdGVkU2VjcmV0IGNvbnN0cnVjdC5cbiAqXG4gKiBAaW50ZXJmYWNlIEVuY3J5cHRlZFNlY3JldFByb3BzXG4gKiBAcHJvcGVydHkge1NlY3JldFByb3BzfSBbc2VjcmV0UHJvcHNdIC0gVGhlIFNlY3JldFByb3BzIGZvciB0aGUgU2VjcmV0IHRvIGJlIGNyZWF0ZWQgYW5kIHNldCB0aGUgZGVjcnlwdGVkIHZhbHVlIGluLlxuICogQHByb3BlcnR5IHtTZWNyZXR9IFtleGlzdGluZ1NlY3JldE9ial0gLSBUaGUgZXhpc3RpbmcgU2VjcmV0IHRvIGJlIHVzZWQgdG8gc2V0IHRoZSBkZWNyeXB0ZWQgdmFsdWUgaW4uXG4gKiBAcHJvcGVydHkge3N0cmluZ30gY2lwaGVydGV4dEJsb2IgLSBUaGUgY2lwaGVydGV4dCB0byBiZSBkZWNyeXB0ZWQgYW5kIHN0b3JlZCBpbiB0aGUgU2VjcmV0LlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGtleUlkIC0gVGhlIEtNUyBLZXkgQVJOIHRvIGJlIHVzZWQgdG8gZGVjcnlwdCB0aGUgY2lwaGVydGV4dC5cbiAqIEBwcm9wZXJ0eSB7UmV0ZW50aW9uRGF5c30gW2xvZ1JldGVudGlvbkRheXNdIC0gVGhlIHJldGVudGlvbiBkYXlzIGZvciB0aGUgbG9nIGdyb3VwIChvcHRpb25hbCwgZGVmYXVsdCBpcyBPTkVfV0VFSykuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRW5jcnlwdGVkU2VjcmV0UHJvcHMge1xuICByZWFkb25seSBzZWNyZXRQcm9wcz86IFNlY3JldFByb3BzO1xuICByZWFkb25seSBleGlzdGluZ1NlY3JldE9iaj86IFNlY3JldDtcbiAgcmVhZG9ubHkgY2lwaGVydGV4dEJsb2I6IHN0cmluZztcbiAgcmVhZG9ubHkga2V5SWQ6IHN0cmluZztcbiAgcmVhZG9ubHkgbG9nUmV0ZW50aW9uRGF5cz86IFJldGVudGlvbkRheXM7XG59XG5cbi8qKlxuICogRW5jcnlwdGVkU2VjcmV0IGlzIGEgY3VzdG9tIGNvbnN0cnVjdCB0aGF0IGNyZWF0ZXMgYSBTZWNyZXQgaW4gU2VjcmV0cyBNYW5hZ2VyIGFuZCBkZWNyeXB0cyB0aGUgY2lwaGVydGV4dFxuICogdXNpbmcgdGhlIEtNUyBLZXkgQVJOIHByb3ZpZGVkIGFuZCBzdG9yZXMgdGhlIGRlY3J5cHRlZCB2YWx1ZSBpbiB0aGUgU2VjcmV0LlxuICpcbiAqIEBjbGFzcyBFbmNyeXB0ZWRTZWNyZXRcbiAqIEBleHRlbmRzIHtDb25zdHJ1Y3R9XG4gKiBAcGFyYW0ge0NvbnN0cnVjdH0gc2NvcGUgLSBUaGUgc2NvcGUgb2YgdGhlIGNvbnN0cnVjdC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBpZCAtIFRoZSBpZCBvZiB0aGUgY29uc3RydWN0LlxuICogQHBhcmFtIHtFbmNyeXB0ZWRTZWNyZXRQcm9wc30gcHJvcHMgLSBUaGUgRW5jcnlwdGVkU2VjcmV0UHJvcHMgZm9yIHRoZSBFbmNyeXB0ZWRTZWNyZXQgY29uc3RydWN0LlxuICovXG5leHBvcnQgY2xhc3MgRW5jcnlwdGVkU2VjcmV0IGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgcHVibGljIHNlY3JldDogU2VjcmV0O1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogRW5jcnlwdGVkU2VjcmV0UHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgLy8gRW5zdXJlIGtleUlkIGlzIHZhbGlkXG4gICAgaWYgKCF2YWxpZGF0ZShwcm9wcy5rZXlJZCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBrZXlJZC4nKTtcbiAgICB9XG4gICAgLy8gUGFyc2Uga2V5SWQgYXMgQVJOXG4gICAgY29uc3Qga21zS2V5OiBBUk4gPSBwYXJzZShwcm9wcy5rZXlJZCk7XG5cbiAgICAvLyBFbnN1cmUgY2lwaGVydGV4dEJsb2IgaXMgbm9uLWVtcHR5XG4gICAgaWYgKCFwcm9wcy5jaXBoZXJ0ZXh0QmxvYi5sZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY2lwaGVydGV4dEJsb2IgY2Fubm90IGJlIGVtcHR5Jyk7XG4gICAgfVxuXG4gICAgaWYgKHByb3BzLmV4aXN0aW5nU2VjcmV0T2JqKSB7XG4gICAgICAvLyBJZiBleGlzdGluZ1NlY3JldE9iaiBpcyBwcm92aWRlZCwgdXNlIGl0XG4gICAgICB0aGlzLnNlY3JldCA9IHByb3BzLmV4aXN0aW5nU2VjcmV0T2JqO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBjcmVhdGUgYSBzZWNyZXQgd2l0aCB0aGUgc2VjcmV0UHJvcHMgcHJvdmlkZWRcbiAgICAgIHRoaXMuc2VjcmV0ID0gbmV3IFNlY3JldCh0aGlzLCAnU2VjcmV0cycsIHByb3BzLnNlY3JldFByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgdGhlIExhbWJkYSBGdW5jdGlvbiB0byBkZWNyeXB0IHRoZSBjaXBoZXJ0ZXh0IGFuZCBzdG9yZSB0aGUgdmFsdWUgaW4gdGhlIFNlY3JldFxuICAgIGNvbnN0IGRlY3J5cHRTZWNyZXRGdW5jdGlvbiA9IG5ldyBTaW5nbGV0b25GdW5jdGlvbih0aGlzLCAnRGVjcnlwdFNlY3JldEZ1bmN0aW9uJywge1xuICAgICAgbGFtYmRhUHVycG9zZTogJ0RlY3J5cHRTZWNyZXQnLFxuICAgICAgdXVpZDogY3J5cHRvLmNyZWF0ZUhhc2goJ21kNScpLnVwZGF0ZShTdGFjay5vZih0aGlzKS5lbnZpcm9ubWVudCkuZGlnZXN0KCdoZXgnKSxcbiAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTXzIyX1gsXG4gICAgICBhcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZS5BUk1fNjQsXG4gICAgICBjb2RlOiBDb2RlLmZyb21Bc3NldChwYXRoLmpvaW4oX19kaXJuYW1lLCAnbGFtYmRhJykpLFxuICAgICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInLFxuICAgICAgbWVtb3J5U2l6ZTogMTI4LFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgS01TX0tFWV9SRUdJT046IGttc0tleS5yZWdpb24sXG4gICAgICB9LFxuICAgICAgbG9nR3JvdXA6IG5ldyBMb2dHcm91cCh0aGlzLCAnRGVjcnlwdFNlY3JldEZ1bmN0aW9uTG9nR3JvdXAnLCB7XG4gICAgICAgIHJlbW92YWxQb2xpY3k6IFJlbW92YWxQb2xpY3kuREVTVFJPWSxcbiAgICAgICAgcmV0ZW50aW9uOiBwcm9wcy5sb2dSZXRlbnRpb25EYXlzID8/IFJldGVudGlvbkRheXMuT05FX1dFRUssXG4gICAgICB9KSxcbiAgICB9KTtcblxuICAgIC8vIEFkZCB0byB0aGUgUG9saWN5IFN0YXRlbWVudCB0aGUgYWJpbGl0eSB0byBkZWNyeXB0IHRoZSBjaXBoZXJUZXh0IHdpdGggS01TIGFnYWluc3QgdGhlIGttc0tleUFybiBpbiB0aGUgcHJvcHNcbiAgICBkZWNyeXB0U2VjcmV0RnVuY3Rpb24uYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGFjdGlvbnM6IFsna21zOkRlY3J5cHQnXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbcHJvcHMua2V5SWRdLFxuICAgICAgfSksXG4gICAgKTtcblxuICAgIC8vIEFkZCB0byB0aGUgUG9saWN5IFN0YXRlbWVudCB0aGUgYWJpbGl0eSB0byBwdXQgdGhlIHNlY3JldCB2YWx1ZSBpbnRvIFNlY3JldHMgTWFuYWdlclxuICAgIGRlY3J5cHRTZWNyZXRGdW5jdGlvbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgYWN0aW9uczogWydzZWNyZXRzbWFuYWdlcjpQdXRTZWNyZXRWYWx1ZSddLFxuICAgICAgICByZXNvdXJjZXM6IFt0aGlzLnNlY3JldC5zZWNyZXRBcm5dLFxuICAgICAgfSksXG4gICAgKTtcblxuICAgIGlmICh0aGlzLnNlY3JldC5lbmNyeXB0aW9uS2V5KSB7XG4gICAgICAvLyBBZGQgdG8gdGhlIExhbWJkYSBGdW5jdGlvbiBQb2xpY3kgU3RhdGVtZW50IHRoZSBhYmlsaXR5IHRvIGVuY3J5cHQgdXNpbmcgdGhlIGVuY3J5cHRpb24ga2V5IG9mIHRoZSBzZWNyZXRcbiAgICAgIGRlY3J5cHRTZWNyZXRGdW5jdGlvbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGFjdGlvbnM6IFsna21zOkVuY3J5cHQnXSxcbiAgICAgICAgICByZXNvdXJjZXM6IFt0aGlzLnNlY3JldC5lbmNyeXB0aW9uS2V5LmtleUFybl0sXG4gICAgICAgIH0pLFxuICAgICAgKTtcblxuICAgICAgLy8gTW9kaWZ5IEtleSBQb2xpY3kgdG8gYWxsb3cgdGhlIExhbWJkYSB0byB1c2UgdGhlIEtNUyBLZXkgdG8gZW5jcnlwdCB0aGUgU2VjcmV0XG4gICAgICB0aGlzLnNlY3JldC5lbmNyeXB0aW9uS2V5LmdyYW50RW5jcnlwdChkZWNyeXB0U2VjcmV0RnVuY3Rpb24pO1xuICAgIH1cblxuICAgIC8vIENyZWF0ZSB0aGUgY3VzdG9tIHJlc291cmNlXG4gICAgY29uc3QgbGFtYmRhSW52b2tlQXdzQ3VzdG9tUmVzb3VyY2UgPSBuZXcgQXdzQ3VzdG9tUmVzb3VyY2UodGhpcywgJ0N1c3RvbVJlc291cmNlU2VjcmV0TGFtYmRhSW52b2tlJywge1xuICAgICAgb25DcmVhdGU6IHtcbiAgICAgICAgc2VydmljZTogJ0xhbWJkYScsXG4gICAgICAgIGFjdGlvbjogJ2ludm9rZScsXG4gICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICBGdW5jdGlvbk5hbWU6IGRlY3J5cHRTZWNyZXRGdW5jdGlvbi5mdW5jdGlvbk5hbWUsXG4gICAgICAgICAgUGF5bG9hZDpcbiAgICAgICAgICAgICd7XCJzZWNyZXRBcm5cIjogXCInICtcbiAgICAgICAgICAgIHRoaXMuc2VjcmV0LnNlY3JldEFybiArXG4gICAgICAgICAgICAnXCIsXCJrZXlJZFwiOiBcIicgK1xuICAgICAgICAgICAgcHJvcHMua2V5SWQgK1xuICAgICAgICAgICAgJ1wiLCBcImNpcGhlclRleHRcIjogXCInICtcbiAgICAgICAgICAgIHByb3BzLmNpcGhlcnRleHRCbG9iICtcbiAgICAgICAgICAgICdcIn0nLFxuICAgICAgICB9LFxuICAgICAgICBwaHlzaWNhbFJlc291cmNlSWQ6IFBoeXNpY2FsUmVzb3VyY2VJZC5vZignQ3VzdG9tUmVzb3VyY2VTZWNyZXRMYW1iZGFJbnZva2UnKSxcbiAgICAgIH0sXG4gICAgICBvblVwZGF0ZToge1xuICAgICAgICBzZXJ2aWNlOiAnTGFtYmRhJyxcbiAgICAgICAgYWN0aW9uOiAnaW52b2tlJyxcbiAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgIEZ1bmN0aW9uTmFtZTogZGVjcnlwdFNlY3JldEZ1bmN0aW9uLmZ1bmN0aW9uTmFtZSxcbiAgICAgICAgICBQYXlsb2FkOlxuICAgICAgICAgICAgJ3tcInNlY3JldEFyblwiOiBcIicgK1xuICAgICAgICAgICAgdGhpcy5zZWNyZXQuc2VjcmV0QXJuICtcbiAgICAgICAgICAgICdcIixcImtleUlkXCI6IFwiJyArXG4gICAgICAgICAgICBwcm9wcy5rZXlJZCArXG4gICAgICAgICAgICAnXCIsIFwiY2lwaGVyVGV4dFwiOiBcIicgK1xuICAgICAgICAgICAgcHJvcHMuY2lwaGVydGV4dEJsb2IgK1xuICAgICAgICAgICAgJ1wifScsXG4gICAgICAgIH0sXG4gICAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogUGh5c2ljYWxSZXNvdXJjZUlkLm9mKCdDdXN0b21SZXNvdXJjZVNlY3JldExhbWJkYUludm9rZScpLFxuICAgICAgfSxcbiAgICAgIHBvbGljeTogQXdzQ3VzdG9tUmVzb3VyY2VQb2xpY3kuZnJvbVNka0NhbGxzKHtcbiAgICAgICAgcmVzb3VyY2VzOiBbZGVjcnlwdFNlY3JldEZ1bmN0aW9uLmZ1bmN0aW9uQXJuXSxcbiAgICAgIH0pLFxuICAgICAgbG9nR3JvdXA6IG5ldyBMb2dHcm91cCh0aGlzLCAnQ3VzdG9tUmVzb3VyY2VTZWNyZXRMYW1iZGFJbnZva2VMb2dHcm91cCcsIHtcbiAgICAgICAgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgICByZXRlbnRpb246IHByb3BzLmxvZ1JldGVudGlvbkRheXMgPz8gUmV0ZW50aW9uRGF5cy5PTkVfV0VFSyxcbiAgICAgIH0pLFxuICAgIH0pO1xuXG4gICAgLy8gR3JhbnQgdGhlIExhbWJkYSBJbnZva2UgcGVybWlzc2lvbnMgdG8gdGhlIGxhbWJkYUludm9rZSBjdXN0b20gcmVzb3VyY2VcbiAgICBkZWNyeXB0U2VjcmV0RnVuY3Rpb24uZ3JhbnRJbnZva2UobGFtYmRhSW52b2tlQXdzQ3VzdG9tUmVzb3VyY2UpO1xuICB9XG59XG4iXX0=