Skip to content
v2.273.0

AWS Key Management Service Construct Library ​

Define a KMS key:

ts
new kms.Key(this, 'MyKey', {
  enableKeyRotation: true,
  rotationPeriod: Duration.days(180), // Default is 365 days
});
python
kms.Key(self, "MyKey",
    enable_key_rotation=True,
    rotation_period=Duration.days(180)
)
java
Key.Builder.create(this, "MyKey")
        .enableKeyRotation(true)
        .rotationPeriod(Duration.days(180))
        .build();
csharp
new Key(this, "MyKey", new KeyProps {
    EnableKeyRotation = true,
    RotationPeriod = Duration.Days(180)
});
go
kms.NewKey(this, jsii.String("MyKey"), &KeyProps{
	EnableKeyRotation: jsii.Boolean(true),
	RotationPeriod: awscdk.Duration_Days(jsii.Number(180)),
})

Define a KMS key with waiting period:

Specifies the number of days in the waiting period before AWS KMS deletes a CMK that has been removed from a CloudFormation stack.

ts
const key = new kms.Key(this, 'MyKey', {
  pendingWindow: Duration.days(10), // Default to 30 Days
});
python
key = kms.Key(self, "MyKey",
    pending_window=Duration.days(10)
)
java
Key key = Key.Builder.create(this, "MyKey")
        .pendingWindow(Duration.days(10))
        .build();
csharp
var key = new Key(this, "MyKey", new KeyProps {
    PendingWindow = Duration.Days(10)
});
go
key := kms.NewKey(this, jsii.String("MyKey"), &KeyProps{
	PendingWindow: awscdk.Duration_Days(jsii.Number(10)),
})

Add a couple of aliases:

ts
const key = new kms.Key(this, 'MyKey');
key.addAlias('alias/foo');
key.addAlias('alias/bar');
python
key = kms.Key(self, "MyKey")
key.add_alias("alias/foo")
key.add_alias("alias/bar")
java
Key key = new Key(this, "MyKey");
key.addAlias("alias/foo");
key.addAlias("alias/bar");
csharp
var key = new Key(this, "MyKey");
key.AddAlias("alias/foo");
key.AddAlias("alias/bar");
go
key := kms.NewKey(this, jsii.String("MyKey"))
key.addAlias(jsii.String("alias/foo"))
key.addAlias(jsii.String("alias/bar"))

Define a key with specific key spec and key usage:

Valid keySpec values depends on keyUsage value.

ts
const key = new kms.Key(this, 'MyKey', {
  keySpec: kms.KeySpec.ECC_SECG_P256K1, // Default to SYMMETRIC_DEFAULT
  keyUsage: kms.KeyUsage.SIGN_VERIFY,    // and ENCRYPT_DECRYPT
});
python
key = kms.Key(self, "MyKey",
    key_spec=kms.KeySpec.ECC_SECG_P256K1,  # Default to SYMMETRIC_DEFAULT
    key_usage=kms.KeyUsage.SIGN_VERIFY
)
java
Key key = Key.Builder.create(this, "MyKey")
        .keySpec(KeySpec.ECC_SECG_P256K1) // Default to SYMMETRIC_DEFAULT
        .keyUsage(KeyUsage.SIGN_VERIFY)
        .build();
csharp
var key = new Key(this, "MyKey", new KeyProps {
    KeySpec = KeySpec.ECC_SECG_P256K1,  // Default to SYMMETRIC_DEFAULT
    KeyUsage = KeyUsage.SIGN_VERIFY
});
go
key := kms.NewKey(this, jsii.String("MyKey"), &KeyProps{
	KeySpec: kms.KeySpec_ECC_SECG_P256K1,
	 // Default to SYMMETRIC_DEFAULT
	KeyUsage: kms.KeyUsage_SIGN_VERIFY,
})

Create a multi-Region primary key:

ts
const key = new kms.Key(this, 'MyKey', {
  multiRegion: true, // Default is false
});
python
key = kms.Key(self, "MyKey",
    multi_region=True
)
java
Key key = Key.Builder.create(this, "MyKey")
        .multiRegion(true)
        .build();
csharp
var key = new Key(this, "MyKey", new KeyProps {
    MultiRegion = true
});
go
key := kms.NewKey(this, jsii.String("MyKey"), &KeyProps{
	MultiRegion: jsii.Boolean(true),
})

Sharing keys between stacks ​

To use a KMS key in a different stack in the same CDK application, pass the construct to the other stack:

ts

/**
 * Stack that defines the key
 */
class KeyStack extends cdk.Stack {
  public readonly key: kms.Key;

  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    this.key = new kms.Key(this, 'MyKey', { removalPolicy: cdk.RemovalPolicy.DESTROY });
  }
}

interface UseStackProps extends cdk.StackProps {
  key: kms.IKey; // Use IKey here
}

/**
 * Stack that uses the key
 */
class UseStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props: UseStackProps) {
    super(scope, id, props);

