UNPKG

aws-delivlib

Version:

A fabulous library for defining continuous pipelines for building, testing and releasing code libraries.

144 lines • 13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const crypto = require("crypto"); const fs = require("fs"); const os = require("os"); const path = require("path"); const util = require("util"); const client_secrets_manager_1 = require("@aws-sdk/client-secrets-manager"); const client_ssm_1 = require("@aws-sdk/client-ssm"); const cfn = require("./_cloud-formation"); const _exec = require("./_exec"); const _rmrf = require("./_rmrf"); const mkdtemp = util.promisify(fs.mkdtemp); const writeFile = util.promisify(fs.writeFile); const secretsManager = new client_secrets_manager_1.SecretsManager(); const ssm = new client_ssm_1.SSM(); exports.handler = cfn.customResourceHandler(handleEvent); const GPG_BIN = 'gpg'; async function handleEvent(event, context) { const props = event.ResourceProperties; if (event.RequestType !== cfn.RequestType.DELETE) { cfn.validateProperties(props, { Description: false, Email: true, Expiry: true, Identity: true, KeyArn: false, KeySizeBits: true, SecretName: true, Version: false, DeleteImmediately: false, }); } let newKey = event.RequestType === cfn.RequestType.CREATE; if (event.RequestType === cfn.RequestType.UPDATE) { const oldProps = event.OldResourceProperties; const immutableFields = ['Email', 'Expiry', 'Identity', 'KeySizeBits', 'SecretName', 'Version']; for (const key of immutableFields) { if (props[key] !== oldProps[key]) { console.log(`New key required: ${key} changed from ${oldProps[key]} to ${props[key]}`); newKey = true; } } } switch (event.RequestType) { case cfn.RequestType.CREATE: case cfn.RequestType.UPDATE: return newKey ? _createNewKey(event, context) : _updateExistingKey(event, context); case cfn.RequestType.DELETE: return _deleteSecret(event); } } async function _createNewKey(event, context) { const passPhrase = crypto.randomBytes(32).toString('base64'); const tempDir = await mkdtemp(path.join(os.tmpdir(), 'OpenPGP-')); try { process.env.GNUPGHOME = tempDir; const keyConfig = path.join(tempDir, 'key.config'); await writeFile(keyConfig, [ 'Key-Type: RSA', `Key-Length: ${event.ResourceProperties.KeySizeBits}`, `Name-Real: ${event.ResourceProperties.Identity}`, `Name-Email: ${event.ResourceProperties.Email}`, `Expire-Date: ${event.ResourceProperties.Expiry}`, `Passphrase: ${passPhrase}`, '%commit', '%echo done', ].join('\n'), { encoding: 'utf8' }); const gpgCommonArgs = [`--homedir=${tempDir}`, '--agent-program=/bin/gpg-agent']; await _exec(GPG_BIN, ...gpgCommonArgs, '--batch', '--gen-key', keyConfig); const keyMaterial = await _exec(GPG_BIN, ...gpgCommonArgs, '--batch', '--yes', '--export-secret-keys', '--armor', '--pinentry-mode=loopback', `--passphrase=${passPhrase}`); const publicKey = await _exec(GPG_BIN, ...gpgCommonArgs, '--batch', '--yes', '--export', '--armor'); const secretOpts = { ClientRequestToken: context.awsRequestId, Description: event.ResourceProperties.Description, KmsKeyId: event.ResourceProperties.KeyArn, SecretString: JSON.stringify({ PrivateKey: keyMaterial, Passphrase: passPhrase, }), }; const secret = event.RequestType === cfn.RequestType.CREATE ? await secretsManager.createSecret(Object.assign(Object.assign({}, secretOpts), { Name: event.ResourceProperties.SecretName })) : await secretsManager.updateSecret(Object.assign(Object.assign({}, secretOpts), { SecretId: event.PhysicalResourceId })); return { Ref: secret.ARN, SecretArn: secret.ARN, PublicKey: publicKey, }; } finally { await _rmrf(tempDir); } } async function _updateExistingKey(event, context) { const publicKey = await _getPublicKey(event.PhysicalResourceId); const result = await secretsManager.updateSecret({ ClientRequestToken: context.awsRequestId, Description: event.ResourceProperties.Description, KmsKeyId: event.ResourceProperties.KeyArn, SecretId: event.PhysicalResourceId, }); if (event.OldResourceProperties.ParameterName) { try { await ssm.deleteParameter({ Name: event.OldResourceProperties.ParameterName }); } catch (e) { if (e.name !== 'ParameterNotFound') { throw e; } } } return { Ref: result.ARN, SecretArn: result.ARN, PublicKey: publicKey, }; } async function _getPublicKey(secretArn) { const secretValue = await secretsManager.getSecretValue({ SecretId: secretArn }); const keyData = JSON.parse(secretValue.SecretString); const tempDir = await mkdtemp(path.join(os.tmpdir(), 'OpenPGP-')); try { process.env.GNUPGHOME = tempDir; const privateKeyFile = path.join(tempDir, 'private.key'); await writeFile(privateKeyFile, keyData.PrivateKey, { encoding: 'utf-8' }); const gpgCommonArgs = [`--homedir=${tempDir}`, '--agent-program=/bin/gpg-agent']; await _exec(GPG_BIN, ...gpgCommonArgs, '--batch', '--yes', '--import', privateKeyFile); return await _exec(GPG_BIN, ...gpgCommonArgs, '--batch', '--yes', '--export', '--armor'); } finally { await _rmrf(tempDir); } } async function _deleteSecret(event) { await secretsManager.deleteSecret({ SecretId: event.PhysicalResourceId, ForceDeleteWithoutRecovery: !!event.ResourceProperties.DeleteImmediately, }); return { Ref: event.PhysicalResourceId }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGdwLXNlY3JldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wZ3Atc2VjcmV0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsaUNBQWlDO0FBQ2pDLHlCQUF5QjtBQUN6Qix5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLDZCQUE2QjtBQUU3Qiw0RUFBaUU7QUFFakUsb0RBQTBDO0FBRTFDLDBDQUEwQztBQUUxQyxpQ0FBa0M7QUFHbEMsaUNBQWtDO0FBRWxDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQzNDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBRS9DLE1BQU0sY0FBYyxHQUFHLElBQUksdUNBQWMsRUFBRSxDQUFDO0FBQzVDLE1BQU0sR0FBRyxHQUFHLElBQUksZ0JBQUcsRUFBRSxDQUFDO0FBRXRCLE9BQU8sQ0FBQyxPQUFPLEdBQUcsR0FBRyxDQUFDLHFCQUFxQixDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBRXpELE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQztBQVF0QixLQUFLLFVBQVUsV0FBVyxDQUFDLEtBQWdCLEVBQUUsT0FBdUI7SUFDbEUsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLGtCQUFrQixDQUFDO0lBRXZDLElBQUksS0FBSyxDQUFDLFdBQVcsS0FBSyxHQUFHLENBQUMsV0FBVyxDQUFDLE1BQU0sRUFBRTtRQUNoRCxHQUFHLENBQUMsa0JBQWtCLENBQUMsS0FBSyxFQUFFO1lBQzVCLFdBQVcsRUFBRSxLQUFLO1lBQ2xCLEtBQUssRUFBRSxJQUFJO1lBQ1gsTUFBTSxFQUFFLElBQUk7WUFDWixRQUFRLEVBQUUsSUFBSTtZQUNkLE1BQU0sRUFBRSxLQUFLO1lBQ2IsV0FBVyxFQUFFLElBQUk7WUFDakIsVUFBVSxFQUFFLElBQUk7WUFDaEIsT0FBTyxFQUFFLEtB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