@@ -31,8 +31,6 @@ key.addAlias('alias/bar');
3131
3232## Sharing keys between stacks
3333
34- > see Trust Account Identities for additional details
35-
3634To use a KMS key in a different stack in the same CDK application,
3735pass the construct to the other stack:
3836
@@ -41,8 +39,6 @@ pass the construct to the other stack:
4139
4240## Importing existing keys
4341
44- > see Trust Account Identities for additional details
45-
4642To use a KMS key that is not defined in this CDK app, but is created through other means, use
4743` Key.fromKeyArn(parent, name, ref) ` :
4844
@@ -72,71 +68,96 @@ Note that calls to `addToResourcePolicy` and `grant*` methods on `myKeyAlias` wi
7268no-ops, and ` addAlias ` and ` aliasTargetKey ` will fail, as the imported alias does not
7369have a reference to the underlying KMS Key.
7470
75- ## Trust Account Identities
71+ ## Key Policies
7672
77- KMS keys can be created to trust IAM policies. This is the default behavior for both the KMS APIs and in
78- the console and is described [ here] ( https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html ) .
73+ Controlling access and usage of KMS Keys requires the use of key policies (resource-based policies attached to the key);
74+ this is in contrast to most other AWS resources where access can be entirely controlled with IAM policies,
75+ and optionally complemented with resource policies. For more in-depth understanding of KMS key access and policies, see
7976
80- This behavior is enabled by the '@aws-cdk/aws-kms : defaultKeyPolicies ' feature flag,
81- which is set for all new projects. For existing projects, this same behavior can be enabled by:
77+ * https://docs.aws.amazon.com/kms/latest/developerguide/control-access-overview.html
78+ * https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html
79+
80+ KMS keys can be created to trust IAM policies. This is the default behavior for both the KMS APIs and in
81+ the console. This behavior is enabled by the '@aws-cdk/aws-kms : defaultKeyPolicies ' feature flag,
82+ which is set for all new projects; for existing projects, this same behavior can be enabled by:
8283
8384``` ts
84- new Key (stack , ' MyKey' , { trustAccountIdentities: true });
85+ new kms . Key (stack , ' MyKey' , { trustAccountIdentities: true });
8586```
8687
87- Adopting the default KMS key policy (and so trusting account identities)
88- solves many issues around cyclic dependencies between stacks.
89- The most common use case is creating an S3 Bucket with CMK
90- default encryption which is later accessed by IAM roles in other stacks.
91-
92- stack-1 (bucket and key created)
93-
94- ``` ts
95- // ... snip
96- const myKmsKey = new kms .Key (this , ' MyKey' , { trustAccountIdentities: true });
88+ With either the ` defaultKeyPolicies ` feature flag set, or ` trustAccountIdentities ` set,
89+ the Key will be given the following default key policy:
9790
98- const bucket = new Bucket (this , ' MyEncryptedBucket' , {
99- bucketName: ' myEncryptedBucket' ,
100- encryption: BucketEncryption .KMS ,
101- encryptionKey: myKmsKey
102- });
91+ ``` json
92+ {
93+ "Effect" : " Allow" ,
94+ "Principal" : {"AWS" : " arn:aws:iam::111122223333:root" },
95+ "Action" : " kms:*" ,
96+ "Resource" : " *"
97+ }
10398```
10499
105- stack-2 (lambda that operates on bucket and key)
100+ This policy grants full access to the key to the root account user.
101+ This enables the root account user -- via IAM policies -- to grant access to other IAM principals.
102+ With the above default policy, future permissions can be added to either the key policy or IAM principal policy.
106103
107104``` ts
108- // ... snip
105+ const key = new kms .Key (stack , ' MyKey' );
106+ const user = new iam .user (stack , ' MyUser' );
107+ key .grantEncrypt (user ); // Adds encrypt permissions to user policy; key policy is unmodified.
108+ ```
109109
110- const fn = new lambda . Function ( this , ' MyFunction ' , {
111- runtime: lambda . Runtime . NODEJS_10_X ,
112- handler: ' index.handler ' ,
113- code: lambda . Code . fromAsset ( path . join ( __dirname , ' lambda-handler ' )),
114- });
110+ Adopting the default KMS key policy (and so trusting account identities)
111+ solves many issues around cyclic dependencies between stacks.
112+ Without this default key policy, future permissions must be added to both the key policy and IAM principal policy ,
113+ which can cause cyclic dependencies if the permissions cross stack boundaries.
114+ (For example, an encrypted bucket in one stack, and Lambda function that accesses it in another).
115115
116- const bucket = s3 . Bucket . fromBucketName ( this , ' BucketId ' , ' myEncryptedBucket ' );
116+ ### Appending to or replacing the default key policy
117117
118- const key = kms .Key .fromKeyArn (this , ' KeyId' , ' arn:aws:...' ); // key ARN passed via stack props
118+ The default key policy can be ammended or replaced entirely, depending on your use case and requirements.
119+ A common addition to the key policy would be to add other key admins that are allowed to administer the key
120+ (e.g., change permissions, revoke, delete). Additional key admins can be specified at key creation or after
121+ via the ` addAdmin ` method.
119122
120- bucket .grantReadWrite (fn );
121- key .grantEncryptDecrypt (fn );
123+ ``` ts
124+ const myTrustedAdminRole = iam .Role .fromRoleArn (stack , ' TrustedRole' , ' arn:aws:iam:....' );
125+ const key = new kms .Key (stack , ' MyKey' , {
126+ admins: [myTrustedAdminRole ],
127+ });
128+
129+ const secondKey = new kms .Key (stack , ' MyKey2' );
130+ secondKey .addAdmin (myTrustedAdminRole );
122131```
123132
124- The challenge in this scenario is the KMS key policy behavior. The simple way to understand
125- this, is IAM policies for account entities can only grant the permissions granted to the
126- account root principle in the key policy. When ` trustAccountIdentities ` is true,
127- the following policy statement is added:
133+ Alternatively, a custom key policy can be specified, which will replace the default key policy.
128134
129- ``` json
130- {
131- "Sid" : " Enable IAM User Permissions" ,
132- "Effect" : " Allow" ,
133- "Principal" : {"AWS" : " arn:aws:iam::111122223333:root" },
134- "Action" : " kms:*" ,
135- "Resource" : " *"
136- }
135+ > ** Note** : In applications without the '@aws-cdk/aws-kms : defaultKeyPolicies ' feature flag set,
136+ or ` trustedAccountIdentities ` set to false, specifying a policy at key creation _ appends_ the
137+ provided policy to the default key policy, rather than _ replacing_ the default policy.
138+
139+ ``` ts
140+ const myTrustedAdminRole = iam .Role .fromRoleArn (stack , ' TrustedRole' , ' arn:aws:iam:....' );
141+ // Creates a limited admin policy and assigns to the account root.
142+ const myCustomPolicy = new iam .PolicyDocument ({
143+ statements: [new iam .PolicyStatement ({
144+ actions: [
145+ ' kms:Create*' ,
146+ ' kms:Describe*' ,
147+ ' kms:Enable*' ,
148+ ' kms:List*' ,
149+ ' kms:Put*' ,
150+ ],
151+ principals: [new iam .AccountRootPrincipal ()],
152+ resources: [' *' ],
153+ })],
154+ });
155+ const key = new kms .Key (stack , ' MyKey' , {
156+ policy: myCustomPolicy ,
157+ });
137158```
138159
139- As the name suggests this trusts IAM policies to control access to the key.
140- If account root does not have permissions to the specific actions, then the key
141- policy and the IAM policy for the entity (e.g. Lambda) both need to grant
142- permission .
160+ > ** Warning: ** Replacing the default key policy with one that only grants access to a specific user or role
161+ runs the risk of the key becoming unmanageable if that user or role is deleted.
162+ It is highly recommended that the key policy grants access to the account root, rather than specific principals.
163+ See https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html for more information .
0 commit comments