    // Use the IKey object here.
    new kms.Alias(this, 'Alias', {
      aliasName: 'alias/foo',
      targetKey: props.key,
    });
  }
}

const keyStack = new KeyStack(app, 'KeyStack');
new UseStack(app, 'UseStack', { key: keyStack.key });
python
#
# Stack that defines the key
#
class KeyStack(cdk.Stack):

    def __init__(self, scope, id, *, description=None, env=None, stackName=None, tags=None, notificationArns=None, synthesizer=None, terminationProtection=None, analyticsReporting=None, crossRegionReferences=None, permissionsBoundary=None, suppressTemplateIndentation=None, propertyInjectors=None):
        super().__init__(scope, id, description=description, env=env, stackName=stackName, tags=tags, notificationArns=notificationArns, synthesizer=synthesizer, terminationProtection=terminationProtection, analyticsReporting=analyticsReporting, crossRegionReferences=crossRegionReferences, permissionsBoundary=permissionsBoundary, suppressTemplateIndentation=suppressTemplateIndentation, propertyInjectors=propertyInjectors)
        self.key = kms.Key(self, "MyKey", removal_policy=cdk.RemovalPolicy.DESTROY)

#
# Stack that uses the key
#
class UseStack(cdk.Stack):
    def __init__(self, scope, id, *, key, description=None, env=None, stackName=None, tags=None, notificationArns=None, synthesizer=None, terminationProtection=None, analyticsReporting=None, crossRegionReferences=None, permissionsBoundary=None, suppressTemplateIndentation=None, propertyInjectors=None):
        super().__init__(scope, id, key=key, description=description, env=env, stackName=stackName, tags=tags, notificationArns=notificationArns, synthesizer=synthesizer, terminationProtection=terminationProtection, analyticsReporting=analyticsReporting, crossRegionReferences=crossRegionReferences, permissionsBoundary=permissionsBoundary, suppressTemplateIndentation=suppressTemplateIndentation, propertyInjectors=propertyInjectors)

        # Use the IKey object here.
        kms.Alias(self, "Alias",
            alias_name="alias/foo",
            target_key=key
        )

key_stack = KeyStack(app, "KeyStack")
UseStack(app, "UseStack", key=key_stack.key)
java
/**
 * Stack that defines the key
 */
public class KeyStack extends Stack {
    public final Key key;

    public KeyStack(App scope, String id) {
        this(scope, id, null);
    }

    public KeyStack(App scope, String id, StackProps props) {
        super(scope, id, props);
        this.key = Key.Builder.create(this, "MyKey").removalPolicy(RemovalPolicy.DESTROY).build();
    }
}

public class UseStackProps extends StackProps {
    private IKey key;
    public IKey getKey() {
        return this.key;
    }
    public UseStackProps key(IKey key) {
        this.key = key;
        return this;
    }
}

/**
 * Stack that uses the key
 */
public class UseStack extends Stack {
    public UseStack(App scope, String id, UseStackProps props) {
        super(scope, id, props);

        // Use the IKey object here.
        // Use the IKey object here.
        Alias.Builder.create(this, "Alias")
                .aliasName("alias/foo")
                .targetKey(props.getKey())
                .build();
    }
}

KeyStack keyStack = new KeyStack(app, "KeyStack");
new UseStack(app, "UseStack", new UseStackProps().key(keyStack.getKey()));
csharp
/**
 * Stack that defines the key
 */
class KeyStack : Stack
{
    public Key Key { get; }

    public KeyStack(App scope, string id, StackProps? props=null) : base(scope, id, props)
    {
        Key = new Key(this, "MyKey", new KeyProps { RemovalPolicy = RemovalPolicy.DESTROY });
    }
}

class UseStackProps : StackProps
{
    public IKey Key { get; set; }
}

/**
 * Stack that uses the key
 */
class UseStack : Stack
{
    public UseStack(App scope, string id, UseStackProps props) : base(scope, id, props)
    {

        // Use the IKey object here.
        // Use the IKey object here.
        new Alias(this, "Alias", new AliasProps {
            AliasName = "alias/foo",
            TargetKey = props.Key
        });
    }
}

var keyStack = new KeyStack(app, "KeyStack");
new UseStack(app, "UseStack", new UseStackProps { Key = keyStack.Key });
go
/**
 * Stack that defines the key
 */
type keyStack struct {
	Stack
	key Key
}

func newKeyStack(scope App, id *string, props StackProps) *keyStack {
	this := &keyStack{}
	cdk.NewStack_Override(this, scope, id, props)
	this.key = kms.NewKey(this, jsii.String("MyKey"), &KeyProps{
		RemovalPolicy: cdk.RemovalPolicy_DESTROY,
	})
	return this
}

type useStackProps struct {
	StackProps
	key IKey
}

/**
 * Stack that uses the key
 */
type useStack struct {
	Stack
}

