Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(kms): Rename EncryptionKeyAlias to Alias #2769

Merged
merged 1 commit into from
Jun 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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