Skip to content

Commit

Permalink
Merge branch 'master' into huijbers/jest-types
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored May 10, 2021
2 parents 3f0a077 + 10ae1a9 commit 6119e03
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 1 deletion.
12 changes: 12 additions & 0 deletions packages/@aws-cdk/aws-kms/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ key.addAlias('alias/foo');
key.addAlias('alias/bar');
```


Define a key with specific key spec and key usage:

Valid `keySpec` values depends on `keyUsage` value.

```ts
const key = new kms.Key(this, 'MyKey', {
keySpec: kms.KeySpec.ECC_SECG_P256K1, // Default to SYMMETRIC_DEFAULT
keyUsage: kms.KeyUsage.SIGN_VERIFY // and ENCRYPT_DECRYPT
});
```

## Sharing keys between stacks

To use a KMS key in a different stack in the same CDK application,
Expand Down
122 changes: 122 additions & 0 deletions packages/@aws-cdk/aws-kms/lib/key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,85 @@ abstract class KeyBase extends Resource implements IKey {
}
}

/**
* The key spec, represents the cryptographic configuration of keys.
*/
export enum KeySpec {
/**
* The default key spec.
*
* Valid usage: ENCRYPT_DECRYPT
*/
SYMMETRIC_DEFAULT = 'SYMMETRIC_DEFAULT',

/**
* RSA with 2048 bits of key.
*
* Valid usage: ENCRYPT_DECRYPT and SIGN_VERIFY
*/
RSA_2048 = 'RSA_2048',

/**
* RSA with 3072 bits of key.
*
* Valid usage: ENCRYPT_DECRYPT and SIGN_VERIFY
*/
RSA_3072 = 'RSA_3072',

/**
* RSA with 4096 bits of key.
*
* Valid usage: ENCRYPT_DECRYPT and SIGN_VERIFY
*/
RSA_4096 = 'RSA_4096',

/**
* NIST FIPS 186-4, Section 6.4, ECDSA signature using the curve specified by the key and
* SHA-256 for the message digest.
*
* Valid usage: SIGN_VERIFY
*/
ECC_NIST_P256 = 'ECC_NIST_P256',

/**
* NIST FIPS 186-4, Section 6.4, ECDSA signature using the curve specified by the key and
* SHA-384 for the message digest.
*
* Valid usage: SIGN_VERIFY
*/
ECC_NIST_P384 = 'ECC_NIST_P384',

/**
* NIST FIPS 186-4, Section 6.4, ECDSA signature using the curve specified by the key and
* SHA-512 for the message digest.
*
* Valid usage: SIGN_VERIFY
*/
ECC_NIST_P521 = 'ECC_NIST_P521',

/**
* Standards for Efficient Cryptography 2, Section 2.4.1, ECDSA signature on the Koblitz curve.
*
* Valid usage: SIGN_VERIFY
*/
ECC_SECG_P256K1 = 'ECC_SECG_P256K1',
}

/**
* The key usage, represents the cryptographic operations of keys.
*/
export enum KeyUsage {
/**
* Encryption and decryption.
*/
ENCRYPT_DECRYPT = 'ENCRYPT_DECRYPT',

/**
* Signing and verification
*/
SIGN_VERIFY = 'SIGN_VERIFY',
}

/**
* Construction properties for a KMS Key object
*/
Expand Down Expand Up @@ -282,6 +361,26 @@ export interface KeyProps {
*/
readonly enabled?: boolean;

/**
* The cryptographic configuration of the key. The valid value depends on usage of the key.
*
* IMPORTANT: If you change this property of an existing key, the existing key is scheduled for deletion
* and a new key is created with the specified value.
*
* @default KeySpec.SYMMETRIC_DEFAULT
*/
readonly keySpec?: KeySpec;

/**
* The cryptographic operations for which the key can be used.
*
* IMPORTANT: If you change this property of an existing key, the existing key is scheduled for deletion
* and a new key is created with the specified value.
*
* @default KeyUsage.ENCRYPT_DECRYPT
*/
readonly keyUsage?: KeyUsage;

/**
* Custom policy document to attach to the KMS key.
*
Expand Down Expand Up @@ -394,6 +493,27 @@ export class Key extends KeyBase {
constructor(scope: Construct, id: string, props: KeyProps = {}) {
super(scope, id);

const denyLists = {
[KeyUsage.ENCRYPT_DECRYPT]: [
KeySpec.ECC_NIST_P256,
KeySpec.ECC_NIST_P384,
KeySpec.ECC_NIST_P521,
KeySpec.ECC_SECG_P256K1,
],
[KeyUsage.SIGN_VERIFY]: [
KeySpec.SYMMETRIC_DEFAULT,
],
};
const keySpec = props.keySpec ?? KeySpec.SYMMETRIC_DEFAULT;
const keyUsage = props.keyUsage ?? KeyUsage.ENCRYPT_DECRYPT;
if (denyLists[keyUsage].includes(keySpec)) {
throw new Error(`key spec '${keySpec}' is not valid with usage '${keyUsage}'`);
}

if (keySpec !== KeySpec.SYMMETRIC_DEFAULT && props.enableKeyRotation) {
throw new Error('key rotation cannot be enabled on asymmetric keys');
}

const defaultKeyPoliciesFeatureEnabled = FeatureFlags.of(this).isEnabled(cxapi.KMS_DEFAULT_KEY_POLICIES);

this.policy = props.policy ?? new iam.PolicyDocument();
Expand Down Expand Up @@ -428,6 +548,8 @@ export class Key extends KeyBase {
description: props.description,
enableKeyRotation: props.enableKeyRotation,
enabled: props.enabled,
keySpec: props.keySpec,
keyUsage: props.keyUsage,
keyPolicy: this.policy,
pendingWindowInDays: pendingWindowInDays,
});
Expand Down
37 changes: 37 additions & 0 deletions packages/@aws-cdk/aws-kms/test/integ.key.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,43 @@
]
}
}
},
"AsymmetricKey26BBC514": {
"Type": "AWS::KMS::Key",
"Properties": {
"KeyPolicy": {
"Statement": [
{
"Action": "kms:*",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::",
{
"Ref": "AWS::AccountId"
},
":root"
]
]
}
},
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"KeySpec": "ECC_NIST_P256",
"KeyUsage": "SIGN_VERIFY"
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
}
}
}
8 changes: 7 additions & 1 deletion packages/@aws-cdk/aws-kms/test/integ.key.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as iam from '@aws-cdk/aws-iam';
import { App, RemovalPolicy, Stack } from '@aws-cdk/core';
import { Key } from '../lib';
import { Key, KeySpec, KeyUsage } from '../lib';

const app = new App();

Expand All @@ -16,4 +16,10 @@ key.addToResourcePolicy(new iam.PolicyStatement({

key.addAlias('alias/bar');

new Key(stack, 'AsymmetricKey', {
keySpec: KeySpec.ECC_NIST_P256,
keyUsage: KeyUsage.SIGN_VERIFY,
removalPolicy: RemovalPolicy.DESTROY,
});

app.synth();
50 changes: 50 additions & 0 deletions packages/@aws-cdk/aws-kms/test/key.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -844,3 +844,53 @@ describe('when the defaultKeyPolicies feature flag is disabled', () => {
});
});
});

describe('key specs and key usages', () => {
testFutureBehavior('both usage and spec are specified', flags, cdk.App, (app) => {
const stack = new cdk.Stack(app);
new kms.Key(stack, 'Key', { keySpec: kms.KeySpec.ECC_SECG_P256K1, keyUsage: kms.KeyUsage.SIGN_VERIFY });

expect(stack).toHaveResourceLike('AWS::KMS::Key', {
KeySpec: 'ECC_SECG_P256K1',
KeyUsage: 'SIGN_VERIFY',
});
});

testFutureBehavior('only key usage is specified', flags, cdk.App, (app) => {
const stack = new cdk.Stack(app);
new kms.Key(stack, 'Key', { keyUsage: kms.KeyUsage.ENCRYPT_DECRYPT });

expect(stack).toHaveResourceLike('AWS::KMS::Key', {
KeyUsage: 'ENCRYPT_DECRYPT',
});
});

testFutureBehavior('only key spec is specified', flags, cdk.App, (app) => {
const stack = new cdk.Stack(app);
new kms.Key(stack, 'Key', { keySpec: kms.KeySpec.RSA_4096 });

expect(stack).toHaveResourceLike('AWS::KMS::Key', {
KeySpec: 'RSA_4096',
});
});

testFutureBehavior('invalid combinations of key specs and key usages', flags, cdk.App, (app) => {
const stack = new cdk.Stack(app);

expect(() => new kms.Key(stack, 'Key1', { keySpec: kms.KeySpec.ECC_NIST_P256 }))
.toThrow('key spec \'ECC_NIST_P256\' is not valid with usage \'ENCRYPT_DECRYPT\'');
expect(() => new kms.Key(stack, 'Key2', { keySpec: kms.KeySpec.ECC_SECG_P256K1, keyUsage: kms.KeyUsage.ENCRYPT_DECRYPT }))
.toThrow('key spec \'ECC_SECG_P256K1\' is not valid with usage \'ENCRYPT_DECRYPT\'');
expect(() => new kms.Key(stack, 'Key3', { keySpec: kms.KeySpec.SYMMETRIC_DEFAULT, keyUsage: kms.KeyUsage.SIGN_VERIFY }))
.toThrow('key spec \'SYMMETRIC_DEFAULT\' is not valid with usage \'SIGN_VERIFY\'');
expect(() => new kms.Key(stack, 'Key4', { keyUsage: kms.KeyUsage.SIGN_VERIFY }))
.toThrow('key spec \'SYMMETRIC_DEFAULT\' is not valid with usage \'SIGN_VERIFY\'');
});

testFutureBehavior('fails if key rotation enabled on asymmetric key', flags, cdk.App, (app) => {
const stack = new cdk.Stack(app);

expect(() => new kms.Key(stack, 'Key', { enableKeyRotation: true, keySpec: kms.KeySpec.RSA_3072 }))
.toThrow('key rotation cannot be enabled on asymmetric keys');
});
});

0 comments on commit 6119e03

Please sign in to comment.