func newUseStack(scope App, id *string, props useStackProps) *useStack {
	this := &useStack{}
	cdk.NewStack_Override(this, scope, id, props)

	// Use the IKey object here.
	// Use the IKey object here.
	kms.NewAlias(this, jsii.String("Alias"), &AliasProps{
		AliasName: jsii.String("alias/foo"),
		TargetKey: props.key,
	})
	return this
}

keyStack := NewKeyStack(app, jsii.String("KeyStack"))
NewUseStack(app, jsii.String("UseStack"), &useStackProps{
	key: keyStack.key,
})

Importing existing keys ​

Import key by ARN ​

To use a KMS key that is not defined in this CDK app, but is created through other means, use Key.fromKeyArn(parent, name, ref):

ts
const myKeyImported = kms.Key.fromKeyArn(this, 'MyImportedKey', 'arn:aws:...');

// you can do stuff with this imported key.
myKeyImported.addAlias('alias/foo');
python
my_key_imported = kms.Key.from_key_arn(self, "MyImportedKey", "arn:aws:...")

# you can do stuff with this imported key.
my_key_imported.add_alias("alias/foo")
java
IKey myKeyImported = Key.fromKeyArn(this, "MyImportedKey", "arn:aws:...");

// you can do stuff with this imported key.
myKeyImported.addAlias("alias/foo");
csharp
var myKeyImported = Key.FromKeyArn(this, "MyImportedKey", "arn:aws:...");

// you can do stuff with this imported key.
myKeyImported.AddAlias("alias/foo");
go
myKeyImported := kms.Key_FromKeyArn(this, jsii.String("MyImportedKey"), jsii.String("arn:aws:..."))

// you can do stuff with this imported key.
myKeyImported.AddAlias(jsii.String("alias/foo"))

Note that a call to .addToResourcePolicy(statement) on myKeyImported will not have an affect on the key's policy because it is not owned by your stack. The call will be a no-op.

Import key by alias ​

If a Key has an associated Alias, the Alias can be imported by name and used in place of the Key as a reference. A common scenario for this is in referencing AWS managed keys.

ts
import * as cloudtrail from 'aws-cdk-lib/aws-cloudtrail';

const myKeyAlias = kms.Alias.fromAliasName(this, 'myKey', 'alias/aws/s3');
const trail = new cloudtrail.Trail(this, 'myCloudTrail', {
  sendToCloudWatchLogs: true,
  encryptionKey: myKeyAlias,
});
python
import aws_cdk.aws_cloudtrail as cloudtrail


my_key_alias = kms.Alias.from_alias_name(self, "myKey", "alias/aws/s3")
trail = cloudtrail.Trail(self, "myCloudTrail",
    send_to_cloud_watch_logs=True,
    encryption_key=my_key_alias
)
java
import software.amazon.awscdk.services.cloudtrail.*;


IAlias myKeyAlias = Alias.fromAliasName(this, "myKey", "alias/aws/s3");
Trail trail = Trail.Builder.create(this, "myCloudTrail")
        .sendToCloudWatchLogs(true)
        .encryptionKey(myKeyAlias)
        .build();
csharp
using Amazon.CDK.AWS.CloudTrail;


var myKeyAlias = Alias.FromAliasName(this, "myKey", "alias/aws/s3");
var trail = new Trail(this, "myCloudTrail", new TrailProps {
    SendToCloudWatchLogs = true,
    EncryptionKey = myKeyAlias
});
go
import cloudtrail "github.com/aws/aws-cdk-go/awscdk"


myKeyAlias := kms.Alias_FromAliasName(this, jsii.String("myKey"), jsii.String("alias/aws/s3"))
trail := cloudtrail.NewTrail(this, jsii.String("myCloudTrail"), &TrailProps{
	SendToCloudWatchLogs: jsii.Boolean(true),
	EncryptionKey: myKeyAlias,
})

Note that calls to addToResourcePolicy method on myKeyAlias will be a no-op, addAlias and aliasTargetKey will fail. The grant methods (i.e., methods in KeyGrants) will not modify the key policy, as the imported alias does not have a reference to the underlying KMS Key. For the grant methods to modify the principal's IAM policy, the feature flag @aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal must be set to true. By default, this flag is false and grant calls on an imported alias are a no-op.

Lookup key by alias ​

If you can't use a KMS key imported by alias (e.g. because you need access to the key id), you can lookup the key with Key.fromLookup().

In general, the preferred method would be to use Alias.fromAliasName() which returns an IAlias object which extends IKey. However, some services need to have access to the underlying key id. In this case, Key.fromLookup() allows to lookup the key id.

The result of the Key.fromLookup() operation will be written to a file called cdk.context.json. You must commit this file to source control so that the lookup values are available in non-privileged environments such as CI build steps, and to ensure your template builds are repeatable.

Here's how Key.fromLookup() can be used:

ts
const myKeyLookup = kms.Key.fromLookup(this, 'MyKeyLookup', {
  aliasName: 'alias/KeyAlias',
});

