aws-delivlib
Version:
A fabulous library for defining continuous pipelines for building, testing and releasing code libraries.
144 lines • 13 kB
JavaScript
"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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