AWS KMS Key Restricts Usage


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.

Query · python

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

Analyst notes

Add appropriate limitations to the KMS Key's policy.

Raw source AWS KMS Key Restricts Usage · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
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

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.