const role = new iam.Role(this, 'MyRole', {
  assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});
myKeyLookup.grantEncryptDecrypt(role);
python
my_key_lookup = kms.Key.from_lookup(self, "MyKeyLookup",
    alias_name="alias/KeyAlias"
)

role = iam.Role(self, "MyRole",
    assumed_by=iam.ServicePrincipal("lambda.amazonaws.com")
)
my_key_lookup.grant_encrypt_decrypt(role)
java
IKey myKeyLookup = Key.fromLookup(this, "MyKeyLookup", KeyLookupOptions.builder()
        .aliasName("alias/KeyAlias")
        .build());

Role role = Role.Builder.create(this, "MyRole")
        .assumedBy(new ServicePrincipal("lambda.amazonaws.com"))
        .build();
myKeyLookup.grantEncryptDecrypt(role);
csharp
var myKeyLookup = Key.FromLookup(this, "MyKeyLookup", new KeyLookupOptions {
    AliasName = "alias/KeyAlias"
});

var role = new Role(this, "MyRole", new RoleProps {
    AssumedBy = new ServicePrincipal("lambda.amazonaws.com")
});
myKeyLookup.GrantEncryptDecrypt(role);
go
myKeyLookup := kms.Key_FromLookup(this, jsii.String("MyKeyLookup"), &KeyLookupOptions{
	AliasName: jsii.String("alias/KeyAlias"),
})

role := iam.NewRole(this, jsii.String("MyRole"), &RoleProps{
	AssumedBy: iam.NewServicePrincipal(jsii.String("lambda.amazonaws.com")),
})
myKeyLookup.GrantEncryptDecrypt(role)

Note that a call to .addToResourcePolicy(statement) on myKeyLookup will not have an affect on the key's policy because it is not owned by your stack. The call will be a no-op.

If the target key is not found in your account, an error will be thrown. To prevent the error in the case, you can receive a dummy key without the error by setting returnDummyKeyOnMissing to true. The dummy key has a keyId of 1234abcd-12ab-34cd-56ef-1234567890ab. The value of the dummy key id can also be referenced using the Key.DEFAULT_DUMMY_KEY_ID variable, and you can check if the key is a dummy key by using the Key.isLookupDummy() method.

ts
const dummy = kms.Key.fromLookup(this, 'MyKeyLookup', {
  aliasName: 'alias/NonExistentAlias',
  returnDummyKeyOnMissing: true,
});

if (kms.Key.isLookupDummy(dummy)) {
  // alternative process
}
python
dummy = kms.Key.from_lookup(self, "MyKeyLookup",
    alias_name="alias/NonExistentAlias",
    return_dummy_key_on_missing=True
)

if kms.Key.is_lookup_dummy(dummy):
    pass
java
IKey dummy = Key.fromLookup(this, "MyKeyLookup", KeyLookupOptions.builder()
        .aliasName("alias/NonExistentAlias")
        .returnDummyKeyOnMissing(true)
        .build());

if (Key.isLookupDummy(dummy)) {
}
csharp
var dummy = Key.FromLookup(this, "MyKeyLookup", new KeyLookupOptions {
    AliasName = "alias/NonExistentAlias",
    ReturnDummyKeyOnMissing = true
});

if (Key.IsLookupDummy(dummy))
{
}
go
dummy := kms.Key_FromLookup(this, jsii.String("MyKeyLookup"), &KeyLookupOptions{
	AliasName: jsii.String("alias/NonExistentAlias"),
	ReturnDummyKeyOnMissing: jsii.Boolean(true),
})

if kms.Key_IsLookupDummy(dummy) {}

Key Policies ​

Controlling access and usage of KMS Keys requires the use of key policies (resource-based policies attached to the key); this is in contrast to most other AWS resources where access can be entirely controlled with IAM policies, and optionally complemented with resource policies. For more in-depth understanding of KMS key access and policies, see

KMS keys can be created to trust IAM policies. This is the default behavior for both the KMS APIs and in the console. This behavior is enabled by the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag, which is set for all new projects; for existing projects, this same behavior can be enabled by passing the trustAccountIdentities property as true when creating the key:

ts
new kms.Key(this, 'MyKey', { trustAccountIdentities: true });
python
kms.Key(self, "MyKey", trust_account_identities=True)
java
Key.Builder.create(this, "MyKey").trustAccountIdentities(true).build();
csharp
new Key(this, "MyKey", new KeyProps { TrustAccountIdentities = true });
go
kms.NewKey(this, jsii.String("MyKey"), &KeyProps{
	TrustAccountIdentities: jsii.Boolean(true),
})

With either the @aws-cdk/aws-kms:defaultKeyPolicies feature flag set, or the trustAccountIdentities prop set, the Key will be given the following default key policy:

json
{
  "Effect": "Allow",
  "Principal": {"AWS": "arn:aws:iam::111122223333:root"},
  "Action": "kms:*",
  "Resource": "*"
}

