aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.72k stars 3.94k forks source link

(aws-kms): Add support for MultiRegion Key with ReplicaKey #15257

Open chrisjgray opened 3 years ago

chrisjgray commented 3 years ago

KMS recently added support for MultiRegion KMS Keys with the MultiRegion boolean Property as part of Key and the ReplicaKey which can point to a Key that has MultiRegion set to true. This is required to support the new functionality that was released.

Use Case

Enables functional support already enabled in CloudFormation. Being able to manage key replication for DR purposes becomes easier.

Proposed Solution

First is to add the MultiRegion Property to the KeyProps interface

  /**
   * Creates a multi-Region primary CMK that you can replicate in other AWS Regions.
   * 
   * IMPORTANT: If you change the MultiRegion property of an existing CMK, the existing CMK is scheduled for
   * deletion and a new CMK is created with the specified Multi-Region value. While the scheduled deletion is
   * pending, you can't use the existing CMK. Unless you cancel the scheduled deletion of the CMK outside of
   * CloudFormation, all data encrypted under the existing CMK becomes unrecoverable when the CMK is deleted.
   * 
   * @default false
   */
  readonly multiRegion?: boolean;

Then add the multiRegion property to the CfnKey resource

    const resource = new CfnKey(this, 'Resource', {
      description: props.description,
      enableKeyRotation: props.enableKeyRotation,
      enabled: props.enabled,
      keySpec: props.keySpec,
      keyUsage: props.keyUsage,
      keyPolicy: this.policy,
      multiRegion: props.multiRegion,
      pendingWindowInDays: pendingWindowInDays,
    });

For the ReplicaKey, implement what is already in Cloudformation as referenced https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-kms-replicakey.html

Other


This is a :rocket: Feature Request

njlynch commented 3 years ago

Thanks for filing the feature request.

I've tagged this as P1, which means it should be on our near-term roadmap.

We welcome community contributions! If you are able, we encourage you to contribute a bug fix or new feature to the CDK. If you decide to contribute, please start an engineering discussion in this issue to ensure there is a commonly understood design before submitting code. This will minimize the number of review cycles and get your code merged faster.

njlynch commented 3 years ago

By the way, it's worth noting that support for this feature was added to the L1s (CfnKey, CfnReplicaKey) as part of the v1.111.0 release (v1.111.0). Using a combination of the CfnReplicaKey directy, and escape hatches to add the property to the CfnKey, you should be able to use this with existing L2 Keys.

dhawalschumi commented 2 years ago

We tried using escape hatches for use case wherein Primary Key is in us-east-1 region and replica keys are in us-west-2 and eu-west-1 regions. We ran into Cross Stack Reference issue while passing primary key arn to replica keys of us-west-2 and eu-west-1 regions.

Exception - Stack "Replica Key Stack" cannot consume a cross reference from stack "Primary Key Stack". Cross stack references are only supported for stacks deployed to the same environment or between nested stacks and their parent stack

What are the possible solutions we can try here?

ClayMav commented 2 years ago

Hi, any update on getting this added as the issue requests?

Lilja commented 2 years ago

It's possible to create an CfnReplicaKey, but the secret I want to add replication to accepts an IKey, not an CfnReplicaKey. image

How does one proceed with this?

Lilja commented 2 years ago

I spent some time reading the CfnKey and CfnReplicaKey documentation. From what I've understand, in CDK, the suggestion is to create this from the low level APIs, since the features aren't available in the higher level constructs.

In the KMS Console after creating a multi region key, it's from that specific key's view you create replicas to other regions. image

image

In the CDK world, you are supposed to create a CfnKey and then a CfnReplicaKey with the target primaryKeyArn pointing to the CfnKey that was created. In the CfnReplicaKeyProps there does not seem to be a way to select a particular region, which is what I would expect based of my experience in the KMS console. But I guess this stems from the fundamental problem/design decision with CDK and that it's supposed to always assume the region you are deploying to is the region that you want a particular resource to be.

It looked like @dhawalschumi tried to do this with different stacks, deploying the CfnKey to one region and in another stack use CfnReplicaKey in the other, which didn't work according to their error messages.

Could we please be advised on how we should solve this?

dhawalschumi commented 2 years ago

@Lilja - Given there is no way as of now, we went ahead with creating keys via AWS CLI and used they KMS Key Ids for our global table use case.

bearrito commented 2 years ago

Any update on this? For anyone attempting to do this keep in mind you can also call the AWS CLI from a custom CDK resource.

lukezdz commented 2 years ago

There is one issue with adding an L2 ReplicaKey construct that would be able to take in a Key in props as the primary key - the way ARNs of KMS keys work. That's the issue that caused errors noticed by @dhawalschumi.

Example KMS key ARN for more context/clarity: arn:aws:kms:<region>:<account-id>:key/<key-id>

ARN of a KMS key contains the given key's ID, which (at least that's how it seems) is being pseudo-randomly generated during the key's creation. Due to that, there is no way to control and/or reference a KMS key cross-region/account from the CDK level without creating it first and then hardcoding the ARN value (or at least I couldn't find any). This problem is not noticeable when creating multiple stacks in a single account and region, as the KMS key ARN can be exported in stacks output values and later on imported into another stack. This is unfortunately not possible for stacks in different regions/accounts, which is a requirement to create a replica key - the primary and replica must be in different regions.

The workaround here would be to just take the key ARN in ReplicaKeyProps as a string. This way there is still a construct that allows creating key aliases etc., which is definitely better than plain CfnReplicaKey

victormoraesgs commented 2 years ago

If I manually create a KMS multi region key with an alias, create regional replica with another alias, can I reference them in my CDK code?

My intention is to reference them so I can give decrypt permission to some fargate instances

tvb commented 1 year ago

Any update on this? We want to create multi-region KMS keys by using the L2 construct kms.Key()

ArielPrevu3D commented 1 year ago

Any update on this? We want to create multi-region KMS keys by using the L2 construct kms.Key()

This will never be possible. The CfnReplicaKey has to be created in the region where the primary key is to be replicated. The way I solved this was by creating a second stack that depends on the stack where the primary key is. Then, the second stack deploys a StackSet where the primary key's ARN is set as a parameter (not as an imported value, since you can't import from Stacks that are in other regions).

The multi-region replication of AWS Secrets Manager doesn't require us to do this, but that's because AWS doesn't require you to call the API from a different region to enable replication on this product. However, this is necessary with AWS KMS.

aamielsan commented 1 year ago

Thought of sharing how we solved this for our use case. We created a custom CDK construct (in Kotlin) using a combination of CDK's CfnKey and CustomResource. Gist can be found here.

When the construct is deployed in the primary region, it will provision a:

  1. KMS key with multi-region set to true;
  2. KMS key alias for (1);
  3. custom resource that runs AWS SDK kms replicate-key with the replica region set as the secondary region;
  4. custom resource that runs AWS SDK kms create-alias on the replica key in the secondary region.

When the construct is deployed in the secondary region, it will return an IKey from Key.fromLookup() via the alias.

tenjaa commented 4 months ago

But does using .fromLookup() reflect changes made to the key? For example adding something to the key policy. If I understand the docs correctly, this is what fromCfnKey() is for.