AWS KMS Governance


Effective key management is a cornerstone of robust cloud security. AWS Key Management Service (KMS) provides a scalable and reliable solution for managing cryptographic keys. This guide explores best practices for AWS KMS governance, focusing on security, compliance, and operational efficiency.

Understanding AWS KMS Governance

KMS governance entails implementing policies and processes to manage key usage while ensuring compliance with organizational standards and regulatory requirements. A well-governed KMS framework enhances data protection, prevents unauthorized access, and supports audit readiness.

The primary goal of KMS key governance is to ensure that KMS keys are used appropriately and securely to protect sensitive data. KMS key governance encompasses several essential components:

  1. Key Creation and Rotation Policies: Establish policies for creating and rotating KMS keys, specifying requirements for key strength and rotation frequency.
  2. Key Usage Policies: Define policies for how KMS keys should be used, specifying which AWS services can access the keys, which IAM roles or users can utilize the keys, and the specific circumstances under which keys should be employed.
  3. Key Retention and Deletion Policies: Define policies for the retention period of KMS keys, their secure destruction at the end of their lifecycle, and the handling of any key material backups.
  4. Key Management and Monitoring: Establish processes for managing and monitoring KMS keys, including logging all key usage, conducting periodic audits of key usage, and enforcing stringent key access controls.

Separation of Duties Principle

Separation of duties (SoD) is a critical security principle designed to minimize risks such as fraud, errors, and unauthorized actions. By distributing roles and responsibilities across different individuals or teams, organizations ensure that no single entity has sufficient access to perform malicious or high-risk actions independently.

In AWS KMS, separation of duties typically involves the following roles:

  • Key Administrators: Responsible for creating, managing, and configuring keys and policies.
  • Key Owners: Oversee key permissions and delegate access to others.
  • Key Users: Applications or individuals with restricted access for encryption and decryption tasks.

aws-kms-roles

In AWS, it is strongly discouraged to manage keys using the root user, as it has unrestricted access to all resources. Instead, create a dedicated IAM role for key administration.

AWS key administrators may have full access to the KMS API (kms:*) to create and manage encryption keys. However, it’s advisable to avoid assigning full privileges to any role to adhere to the principle of least privilege

For example, the following actions limit an IAM principal to only create keys and update their policy, preventing them from using the key for encryption/decryption:

"Action": [
  kms:Create*  
  kms:PutKeyPolicy
]

Key Owners: Grant permissions limited to policy updates (kms:PutKeyPolicy) while safeguarding key privileges to prevent escalation.

"Action": [
  kms:PutKeyPolicy
]

Note that the above policy action allows key owners to elevate their KMS privileges by updating key policies. Therefore, it’s crucial to protect critical keys using service control policies at the AWS organization level.

Key Users: Restrict permissions to cryptographic operations required for their tasks.

"Action": [
    "kms:Encrypt",
    "kms:Decrypt",
    "kms:GenerateDataKey*",
    "kms:DescribeKey"
]

KMS Key Policy

A KMS key policy is a JSON document attached to a specific KMS key to define access control. It determines who can access the key and what actions they can perform, whether IAM users, roles, AWS services, or external accounts (via AWS account IDs or public keys). Using key-specific policies is recommended over broader IAM policies for fine-grained control.

Each KMS key (Customer Master Key, CMK) must have one key policy, which typically:

  • Grants the AWS root user full access.
  • Allows permission delegation via IAM policies, though IAM policy use can be disabled by including the following condition:
"Condition": {
    "StringEquals": {
        "aws:PrincipalType": "Account"
    }
}

This ensures centralized management of key permissions within KMS key policies.