This policy grants full access to the key to the root account user. This enables the root account user -- via IAM policies -- to grant access to other IAM principals. With the above default policy, future permissions can be added to either the key policy or IAM principal policy.

ts
const key = new kms.Key(this, 'MyKey');
const user = new iam.User(this, 'MyUser');
key.grants.encrypt(user); // Adds encrypt permissions to user policy; key policy is unmodified.
python
key = kms.Key(self, "MyKey")
user = iam.User(self, "MyUser")
key.grants.encrypt(user)
java
Key key = new Key(this, "MyKey");
User user = new User(this, "MyUser");
key.grants.encrypt(user);
csharp
var key = new Key(this, "MyKey");
var user = new User(this, "MyUser");
key.Grants.Encrypt(user);
go
key := kms.NewKey(this, jsii.String("MyKey"))
user := iam.NewUser(this, jsii.String("MyUser"))
key.grants.Encrypt(user)

Adopting the default KMS key policy (and so trusting account identities) solves many issues around cyclic dependencies between stacks. Without this default key policy, future permissions must be added to both the key policy and IAM principal policy, which can cause cyclic dependencies if the permissions cross stack boundaries. (For example, an encrypted bucket in one stack, and Lambda function that accesses it in another.)

Appending to or replacing the default key policy ​

The default key policy can be amended or replaced entirely, depending on your use case and requirements. A common addition to the key policy would be to add other key admins that are allowed to administer the key (e.g., change permissions, revoke, delete). Additional key admins can be specified at key creation or after via the key.grants.admin method.

ts
const myTrustedAdminRole = iam.Role.fromRoleArn(this, 'TrustedRole', 'arn:aws:iam:....');
const key = new kms.Key(this, 'MyKey', {
  admins: [myTrustedAdminRole],
});

const secondKey = new kms.Key(this, 'MyKey2');
secondKey.grants.admin(myTrustedAdminRole);
python
my_trusted_admin_role = iam.Role.from_role_arn(self, "TrustedRole", "arn:aws:iam:....")
key = kms.Key(self, "MyKey",
    admins=[my_trusted_admin_role]
)

second_key = kms.Key(self, "MyKey2")
second_key.grants.admin(my_trusted_admin_role)
java
IRole myTrustedAdminRole = Role.fromRoleArn(this, "TrustedRole", "arn:aws:iam:....");
Key key = Key.Builder.create(this, "MyKey")
        .admins(List.of(myTrustedAdminRole))
        .build();

Key secondKey = new Key(this, "MyKey2");
secondKey.grants.admin(myTrustedAdminRole);
csharp
var myTrustedAdminRole = Role.FromRoleArn(this, "TrustedRole", "arn:aws:iam:....");
var key = new Key(this, "MyKey", new KeyProps {
    Admins = new [] { myTrustedAdminRole }
});

var secondKey = new Key(this, "MyKey2");
secondKey.Grants.Admin(myTrustedAdminRole);
go
myTrustedAdminRole := iam.Role_FromRoleArn(this, jsii.String("TrustedRole"), jsii.String("arn:aws:iam:...."))
key := kms.NewKey(this, jsii.String("MyKey"), &KeyProps{
	Admins: []IPrincipal{
		myTrustedAdminRole,
	},
})

secondKey := kms.NewKey(this, jsii.String("MyKey2"))
secondKey.grants.Admin(myTrustedAdminRole)

Alternatively, a custom key policy can be specified, which will replace the default key policy.

Note: In applications without the '@aws-cdk/aws-kms:defaultKeyPolicies' feature flag set and with trustedAccountIdentities set to false (the default), specifying a policy at key creation appends the provided policy to the default key policy, rather than replacing the default policy.

ts
const myTrustedAdminRole = iam.Role.fromRoleArn(this, 'TrustedRole', 'arn:aws:iam:....');
// Creates a limited admin policy and assigns to the account root.
const myCustomPolicy = new iam.PolicyDocument({
  statements: [new iam.PolicyStatement({
    actions: [
      'kms:Create*',
      'kms:Describe*',
      'kms:Enable*',
      'kms:List*',
      'kms:Put*',
    ],
    principals: [new iam.AccountRootPrincipal()],
    resources: ['*'],
  })],
});
const key = new kms.Key(this, 'MyKey', {
  policy: myCustomPolicy,
});
python
my_trusted_admin_role = iam.Role.from_role_arn(self, "TrustedRole", "arn:aws:iam:....")
# Creates a limited admin policy and assigns to the account root.
my_custom_policy = iam.PolicyDocument(
    statements=[iam.PolicyStatement(
        actions=["kms:Create*", "kms:Describe*", "kms:Enable*", "kms:List*", "kms:Put*"
        ],
        principals=[iam.AccountRootPrincipal()],
        resources=["*"]
    )]
)
key = kms.Key(self, "MyKey",
    policy=my_custom_policy
)
java
IRole myTrustedAdminRole = Role.fromRoleArn(this, "TrustedRole", "arn:aws:iam:....");
// Creates a limited admin policy and assigns to the account root.
PolicyDocument myCustomPolicy = PolicyDocument.Builder.create()
        .statements(List.of(PolicyStatement.Builder.create()
                .actions(List.of("kms:Create*", "kms:Describe*", "kms:Enable*", "kms:List*", "kms:Put*"))
                .principals(List.of(new AccountRootPrincipal()))
                .resources(List.of("*"))
                .build()))
        .build();
