AnalysisType: policy
Filename: aws_kms_key_policy_restricts_usage.py
PolicyID: "AWS.KMS.RestrictsUsage"
DisplayName: "AWS KMS Key Restricts Usage"
Enabled: true
ResourceTypes:
- AWS.KMS.Key
Tags:
- AWS
- PCI
- Credential Access:Unsecured Credentials
Reports:
PCI:
- 3.5.2
MITRE ATT&CK:
- TA0006:T1552
Severity: High
Description: >
This policy validates that KMS Keys restrict what entities can use them and how. This is to ensure that encryption keys are limited in who can use them in order to prevent unapproved decryption.
Runbook: Add appropriate limitations to the KMS Key's policy.
Reference: https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html
Tests:
- Name: Key Usage Not Restricted
ExpectedResult: false
Resource:
{
"KeyRotationEnabled": true,
"AWSAccountId": "1122334455",
"Arn": "arn:aws:kms:us-west-2:11223344:key/1122233-asdf-adsf-111222333",
"CloudHsmClusterId": null,
"CreationDate": "2019-01-01T00:00:00Z",
"CustomKeyStoreId": null,
"DeletionDate": null,
"Description": "Default master key that protects my Secrets Manager data when no other key is defined",
"Enabled": false,
"ExpirationModel": null,
"KeyId": "1122233-asdf-adsf-111222333",
"KeyManager": "AWS",
"KeyState": "Enabled",
"KeyUsage": "ENCRYPT_DECRYPT",
"Origin": "AWS_KMS",
"ValidTo": null,
"Policy": "{\n \"Version\" : \"2012-10-17\",\n \"Id\" : \"use-key\",\n \"Statement\" : [ {\n \"Sid\" : \"Allow access\",\n \"Effect\" : \"Allow\",\n \"Principal\" : {\n \"AWS\" : \"*\"\n },\n \"Action\" : [ \"kms:*\", \"kms:Decrypt\", \"kms:ReEncrypt*\", \"kms:GenerateDataKey*\", \"kms:CreateGrant\", \"kms:DescribeKey\" ],\n \"Resource\" : \"*\"} ]\n}",
}
- Name: Key Restricts Usage With Condition
ExpectedResult: true
Resource:
{
"KeyRotationEnabled": true,
"AWSAccountId": "1122334455",
"Arn": "arn:aws:kms:us-west-2:11223344:key/1122233-asdf-adsf-111222333",
"CloudHsmClusterId": null,
"CreationDate": "2019-01-01T00:00:00Z",
"CustomKeyStoreId": null,
"DeletionDate": null,
"Description": "Example key",
"Enabled": false,
"ExpirationModel": null,
"KeyId": "1122233-asdf-adsf-111222333",
"KeyManager": "AWS",
"KeyState": "Enabled",
"KeyUsage": "ENCRYPT_DECRYPT",
"Origin": "AWS_KMS",
"ValidTo": null,
"Policy": "{\n \"Version\" : \"2012-10-17\",\n \"Id\" : \"use key\",\n \"Statement\" : [ {\n \"Sid\" : \"Allow access\",\n \"Effect\" : \"Allow\",\n \"Principal\" : {\n \"AWS\" : \"*\"\n },\n \"Action\" : [ \"kms:Encrypt\", \"kms:Decrypt\"],\n \"Resource\" : \"*\",\n \"Condition\" : {\n \"StringEquals\" : {\n \"kms:CallerAccount\" : \"123456789012\",\n \"kms:ViaService\" : \"lambda.us-east-1.amazonaws.com\"\n }\n }\n } ]\n}",
}
# ------ paired body: aws_kms_key_policy_restricts_usage.py ------
import json
from policyuniverse.policy import Policy
BAD_PRINCIPALS = {
"*",
}
BAD_ACTIONS = {
"*",
"kms:*",
}
def policy(resource):
if resource["Policy"] is None:
return True
iam_policy = Policy(json.loads(resource["Policy"]))
for statement in iam_policy.statements:
# Only apply to allow effects
if statement.effect != "Allow":
continue
# Don't apply where there are strong conditions
if statement.condition_entries:
continue
if BAD_PRINCIPALS.intersection(statement.principals) and BAD_ACTIONS.intersection(
statement.actions
):
return False
if statement.uses_not_principal():
return False
return True