A standard key policy might include:

  1. Granting the root user full access, with a condition to restrict IAM policies.
  2. Assigning permissions to key administrators (e.g., key creation and management).
  3. Defining cryptographic operation permissions for key users.
{
    "Version": "2012-10-17",
    "Id": "Key-policy",
    "Statement": [
        {
            "Sid": "Account root user has full access and IAM policies disabled",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
            },
            "Action": "kms:*",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "aws:PrincipalType": "Account"
                }
            }
        },
        {
            "Sid": "Key administrators can manage the lifecycle of this key",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::123456789012:role/keyadmin"
                ]
            },
            "Action": [
                "kms:Create*",
                "kms:Describe*",
                "kms:Enable*",
                "kms:List*",
                "kms:Put*",
                "kms:Update*",
                "kms:Revoke*",
                "kms:Disable*",
                "kms:Get*",
                "kms:Delete*",
                "kms:TagResource",
                "kms:UntagResource",
                "kms:ScheduleKeyDeletion",
                "kms:CancelKeyDeletion"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::123456789012:role/keyuser",
                ]
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        }
}

Hardening KMS API Access

To access KMS securely from within your VPC, you can create a VPC endpoint for the KMS service using AWS PrivateLink. This eliminates the need for public internet connectivity to KMS and ensures that all traffic between your VPC and KMS stays within the AWS network.

aws-kms-hardening

To secure a VPC endpoint in AWS, you can implement several measures, including:

  • To control access to the VPC endpoint, you can use VPC security groups to allow or deny inbound and outbound traffic to the endpoint based on IP addresses, protocols, and ports. You can also specify which instances or subnets can access the endpoint by associating the security group with the VPC endpoint.
  • You can create IAM policies to control which AWS accounts and roles have access to your VPC endpoints. IAM policies enable you to specify who can perform actions on the VPC endpoint and which actions they can perform.

It is also possible to restrict access to the KMS API using policy conditions. You can add a condition to your KMS key policy to deny encryption and decryption requests unless the request comes from the specified endpoint. The following example demonstrates this functionality:

{
  "Sid": "DenyIfRequestNotUsingVpcEndpoint" 
  "Effect": "Deny",
  "Principal": "*",
  "Action": [
      "kms:Encrypt",
      "kms:Decrypt"
  ],
  "Condition": {
      "StringNotEquals": {
          "aws:sourceVpce": "vpce-1234abcdf5678c90a"
       }
  }
}

VPC Endpoint Policy

VPC endpoint policies are resource policies that are specific to VPC endpoints. They allow you to control which VPCs and subnets can access the VPC endpoint and which AWS services the endpoint can reach. VPC endpoint policies are used to grant permissions to resources that are accessed through the VPC endpoint and are managed independently of IAM policies.

By attaching a VPC endpoint policy, it is possible to limit the allowed API operations that applications can invoke through VPC endpoints.

E.g. The following policy allows only encrypt and decrypt operations on the key specified by the resource ID.

{
   "Statement":[
      {
         "Sid": "AllowedKmsActions",
         "Principal": "*",
         "Effect": "Allow",
         "Action": [ 
             "kms:Decrypt",
             "kms:Encrypt"
          ],
         "Resource": "arn:aws:kms:eu-west-1:140545465132:key/1234abcd-12ab-34cd-56ef-1234567890ab"
      }
   ]
}

In the diagram above, the VPC endpoint is protected by a security group, which allows traffic only from the Kubernetes nodes. As the key policy denies encryption and decryption requests that don’t originate from the VPC endpoint, it is safe to say that only the applications running on the nodes can use this key for encrypting and decrypting data.

Service Control Policies

Service Control Policies (SCPs) are a powerful security mechanism that can be used to restrict access to AWS services and resources, including KMS keys, at the AWS Organization level.

SCPs can be used to restrict access to KMS keys based on specific criteria, such as the IAM user or role attempting to access the key or the AWS service being used. SCPs can also be used to control who can create and delete KMS keys within an AWS account. By limiting these actions to only authorized users or roles, you can reduce the risk of accidental or malicious deletion of keys.

The following SCP limits key deletions to only a single role.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "OnlyKMSGuardianCanDeleteThisKey",
            "Effect": "Allow",
            "Action": [
                "kms:ScheduleKeyDeletion",
                "kms:Delete*"
            ],
            "Resource": [
                "arn:aws:kms:us-west-2:123456789012:key/securekey"
            ],
            "Condition": {
                "StringEquals": {
                    "aws:PrincipalArn": [
                        "arn:aws:iam::123456789012:role/kmsguardian"
                    ]
                }
            }
        }
    ]
}