Key key = Key.Builder.create(this, "MyKey")
        .policy(myCustomPolicy)
        .build();
csharp
var myTrustedAdminRole = Role.FromRoleArn(this, "TrustedRole", "arn:aws:iam:....");
// Creates a limited admin policy and assigns to the account root.
var myCustomPolicy = new PolicyDocument(new PolicyDocumentProps {
    Statements = new [] { new PolicyStatement(new PolicyStatementProps {
        Actions = new [] { "kms:Create*", "kms:Describe*", "kms:Enable*", "kms:List*", "kms:Put*" },
        Principals = new [] { new AccountRootPrincipal() },
        Resources = new [] { "*" }
    }) }
});
var key = new Key(this, "MyKey", new KeyProps {
    Policy = myCustomPolicy
});
go
myTrustedAdminRole := iam.Role_FromRoleArn(this, jsii.String("TrustedRole"), jsii.String("arn:aws:iam:...."))
// Creates a limited admin policy and assigns to the account root.
myCustomPolicy := iam.NewPolicyDocument(&PolicyDocumentProps{
	Statements: []PolicyStatement{
		iam.NewPolicyStatement(&PolicyStatementProps{
			Actions: []*string{
				jsii.String("kms:Create*"),
				jsii.String("kms:Describe*"),
				jsii.String("kms:Enable*"),
				jsii.String("kms:List*"),
				jsii.String("kms:Put*"),
			},
			Principals: []IPrincipal{
				iam.NewAccountRootPrincipal(),
			},
			Resources: []*string{
				jsii.String("*"),
			},
		}),
	},
})
key := kms.NewKey(this, jsii.String("MyKey"), &KeyProps{
	Policy: myCustomPolicy,
})

Warning: Replacing the default key policy with one that only grants access to a specific user or role runs the risk of the key becoming unmanageable if that user or role is deleted. It is highly recommended that the key policy grants access to the account root, rather than specific principals. See https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html for more information.

Signing and Verification key policies ​

Creating signatures and verifying them with KMS requires specific permissions. The respective policies can be attached to a principal via the key.grants.sign and key.grants.verify methods.

ts
const key = new kms.Key(this, 'MyKey');
const user = new iam.User(this, 'MyUser');
key.grants.sign(user); // Adds 'kms:Sign' to the principal's policy
key.grants.verify(user); // Adds 'kms:Verify' to the principal's policy
python
key = kms.Key(self, "MyKey")
user = iam.User(self, "MyUser")
key.grants.sign(user) # Adds 'kms:Sign' to the principal's policy
key.grants.verify(user)
java
Key key = new Key(this, "MyKey");
User user = new User(this, "MyUser");
key.grants.sign(user); // Adds 'kms:Sign' to the principal's policy
key.grants.verify(user);
csharp
var key = new Key(this, "MyKey");
var user = new User(this, "MyUser");
key.Grants.Sign(user); // Adds 'kms:Sign' to the principal's policy
key.Grants.Verify(user);
go
key := kms.NewKey(this, jsii.String("MyKey"))
user := iam.NewUser(this, jsii.String("MyUser"))
key.grants.Sign(user) // Adds 'kms:Sign' to the principal's policy
key.grants.Verify(user)

If both sign and verify permissions are required, they can be applied with one method in KeyGrants called signVerify.

ts
const key = new kms.Key(this, 'MyKey');
const user = new iam.User(this, 'MyUser');
key.grants.signVerify(user); // Adds 'kms:Sign' and 'kms:Verify' to the principal's policy
python
key = kms.Key(self, "MyKey")
user = iam.User(self, "MyUser")
key.grants.sign_verify(user)
java
Key key = new Key(this, "MyKey");
User user = new User(this, "MyUser");
key.grants.signVerify(user);
csharp
var key = new Key(this, "MyKey");
var user = new User(this, "MyUser");
key.Grants.SignVerify(user);
go
key := kms.NewKey(this, jsii.String("MyKey"))
user := iam.NewUser(this, jsii.String("MyUser"))
key.grants.SignVerify(user)

HMAC specific key policies ​

HMAC keys have a different key policy than other KMS keys. They have a policy for generating and for verifying a MAC. The respective policies can be attached to a principal via the generateMac and verifyMac methods in KeyGrants.

