AWS Key Management Service (AWS KMS) is a managed service that makes it easy for you to create and control the cryptographic keys used to protect your data. This service easily integrates with other AWS services, such as Secrets Manager, RDS, and S3 (the full list can be found here), to facilitate the encryption of your data. For auditing purposes, you can use AWS CloudTrail to log all API calls made on your keys. If you use AWS cloud services, you most certainly will encounter an option to set encryption for an S3 bucket or an EC2 volume. This encryption is done with KMS.
KMS Key Types
The primary resource of AWS KMS is the keys. They are used for encryption, decryption, and re-encryption of data. A KMS key is a logical representation of a cryptographic key. It contains metadata, such as the key ID, key spec, key usage, creation date, description, key state, and a reference to the key material that is used when you run cryptographic operations. By default, key material is generated by AWS, but it can also be imported (more information on importing key material).
There are three types of keys - customer managed keys, AWS managed keys, and AWS owned keys.
Below is a table that sums up the main differences between the three:
Customer managed keys
Customer managed keys are KMS keys that you create, own, and manage. You are responsible for every aspect - access, status, rotation, and more. You can use your customer managed key for cryptographic operations such as encrypt, decrypt, sign, and verify. All KMS operations (from kms:DescribeKey to kms:Decrypt) can be audited in AWS CloudTrail logs. In addition, many AWS services that integrate with AWS KMS let you specify a customer managed key to protect the data stored and managed for you. For instance, when you want to enable default encryption for an S3 bucket, you can choose to use one of your customer managed keys.
Below is a CLI command that describes a customer managed KMS key. The “KeyManager” field value is set to “CUSTOMER”.
aws kms describe-key --key-id KEY-ID --region REGION
AWS managed keys
AWS managed keys are KMS keys in your account created, managed, and used on your behalf by another AWS service (their alias is aws/service-name). If we look again at the S3 example above, we can see that there is an option to choose the KMS key aws/s3; this is an AWS managed key for this service.
You can view the AWS managed keys in your account, check their key policies, and audit their use in AWS CloudTrail logs. However, you cannot manage these KMS keys, rotate them, or change their key policies. You also cannot use AWS managed keys in cryptographic operations directly; the service that creates them uses them on your behalf. All AWS managed keys are automatically rotated every year, that cannot be changed (Rotating Keys).
Below is a CLI command that describes an AWS managed KMS key. The “KeyManager” field value is set to “AWS”.
aws kms describe-key --key-id KEY-ID --region REGION
AWS owned keys
AWS owned keys are a collection of KMS keys that an AWS service owns and manages for use in multiple AWS accounts. Although AWS owned keys are not in your AWS account, an AWS service can use the associated AWS owned keys to protect the resources in your account. For enabling default encryption of a bucket, you can choose to use an AWS owned key:
You do not need to create or manage the AWS owned keys. You also cannot view, use, track, or audit them. We cannot get any information about an AWS owned key; therefore, we cannot use the describe-key command on them.
Which type should you use?
For this discussion, we will set aside the AWS owned keys, as we do not have any control over them.
So, should you go with customer managed or AWS managed keys? It depends. From a security perspective, neither one is better than the other. You can decide based on your needs. An AWS managed key can only be used to protect resources within the specific AWS service for which it is created, and there are less access control mechanisms that can be used (less room for human error and misconfigurations). On the other hand, customer managed keys give you more control over access and management. Moreover, if you need to import your own key material, customer managed keys are your only option.
Below is another chart to help you decide between the two:
Access Control for KMS Keys
To have any sort of access to KMS keys, from creating and viewing, to using keys in cryptographic operations, one must have valid AWS credentials for authentication. In terms of authorization, like all other AWS services and resources, there are no principals that have implicit KMS permissions. Permissions need to be actively provided. There are three access control mechanisms for managing access to AWS KMS resources – key policies, IAM (Identity Access Management) policies, and grants. For a principal to have access to a KMS key there must be an explicit allow in at least one of key policy, IAM policy or grants, and no deny in all of them (grants cannot deny access, so a deny statement can only appear in the key policy or in an IAM policy).
A key policy is a resource-based policy, and it is the primary way to control access to KMS keys. Each KMS key must have exactly one key policy. Resource-based policies determine who can perform certain actions on the resource to which they are attached. In this case, who is able to use the KMS key and what they can do with it. As mentioned, access to KMS keys can also be controlled using IAM policies. However, if the key policy (or a grant, as will be discussed further in the next sections) does not allow the use of IAM policies they will have no effect (unless they deny permissions).
Default Key Policy
When creating a new KMS key, you can specify a key policy. If you do not, AWS will use a key policy of their own – the default key policy. It is important to know that AWS's default key policy is not necessarily the same when you create a key using the console and using the KMS API. When you use the KMS API (CLI for instance) to create a KMS key, the default key policy will contain one statement that gives the AWS account that owns the KMS key permission to use IAM policies to allow access to all AWS KMS operations on the KMS key.
Below is a CLI command that creates a new customer managed KMS key with a default key policy.
aws kms create-key --region REGION
Checking the key policy:
aws kms get-key-policy --key-id KEY-ID --policy-name default --region REGION --output text | jq '.'
This key policy only contains one statement that allows the use of IAM policies to control access to the key.
When you use the console, the default key policy begins with the statement that enables the use of IAM permissions (statement number 1 in the picture below). It then adds more statements depending on the creation process. During the creation, you can specify users, roles, and accounts that will have administrating or using (or both) permissions. Administrating permissions refers to permissions to manage the KMS key (such as kms:EnableKey, kms:CreateGrant, and kms:EnableKeyRotation). Using permissions refers to permissions to use the KMS key in cryptographic operations (such as kms:Encrypt, and kms:Decrypt). Based on that, two policy statements will be added – one for the key administrators (statement number 2 in the picture below), and one for the key users (statement number 3 in the picture below). The last statement (statement number 4 in the picture below) that appears in the default key policy, allows principals to use the key with other AWS services. This statement allows the key user to create, view, and revoke grants on the KMS key, but only when the grant operation request comes from an AWS service.
Console key policy:
Grants are another KMS access control mechanism. A grant allows the grantee principals to call the specified grant operations on the KMS key, provided that all conditions specified in the grant are met. They are often used for temporary permissions because you can create a grant, use its permissions, and delete it without changing your key policy or IAM policies. Grants are commonly used by AWS services that integrate with AWS KMS to encrypt your data at rest. The service creates a grant on behalf of a user in the account, uses its permissions, and retires (deletes in grant terminology) the grant as soon as its task is completed.
Everything you need to know about grants
Each grant allows access to a specific KMS key and can only allow access but not deny it. Access can be given to principals in the same AWS account or in another one. The use of grants does not require special action from the grantee; the grantee can use the permissions the same way they would use them if they came from a key policy or an IAM policy (the grant might not be effective immediately and for that, you might want to use a grant token). Deletion and creation of a grant can be done by authorized principals. The permission to create a grant is a powerful one, much like kms:PutKeyPolicy.
Principals that get the kms:CreateGrant permission from a key policy or from an IAM policy, can create grants for any grant operation on the KMS key, even if they do not have the permissions themselves. Distinctively, principals that get the kms:CreateGrant permission from a grant can only delegate the permissions that they were granted, even if they have other permissions from a key policy or an IAM policy (for more information, check Granting CreateGrant permission).
IAM policies can be used to control access to KMS keys. One of the following must exist:
- The key policy for the KMS key gives the account permission to use IAM policies. Specifically, the key policy includes the following statement:
If you change the action statement form kms:* to specific actions, only those actions can be used in IAM policies.
- There is a grant that allows the root user to perform certain KMS operations. The permissions that can be used in the IAM policies are limited to the equivalent actions of the allowed grant operations. For instance, if there is a grant that its grantee principal is the root user, and the allowed grant operation is decrypt, the only action that will have an effect in IAM policies is kms:Decrypt. This method is less common, and less recommended as grants are more suitable for temporary access.
The use of IAM policies is like all other AWS resources. You create a policy with KMS permissions and attach it to a user, group, or role.
Here is a link to all available KMS permissions - https://docs.aws.amazon.com/kms/latest/developerguide/kms-api-permissions-reference.html.
AWS KMS evaluates the following to authorize access:
- The key policy
- All IAM policies that are attached to the IAM user or role making the request
- All grants that apply to the KMS key
Other types of policies that might apply to the request to use the KMS key, such as AWS Organizations service control policies, and VPC endpoint policies. These policies are optional and allow all actions by default, but you can use them to restrict permissions otherwise given to principals.
To authorize access, AWS KMS takes all four and evaluates whether to allow or deny the request. Below is a flowchart from AWS’s documentation that describes the policy evaluation process:
Access Best Practices
To wrap up, we wanted to provide you with some security tips and best practices (this can also be helpful - kms-cheat-sheet)
- Old but gold – Follow the least privilege principle. Give only the required permissions to the relevant principals. Do not include kms:* permissions in an IAM policy or a key policy, an exception to this will be the key policy statement that allows the use of IAM policies. You can even create a top-level KMS policy that denies all access to KMS except for the principals that need it. This helps to prevent unauthorized users from giving themselves more access.
- Prefer the key policy over an IAM policy - Whenever possible, choose to use the key policy over an IAM policy, as it can affect only one KMS key. If you must use an IAM policy, specify KMS keys in the resource element if possible, or use values like arn:aws:kms:region:account:key/* or arn:aws:kms:*:account:key/* that still give some limitations.
- Risky permissions – Pay extra attention when dealing with risky permissions, such as kms:PutKeyPolicy, kms:CreateGrant, and kms:ScheduleKeyDeletion.
- Befriend the encryption context – An encryption context is an additional layer of authentication for your KMS API calls. It is a set of key pairs that can contain additional contextual information about the data. When you include an encryption context in an encryption request, the same encryption context is required to decrypt (or decrypt and re-encrypt) the data. If the encryption context provided in the decryption request is not an exact, case-sensitive match, the decrypt request fails. Incorporate the encryption context inside your policies and grants to enforce tighter controls for your encrypted resources (for more information, see encryption context).
- Multi-Factor Authentication – You can add MFA for certain API calls to add another layer of security. You can add a condition to the key policy that checks for when or if an MFA device was used as part of authentication. For example:
- Grants do not expire on their own – Remember to retire or revoke them when they are not needed anymore.
- Double is trouble – Delete duplicate grants (grants that have the same key ARN, API actions, grantee principal, encryption context, and name). Duplicate grants can lead to unintended privileges if one is retired or revoked.
- Auditing for ever - Enable CloudTrail logging to ensure that all KMS API calls made on keys in your AWS account are automatically logged. You can use this information to determine which request was made, the source IP address from which the request was made, who made the request, when it was made, and more. You can also use other monitoring services and create alerts on KMS events if desired.