Skip to content

Commit

Permalink
refactor(kms): Rename EncryptionKeyAlias to Alias (#2769)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The `EncryptionKeyAlias` class was renamed to `Alias`.
Associated types (such as `EncryptionKeyAliasProps`) were renamed in the
same way.
  • Loading branch information
RomainMuller authored Jun 6, 2019
1 parent da94d8b commit da8e1d5
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 52 deletions.
8 changes: 4 additions & 4 deletions packages/@aws-cdk/aws-kms/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
Defines a KMS key:

```js
new EncryptionKey(this, 'MyKey', {
new Key(this, 'MyKey', {
enableKeyRotation: true
});
```

Add a couple of aliases:

```js
const key = new EncryptionKey(this, 'MyKey');
const key = new Key(this, 'MyKey');
key.addAlias('alias/foo');
key.addAlias('alias/bar');
```
Expand All @@ -39,10 +39,10 @@ pass the construct to the other stack:
### Importing existing keys

To use a KMS key that is not defined in this CDK app, but is created through other means, use
`EncryptionKey.import(parent, name, ref)`:
`Key.import(parent, name, ref)`:

```ts
const myKeyImported = EncryptionKey.import(this, 'MyImportedKey', {
const myKeyImported = Key.import(this, 'MyImportedKey', {
keyArn: 'arn:aws:...'
});

Expand Down
90 changes: 69 additions & 21 deletions packages/@aws-cdk/aws-kms/lib/alias.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,57 @@
import { Construct } from '@aws-cdk/cdk';
import { Construct, IResource, Resource, Token } from '@aws-cdk/cdk';
import { IKey } from './key';
import { CfnAlias } from './kms.generated';

const REQUIRED_ALIAS_PREFIX = 'alias/';
const DISALLOWED_PREFIX = REQUIRED_ALIAS_PREFIX + 'AWS';
const DISALLOWED_PREFIX = REQUIRED_ALIAS_PREFIX + 'aws/';

export interface EncryptionKeyAliasProps {
/**
* A KMS Key alias.
*/
export interface IAlias extends IResource {
/**
* The name of the alias.
*
* @attribute AliasName
*/
readonly aliasName: string;

/**
* The Key to which the Alias refers.
*
* @attribute TargetKeyId
*/
readonly aliasTargetKey: IKey;
}

/**
* Construction properties for a KMS Key Alias object.
*/
export interface AliasProps {
/**
* The name of the alias. The name must start with alias followed by a
* forward slash, such as alias/. You can't specify aliases that begin with
* alias/AWS. These aliases are reserved.
*/
readonly alias: string;
readonly name: string;

/**
* The ID of the key for which you are creating the alias. Specify the key's
* globally unique identifier or Amazon Resource Name (ARN). You can't
* specify another alias.
*/
readonly key: IKey;
readonly targetKey: IKey;
}

abstract class AliasBase extends Resource implements IAlias {
public abstract readonly aliasName: string;

public abstract readonly aliasTargetKey: IKey;
}

export interface AliasAttributes {
readonly aliasName: string;
readonly aliasTargetKey: IKey;
}

/**
Expand All @@ -29,31 +62,46 @@ export interface EncryptionKeyAliasProps {
* Working with Aliases in the AWS Key Management Service Developer Guide.
*
* You can also add an alias for a key by calling `key.addAlias(alias)`.
*
* @resource AWS::KMS::Alias
*/
export class EncryptionKeyAlias extends Construct {
/**
* The name of the alias.
*/
public aliasName: string;
export class Alias extends AliasBase {
public static fromAliasAttributes(scope: Construct, id: string, attrs: AliasAttributes): IAlias {
// tslint:disable-next-line: class-name
class _Alias extends AliasBase {
public get aliasName() { return attrs.aliasName; }
public get aliasTargetKey() { return attrs.aliasTargetKey; }
}
return new _Alias(scope, id);
}

public readonly aliasName: string;
public readonly aliasTargetKey: IKey;

constructor(scope: Construct, id: string, props: EncryptionKeyAliasProps) {
constructor(scope: Construct, id: string, props: AliasProps) {
super(scope, id);

if (!props.alias.startsWith(REQUIRED_ALIAS_PREFIX)) {
throw new Error(`Alias must start with the prefix "${REQUIRED_ALIAS_PREFIX}": ${props.alias}`);
}
if (!Token.unresolved(props.name)) {
if (!props.name.startsWith(REQUIRED_ALIAS_PREFIX)) {
throw new Error(`Alias must start with the prefix "${REQUIRED_ALIAS_PREFIX}": ${props.name}`);
}

if (props.alias === REQUIRED_ALIAS_PREFIX) {
throw new Error(`Alias must include a value after "${REQUIRED_ALIAS_PREFIX}": ${props.alias}`);
}
if (props.name === REQUIRED_ALIAS_PREFIX) {
throw new Error(`Alias must include a value after "${REQUIRED_ALIAS_PREFIX}": ${props.name}`);
}

if (props.name.startsWith(DISALLOWED_PREFIX)) {
throw new Error(`Alias cannot start with ${DISALLOWED_PREFIX}: ${props.name}`);
}

if (props.alias.startsWith(DISALLOWED_PREFIX)) {
throw new Error(`Alias cannot start with ${DISALLOWED_PREFIX}: ${props.alias}`);
if (!props.name.match(/^[a-zA-Z0-9:/_-]{1,256}$/)) {
throw new Error(`Alias name must be between 1 and 256 characters in a-zA-Z0-9:/_-`);
}
}

const resource = new CfnAlias(this, 'Resource', {
aliasName: props.alias,
targetKeyId: props.key.keyArn
aliasName: props.name,
targetKeyId: props.targetKey.keyArn
});

this.aliasName = resource.aliasName;
Expand Down
25 changes: 18 additions & 7 deletions packages/@aws-cdk/aws-kms/lib/key.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import iam = require('@aws-cdk/aws-iam');
import { PolicyDocument, PolicyStatement } from '@aws-cdk/aws-iam';
import { Construct, DeletionPolicy, IResource } from '@aws-cdk/cdk';
import { EncryptionKeyAlias } from './alias';
import { Construct, DeletionPolicy, IResource, Resource } from '@aws-cdk/cdk';
import { Alias } from './alias';
import { CfnKey } from './kms.generated';

/**
* A KMS Key, either managed by this CDK app, or imported.
*/
export interface IKey extends IResource {
/**
* The ARN of the key.
Expand All @@ -15,7 +18,7 @@ export interface IKey extends IResource {
/**
* Defines a new alias for the key.
*/
addAlias(alias: string): EncryptionKeyAlias;
addAlias(alias: string): Alias;

/**
* Adds a statement to the KMS key resource policy.
Expand Down Expand Up @@ -47,7 +50,7 @@ export interface IKey extends IResource {
grantEncryptDecrypt(grantee: iam.IGrantable): iam.Grant;
}

abstract class KeyBase extends Construct implements IKey {
abstract class KeyBase extends Resource implements IKey {
/**
* The ARN of the key.
*/
Expand All @@ -64,8 +67,8 @@ abstract class KeyBase extends Construct implements IKey {
/**
* Defines a new alias for the key.
*/
public addAlias(alias: string): EncryptionKeyAlias {
return new EncryptionKeyAlias(this, 'Alias', { alias, key: this });
public addAlias(alias: string): Alias {
return new Alias(this, 'Alias', { name: alias, targetKey: this });
}

/**
Expand Down Expand Up @@ -179,9 +182,17 @@ export interface KeyProps {

/**
* Defines a KMS key.
*
* @resource AWS::KMS::Key
*/
export class Key extends KeyBase {

/**
* Import an externally defined KMS Key using its ARN.
*
* @param scope the construct that will "own" the imported key.
* @param id the id of the imported key in the construct tree.
* @param keyArn the ARN of an existing KMS key.
*/
public static fromKeyArn(scope: Construct, id: string, keyArn: string): IKey {
class Import extends KeyBase {
public keyArn = keyArn;
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-kms/test/integ.key-sharing.lit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class KeyStack extends cdk.Stack {
}

interface UseStackProps extends cdk.StackProps {
key: kms.IKey; // Use IEncryptionKey here
key: kms.IKey; // Use IKey here
}

/**
Expand All @@ -29,7 +29,7 @@ class UseStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props: UseStackProps) {
super(scope, id, props);

// Use the IEncryptionKey object here.
// Use the IKey object here.
props.key.addAlias('alias/foo');
}
}
Expand Down
53 changes: 35 additions & 18 deletions packages/@aws-cdk/aws-kms/test/test.alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { expect, haveResource } from '@aws-cdk/assert';
import { App, Stack } from '@aws-cdk/cdk';
import { Test } from 'nodeunit';
import { Key } from '../lib';
import { EncryptionKeyAlias } from '../lib/alias';
import { Alias } from '../lib/alias';

export = {
'default alias'(test: Test) {
const app = new App();
const stack = new Stack(app, 'Test');
const key = new Key(stack, 'Key');

new EncryptionKeyAlias(stack, 'Alias', { key, alias: 'alias/foo' });
new Alias(stack, 'Alias', { targetKey: key, name: 'alias/foo' });

expect(stack).to(haveResource('AWS::KMS::Alias', {
AliasName: 'alias/foo',
Expand All @@ -29,9 +29,9 @@ export = {
enabled: false
});

test.throws(() => new EncryptionKeyAlias(stack, 'Alias', {
alias: 'foo',
key
test.throws(() => new Alias(stack, 'Alias', {
name: 'foo',
targetKey: key
}));

test.done();
Expand All @@ -46,15 +46,15 @@ export = {
enabled: false
});

test.throws(() => new EncryptionKeyAlias(stack, 'Alias', {
alias: 'alias/',
key
test.throws(() => new Alias(stack, 'Alias', {
name: 'alias/',
targetKey: key
}));

test.done();
},

'fails if alias starts with "alias/AWS"'(test: Test) {
'fails if alias contains illegal characters'(test: Test) {
const app = new App();
const stack = new Stack(app, 'Test');

Expand All @@ -63,19 +63,36 @@ export = {
enabled: false
});

test.throws(() => new EncryptionKeyAlias(stack, 'Alias', {
alias: 'alias/AWS',
key
test.throws(() => new Alias(stack, 'Alias', {
name: 'alias/@Nope',
targetKey: key
}), 'a-zA-Z0-9:/_-');

test.done();
},

'fails if alias starts with "alias/aws/"'(test: Test) {
const app = new App();
const stack = new Stack(app, 'Test');

const key = new Key(stack, 'MyKey', {
enableKeyRotation: true,
enabled: false
});

test.throws(() => new Alias(stack, 'Alias', {
name: 'alias/aws/',
targetKey: key
}));

test.throws(() => new EncryptionKeyAlias(stack, 'Alias', {
alias: 'alias/AWSAwesome',
key
test.throws(() => new Alias(stack, 'Alias', {
name: 'alias/aws/Awesome',
targetKey: key
}));

test.throws(() => new EncryptionKeyAlias(stack, 'Alias', {
alias: 'alias/AWS/awesome',
key
test.throws(() => new Alias(stack, 'Alias', {
name: 'alias/AWS/awesome',
targetKey: key
}));

test.done();
Expand Down

0 comments on commit da8e1d5

Please sign in to comment.