ts
const key = new kms.Key(this, 'MyKey');
const user = new iam.User(this, 'MyUser');
key.grants.generateMac(user); // Adds 'kms:GenerateMac' to the principal's policy
key.grants.verifyMac(user); // Adds 'kms:VerifyMac' to the principal's policy
python
key = kms.Key(self, "MyKey")
user = iam.User(self, "MyUser")
key.grants.generate_mac(user) # Adds 'kms:GenerateMac' to the principal's policy
key.grants.verify_mac(user)
java
Key key = new Key(this, "MyKey");
User user = new User(this, "MyUser");
key.grants.generateMac(user); // Adds 'kms:GenerateMac' to the principal's policy
key.grants.verifyMac(user);
csharp
var key = new Key(this, "MyKey");
var user = new User(this, "MyUser");
key.Grants.GenerateMac(user); // Adds 'kms:GenerateMac' to the principal's policy
key.Grants.VerifyMac(user);
go
key := kms.NewKey(this, jsii.String("MyKey"))
user := iam.NewUser(this, jsii.String("MyUser"))
key.grants.GenerateMac(user) // Adds 'kms:GenerateMac' to the principal's policy
key.grants.VerifyMac(user)

Granting permissions for L1s ​

The examples above show how to use the KeyGrants methods to grant permissions to principals. If you are using L1 constructs that require permissions to be granted to a principal, you can use the KeyGrants utility class:

ts
declare const principal: iam.IPrincipal;
declare const key: kms.IKeyRef; // can be either an L1 or L2

kms.KeyGrants.fromKey(key).sign(principal);
python
# principal: iam.IPrincipal
# key: kms.IKeyRef
# can be either an L1 or L2

kms.KeyGrants.from_key(key).sign(principal)
java
IPrincipal principal;
IKeyRef key;
// can be either an L1 or L2

KeyGrants.fromKey(key).sign(principal);
csharp
IPrincipal principal;
IKeyRef key;
// can be either an L1 or L2

KeyGrants.FromKey(key).Sign(principal);
go
var principal IPrincipal
var key IKeyRef
// can be either an L1 or L2

kms.KeyGrants_FromKey(key).Sign(principal)

If key is an instance of CfnKey, and the grants process involves adding statements to the key policy, then the KeyGrants class will, by default, do the same thing it would do for an instance of Key: add statements to the keyPolicy property.

But if you want to customize this behavior, you can register an instance of IResourcePolicyFactory for the AWS::KMS::Key CloudFormation type:

ts
import { CfnResource } from 'aws-cdk-lib';
import { AddToResourcePolicyResult, IResourcePolicyFactory, IResourceWithPolicyV2, PolicyStatement, ResourceWithPolicies } from 'aws-cdk-lib/aws-iam';
import { ResourceEnvironment } from 'aws-cdk-lib/interfaces';
import { Construct } from 'constructs';


declare const scope: Construct;

class MyResourceWithPolicy implements IResourceWithPolicyV2 {
  public readonly env: ResourceEnvironment;
  private readonly resource: CfnResource;

  constructor(resource: CfnResource) {
    this.resource = resource;
    this.env = resource.env;
  }

  public addToResourcePolicy(statement: PolicyStatement): AddToResourcePolicyResult {
    // custom implementation to add the statement to the resource policy
    return { statementAdded: true, policyDependable: this.resource };
  }
}

class MyFactory implements IResourcePolicyFactory {
  public forResource(resource: CfnResource): IResourceWithPolicyV2 {
    return new MyResourceWithPolicy(resource);
  }
}

ResourceWithPolicies.register(scope, 'AWS::KMS::Key', new MyFactory());
python
from aws_cdk.aws_iam import AddToResourcePolicyResult
from aws_cdk import CfnResource
from aws_cdk.aws_iam import AddToResourcePolicyResult, IResourcePolicyFactory, IResourceWithPolicyV2, PolicyStatement, ResourceWithPolicies
from aws_cdk.interfaces import ResourceEnvironment
from constructs import Construct

# scope: Construct

@jsii.implements(IResourceWithPolicyV2)
class MyResourceWithPolicy:

    def __init__(self, resource):
        self.resource = resource
        self.env = resource.env

    def add_to_resource_policy(self, statement):
        # custom implementation to add the statement to the resource policy
        return AddToResourcePolicyResult(statement_added=True, policy_dependable=self.resource)

@jsii.implements(IResourcePolicyFactory)
class MyFactory:
    def for_resource(self, resource):
        return MyResourceWithPolicy(resource)

ResourceWithPolicies.register(scope, "AWS::KMS::Key", MyFactory())
java
import software.amazon.awscdk.CfnResource;
import software.amazon.awscdk.services.iam.AddToResourcePolicyResult;
import software.amazon.awscdk.services.iam.IResourcePolicyFactory;
import software.amazon.awscdk.services.iam.IResourceWithPolicyV2;
import software.amazon.awscdk.services.iam.PolicyStatement;
import software.amazon.awscdk.services.iam.ResourceWithPolicies;
import software.amazon.awscdk.interfaces.ResourceEnvironment;
import software.constructs.Construct;

