-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Description
Describe the feature
Currently, there is no way to get a proper IKey reference from an Alias ARN, that would produce a proper IAM PolicyStatement.
This would be especially useful for cross-account situations where the current available options like Key.fromLookup and Alias.fromAliasName are not sufficient.
Use Case
My current use case is creating a Lambda ESM from an encrypted cross-account Kinesis Stream.
From the external account, granting the permissions to the Stream and Key was pretty easy thanks to the existing CDK constructs.
On the reader account, however, we originally thought that we could centralize all the cross-account stuff in our custom Kinesis L3 Stream construct, and that the Lambda one would just create a KinesisEventSource without caring about the IStream origin. Sadly, that was not the case since there was no way to get a reference to the external account KMS Alias that would create a correct IAM PolicyStatement.
We tried the following CDK code:
const streamArn = Stack.of(this).formatArn({
account: externalAccountId,
service: 'kinesis',
resource: 'stream',
resourceName: streamName
})
const keyArn = Stack.of(this).formatArn({
account: externalAccountId,
service: 'kms',
resource: 'alias',
resourceName: `${streamName}-key`
})
const stream = Stream.fromStreamAttributes(this, 'external-stream', {
streamArn,
// Sadly, this doesn't produce the correct policy, and we have to explicitly modify the lambda policy.
encryptionKey: Key.fromKeyArn(this, 'external-stream-key', keyArn)
})But that created this IAM PolicyStatement (which is wrong):
{
"Action": "kms:Decrypt",
"Resource": "arn:aws:kms:<region>:<external-account-id>:alias/<stream-name>-key",
"Effect": "Allow"
}Thus, we had to expose the cross-account information to the Lambda module, and explicitly grant the correct IAM PolicyStatement.
// Workaround for lack of cross-account KMS alias lookup.
lambda.addToRolePolicy(
new PolicyStatement({
actions: ['kms:Decrypt'],
resources: [
Stack.of(this).formatArn({
account: externalAccountId,
service: 'kms',
resource: 'key',
resourceName: '*'
})
],
conditions: {
'ForAnyValue:StringEquals': {
'kms:ResourceAliases': `alias/${streamName}-key`
}
}
})
)Of course, another option would have been to use the external Key ARN instead of the Alias one. However, since Key's ARN values are not predictable, and we deploy this same Stack in multiple regions in multiple environments, we would need to have a hardcoded map of values. And we believe that is a worse solution since it is brittle and error-prone.
Proposed Solution
A static method like Key.fromAliasArn or Alias.fromArn that would return an IKey reference pointing to that Alias, and whose grant methods would produce a proper PolicyStatement with a kms:ResourceAliases condition.
Other Information
This feels related to #28284 & #8822
And, it is likely to be a recurring problem, since the official AWS recommendation is to use multiple accounts, and when sharing data, for example, using Kinesis Streams, it is a security best practice to encrypt it using KMS Keys.
Acknowledgements
- I may be able to implement this feature request
- This feature might incur a breaking change
AWS CDK Library version (aws-cdk-lib)
2.243.0
AWS CDK CLI version
2.1111.0
Environment details (OS name and version, etc.)
Any