Securing AWS KMS key using key policy and IAM policy

AWS IAM policy contains the allowed actions for specified AWS resources. The policy is attached to a user, group, or role, allowing the principal to exercise the permissions defined in the policy. Apart from IAM policy, there is also a resource-based policy. This type of policy is attached directly to a resource instead of a principal.

For an AWS KMS key, the kms:ViaService condition key in the resource-based policy is worth a study.

Within the resource-based policy of an AWS KMS key with ARN arn:aws:kms:us-east-1:111122223333:key/some-key, we could specify the following in one of its policy statements:

{
  "Effect": "Allow",
  "Pricipal": {
    "AWS": "arn:aws:iam::111122223333:root"
  },
  "Actions": [
    "kms:Encrypt",
    "kms:Decrypt",
    "kms:GenerateDataKey*"
  ],
  "Resource": "*",
  "Condition": {
    "StringEquals": {
      "kms:ViaService": "secretsmanager.us-east-1.amazonaws.com",
      "kms:CallerAccount": "111122223333"
    }
  }
}

On the IAM policy that allows the consumption of the KMS key:

{
  "Effect": "Allow",
  "Actions": [
    "kms:Encrypt",
    "kms:Decrypt",
    "kms:GenerateDataKey*"
  ],
  "Resource": "arn:aws:kms:us-east-1:111122223333:key/some-key"
}

When the IAM policy is attached to a user named John, John can utilise the KMS key, but only if he uses the KMS key for the AWS Secrets Manager service in North Virginia (us-east-1) region.

Using this approach, we can define who can use the KMS key via IAM policy and what the key can be used for via AWS KMS resource-based policy, therefore tightening the security control on the KMS key usage.

Note that if we specify the principal in the resource-based policy as "AWS": "*" instead, the IAM policy becomes redundant since everyone can use the KMS key, as long as it is for AWS Secrets Manager.