Construct scope;

public class MyResourceWithPolicy implements IResourceWithPolicyV2 {
    public final ResourceEnvironment env;
    private final CfnResource resource;

    public MyResourceWithPolicy(CfnResource resource) {
        this.resource = resource;
        this.env = resource.getEnv();
    }

    public AddToResourcePolicyResult addToResourcePolicy(PolicyStatement statement) {
        // custom implementation to add the statement to the resource policy
        return AddToResourcePolicyResult.builder().statementAdded(true).policyDependable(this.resource).build();
    }
}

public class MyFactory implements IResourcePolicyFactory {
    public IResourceWithPolicyV2 forResource(CfnResource resource) {
        return new MyResourceWithPolicy(resource);
    }
}

ResourceWithPolicies.register(scope, "AWS::KMS::Key", new MyFactory());
csharp
using Amazon.CDK;
using Amazon.CDK.AWS.IAM;
using Amazon.CDK.Interfaces;
using Constructs;

Construct scope;

class MyResourceWithPolicy : IResourceWithPolicyV2
{
    public ResourceEnvironment Env { get; }
    private readonly CfnResource resource;

    public MyResourceWithPolicy(CfnResource resource)
    {
        resource = resource;
        Env = resource.Env;
    }

    public AddToResourcePolicyResult AddToResourcePolicy(PolicyStatement statement)
    {
        // custom implementation to add the statement to the resource policy
        return new AddToResourcePolicyResult { StatementAdded = true, PolicyDependable = resource };
    }
}

class MyFactory : IResourcePolicyFactory
{
    public IResourceWithPolicyV2 ForResource(CfnResource resource)
    {
        return new MyResourceWithPolicy(resource);
    }
}

ResourceWithPolicies.Register(scope, "AWS::KMS::Key", new MyFactory());
go
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/constructs-go/constructs"

var scope Construct

type myResourceWithPolicy struct {
	env ResourceEnvironment
	resource CfnResource
}

func newMyResourceWithPolicy(resource CfnResource) *myResourceWithPolicy {
	this := &myResourceWithPolicy{}
	this.resource = resource
	this.env = resource.env
	return this
}

func (this *myResourceWithPolicy) addToResourcePolicy(statement PolicyStatement) AddToResourcePolicyResult {
	// custom implementation to add the statement to the resource policy
	return &AddToResourcePolicyResult{
		StatementAdded: jsii.Boolean(true),
		PolicyDependable: this.resource,
	}
}

type myFactory struct {
}

func (this *myFactory) forResource(resource CfnResource) IResourceWithPolicyV2 {
	return NewMyResourceWithPolicy(*resource)
}

awscdk.ResourceWithPolicies_Register(scope, jsii.String("AWS::KMS::Key"), NewMyFactory())

IResourcePolicyFactory is responsible for converting a construct into a IResourceWithPolicyV2, effectively providing an ad-hoc way to extend the behavior of L1s to support grants the same way as L2s do.

Types ​

NameKindSummary
AliasConstruct (L2)Defines a display name for a customer master key (CMK) in AWS Key Management Service (AWS KMS).
KeyConstruct (L2)Defines a KMS key.
CfnAliasConstruct (L1)The AWS::KMS::Alias resource specifies a display name for a KMS key . You can use an alias to identify a KMS key in the AWS console, in the DescribeKey operation, and in cryptographic operations , such as Decrypt and GenerateDataKey .
CfnKeyConstruct (L1)The AWS::KMS::Key resource specifies an KMS key in AWS Key Management Service . You can use this resource to create symmetric encryption KMS keys, asymmetric KMS keys for encryption or signing, and symmetric HMAC KMS keys. You can use AWS::KMS::Key to create multi-Region primary keys of all supported types. To replicate a multi-Region key, use the AWS::KMS::ReplicaKey resource.
CfnReplicaKeyConstruct (L1)The AWS::KMS::ReplicaKey resource specifies a multi-Region replica key that is based on a multi-Region primary key.
AliasAttributesStructProperties of a reference to an existing KMS Alias.
AliasPropsStructConstruction properties for a KMS Key Alias object.
CfnAliasPropsStructProperties for defining a CfnAlias.
CfnKeyPropsStructProperties for defining a CfnKey.
CfnReplicaKeyPropsStructProperties for defining a CfnReplicaKey.
IAliasInterfaceA KMS Key alias.
IKeyInterfaceA KMS Key, either managed by this CDK app, or imported.
KeyGrantsFacadeCollection of grant methods for an IKey.
KeyLookupOptionsStructProperties for looking up an existing Key.
KeyPropsStructConstruction properties for a KMS Key object.
KeySpecEnumThe key spec, represents the cryptographic configuration of keys.
KeyUsageEnumThe key usage, represents the cryptographic operations of keys.
ViaServicePrincipalClassA principal to allow access to a key if it's being used through another AWS service.