Skip to content

Commit

Permalink
feat(kms): introduce fromCfnKey() method (#14859)
Browse files Browse the repository at this point in the history
This is part 1 of adding support from converting L1 resources to L2 without making them immutable in the process.
Next phase after this will be adding support for `Bucket.fromCfnBucket()`
(which will use the method from KMS defined here).

Related issues: #9719 #14795 #14809

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
skinny85 committed Jun 3, 2021
1 parent 25412a6 commit 1ff5b9e
Show file tree
Hide file tree
Showing 4 changed files with 479 additions and 7 deletions.
10 changes: 9 additions & 1 deletion packages/@aws-cdk/aws-iam/lib/policy-statement.ts
Expand Up @@ -30,7 +30,7 @@ export class PolicyStatement {
* @param obj the PolicyStatement in object form.
*/
public static fromJson(obj: any) {
return new PolicyStatement({
const ret = new PolicyStatement({
sid: obj.Sid,
actions: ensureArrayOrUndefined(obj.Action),
resources: ensureArrayOrUndefined(obj.Resource),
Expand All @@ -41,6 +41,14 @@ export class PolicyStatement {
principals: obj.Principal ? [new JsonPrincipal(obj.Principal)] : undefined,
notPrincipals: obj.NotPrincipal ? [new JsonPrincipal(obj.NotPrincipal)] : undefined,
});

// validate that the PolicyStatement has the correct shape
const errors = ret.validateForAnyPolicy();
if (errors.length > 0) {
throw new Error('Incorrect Policy Statement: ' + errors.join('\n'));
}

return ret;
}

/**
Expand Down
51 changes: 50 additions & 1 deletion packages/@aws-cdk/aws-kms/lib/key.ts
@@ -1,5 +1,5 @@
import * as iam from '@aws-cdk/aws-iam';
import { FeatureFlags, IResource, RemovalPolicy, Resource, Stack, Duration } from '@aws-cdk/core';
import { FeatureFlags, IResource, Lazy, RemovalPolicy, Resource, Stack, Duration } from '@aws-cdk/core';
import * as cxapi from '@aws-cdk/cx-api';
import { IConstruct, Construct } from 'constructs';
import { Alias } from './alias';
Expand Down Expand Up @@ -485,6 +485,55 @@ export class Key extends KeyBase {
return new Import(keyResourceName);
}

/**
* Create a mutable {@link IKey} based on a low-level {@link CfnKey}.
* This is most useful when combined with the cloudformation-include module.
* This method is different than {@link fromKeyArn()} because the {@link IKey}
* returned from this method is mutable;
* meaning, calling any mutating methods on it,
* like {@link IKey.addToResourcePolicy()},
* will actually be reflected in the resulting template,
* as opposed to the object returned from {@link fromKeyArn()},
* on which calling those methods would have no effect.
*/
public static fromCfnKey(cfnKey: CfnKey): IKey {
// use a "weird" id that has a higher chance of being unique
const id = '@FromCfnKey';

// if fromCfnKey() was already called on this cfnKey,
// return the same L2
// (as different L2s would conflict, because of the mutation of the keyPolicy property of the L1 below)
const existing = cfnKey.node.tryFindChild(id);
if (existing) {
return <IKey>existing;
}

let keyPolicy: iam.PolicyDocument;
try {
keyPolicy = iam.PolicyDocument.fromJson(cfnKey.keyPolicy);
} catch (e) {
// If the KeyPolicy contains any CloudFormation functions,
// PolicyDocument.fromJson() throws an exception.
// In that case, because we would have to effectively make the returned IKey immutable,
// throw an exception suggesting to use the other importing methods instead.
// We might make this parsing logic smarter later,
// but let's start by erroring out.
throw new Error('Could not parse the PolicyDocument of the passed AWS::KMS::Key resource because it contains CloudFormation functions. ' +
'This makes it impossible to create a mutable IKey from that Policy. ' +
'You have to use fromKeyArn instead, passing it the ARN attribute property of the low-level CfnKey');
}

// change the key policy of the L1, so that all changes done in the L2 are reflected in the resulting template
cfnKey.keyPolicy = Lazy.any({ produce: () => keyPolicy.toJSON() });

return new class extends KeyBase {
public readonly keyArn = cfnKey.attrArn;
public readonly keyId = cfnKey.ref;
protected readonly policy = keyPolicy;
protected readonly trustAccountIdentities = false;
}(cfnKey, id);
}

public readonly keyArn: string;
public readonly keyId: string;
protected readonly policy?: iam.PolicyDocument;
Expand Down

0 comments on commit 1ff5b9e

Please sign in to comment.