Skip to content

Commit

Permalink
Migrate KMS Microsoft_AD WAF CloudFront CloudWatch resources to cfn-g…
Browse files Browse the repository at this point in the history
…uard ruleset
  • Loading branch information
ysdholak committed Mar 19, 2024
1 parent 946508c commit 7529aa9
Show file tree
Hide file tree
Showing 16 changed files with 1,295 additions and 2 deletions.
2 changes: 2 additions & 0 deletions rules/aws/aws_kms/cmk_backing_key_rotation_enabled.guard
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#

let cmk_backing_key_rotation_enabled = Resources.*[ Type == "AWS::KMS::Key"
Metadata.cfn_nag.rules_to_suppress not exists or
Metadata.cfn_nag.rules_to_suppress.*.id != "F19"
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "CMK_BACKING_KEY_ROTATION_ENABLED"
]
Expand Down
51 changes: 51 additions & 0 deletions rules/aws/aws_kms/kms_no_wildcard_principal.guard
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#
#####################################
## AWS Solutions ##
#####################################
#
# Rule Identifier:
# KMS_NO_WILDCARD_PRINCIPAL
#
# Description:
# KMS key should not allow * principal
#
# Reports on:
# AWS::KMS::Key
#
# Evaluates:
# AWS CloudFormation
#
# Rule Parameters:
# NA
#
# CFN-NAG Rule
# F76
#
# Documentation:
# https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html
#
# Scenarios:
# a) SKIP: when there are no KMS CMKs
# b) SKIP: when metada has rule suppression for KMS_NO_WILDCARD_PRINCIPAL
# c) FAIL: when Principal: '*' appears in any KeyPolicy
# d) PASS: when no keypolicy has Principle: '*'

let kms_no_wildcard_principal = Resources.*[ Type == "AWS::KMS::Key"
Metadata.cfn_nag.rules_to_suppress not exists or
Metadata.cfn_nag.rules_to_suppress.*.id != "F76"
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "KMS_NO_WILDCARD_PRINCIPAL"
]

rule KMS_NO_WILDCARD_PRINCIPAL when %kms_no_wildcard_principal !empty {
let violations = %kms_no_wildcard_principal[
some Properties.KeyPolicy.Statement[*] {
Principal == '*'
}
]
%violations empty
<<
Violation: KMS key should not allow * principal.
Fix: Set the EnableKeyRotation property to true.
>>
}
44 changes: 44 additions & 0 deletions rules/aws/aws_kms/tests/cmk_backing_key_rotation_enabled_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,50 @@
rules:
CMK_BACKING_KEY_ROTATION_ENABLED: SKIP

- name: Scenario b) EnableKeyRotation has been set to false but rule suppressed - CFN_NAG, SKIP
input:
Resources:
myKMSKey:
Type: AWS::KMS::Key
Metadata:
cfn_nag:
rules_to_suppress:
- id: F19
reason: Suppressed for a very good reason
Properties:
EnableKeyRotation: false
KeyPolicy:
Statement:
- Action: kms:*
Effect: Allow
Principal:
AWS:
Fn::Join:
- ""
- - 'arn:'
- Ref: AWS::Partition
- :iam::123456789012:root
Resource: '*'
- Action:
- kms:Decrypt
- kms:DescribeKey
- kms:Encrypt
- kms:ReEncrypt*
- kms:GenerateDataKey*
Effect: Allow
Principal:
AWS:
Fn::Join:
- ""
- - 'arn:'
- Ref: AWS::Partition
- :iam::123456789012:root
Resource: '*'
Version: "2012-10-17"
expectations:
rules:
CMK_BACKING_KEY_ROTATION_ENABLED: SKIP

- name: Scenario c) EnableKeyRotation has not been set, FAIL
input:
Resources:
Expand Down
197 changes: 197 additions & 0 deletions rules/aws/aws_kms/tests/kms_no_wildcard_principal_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
###
# KMS_NO_WILDCARD_PRINCIPAL tests
###
---
- name: Empty, SKIP
input: {}
expectations:
rules:
KMS_NO_WILDCARD_PRINCIPAL: SKIP

- name: Scenario a) No resources, SKIP
input:
Resources: {}
expectations:
rules:
KMS_NO_WILDCARD_PRINCIPAL: SKIP

- name: KMS key with principal "*", FAIL
input:
Resources:
KMS_NO_WILDCARD_PRINCIPAL:
Type: AWS::KMS::Key
Properties:
KeyPolicy:
Statement:
- Action: kms:*
Effect: Allow
Principal:
AWS:
Fn::Join:
- ""
- - 'arn:'
- Ref: AWS::Partition
- :iam::123456789012:root
Resource: 'arn:aws:iam::111122223333:foobar'
- Action:
- kms:Decrypt
- kms:DescribeKey
- kms:Encrypt
- kms:ReEncrypt*
- kms:GenerateDataKey*
Effect: Allow
Principal: '*'
Resource: 'arn:aws:ec2:us-east-1:111122223333:foobar'
expectations:
rules:
KMS_NO_WILDCARD_PRINCIPAL: FAIL

- name: KMS key with principal NOT "*", PASS
input:
Resources:
KMS_NO_WILDCARD_PRINCIPAL:
Type: AWS::KMS::Key
Properties:
KeyPolicy:
Statement:
- Action: kms:*
Effect: Allow
Principal:
AWS:
Fn::Join:
- ""
- - 'arn:'
- Ref: AWS::Partition
- :iam::123456789012:root
Resource: 'arn:aws:iam::111122223333:foobar'
- Action:
- kms:Decrypt
- kms:DescribeKey
- kms:Encrypt
- kms:ReEncrypt*
- kms:GenerateDataKey*
Effect: Allow
Principal:
AWS:
Fn::Join:
- ""
- - 'arn:'
- Ref: AWS::Partition
- :iam::123456789012:root
Resource: 'arn:aws:ec2:us-east-1:111122223333:foobar'
expectations:
rules:
KMS_NO_WILDCARD_PRINCIPAL: PASS

##
## Suppressions
##
- name: F76 CFN-NAG suppression, SKIP
input:
Resources:
KMS_NO_WILDCARD_PRINCIPAL:
Type: AWS::KMS::Key
Properties:
KeyPolicy:
Statement:
- Action: kms:*
Effect: Allow
Principal:
AWS:
Fn::Join:
- ""
- - 'arn:'
- Ref: AWS::Partition
- :iam::123456789012:root
Resource: 'arn:aws:iam::111122223333:foobar'
- Action:
- kms:Decrypt
- kms:DescribeKey
- kms:Encrypt
- kms:ReEncrypt*
- kms:GenerateDataKey*
Effect: Allow
Principal: '*'
Resource: 'arn:aws:ec2:us-east-1:111122223333:foobar'
Metadata:
cfn_nag:
rules_to_suppress:
- id: F76
reason: Suppressed for a very good reason
expectations:
rules:
KMS_NO_WILDCARD_PRINCIPAL: SKIP

- name: cfn-guard suppression, SKIP
input:
Resources:
KMS_NO_WILDCARD_PRINCIPAL:
Type: AWS::KMS::Key
Properties:
KeyPolicy:
Statement:
- Action: kms:*
Effect: Allow
Principal:
AWS:
Fn::Join:
- ""
- - 'arn:'
- Ref: AWS::Partition
- :iam::123456789012:root
Resource: 'arn:aws:iam::111122223333:foobar'
- Action:
- kms:Decrypt
- kms:DescribeKey
- kms:Encrypt
- kms:ReEncrypt*
- kms:GenerateDataKey*
Effect: Allow
Principal: '*'
Resource: 'arn:aws:ec2:us-east-1:111122223333:foobar'
Metadata:
guard:
SuppressedRules:
- KMS_NO_WILDCARD_PRINCIPAL: Suppressed for a very good reason
expectations:
rules:
KMS_NO_WILDCARD_PRINCIPAL: SKIP

- name: cfn-guard and cfn-nag suppression, SKIP
input:
Resources:
KMS_NO_WILDCARD_PRINCIPAL:
Type: AWS::KMS::Key
Properties:
KeyPolicy:
Statement:
- Action: kms:*
Effect: Allow
Principal:
AWS:
Fn::Join:
- ""
- - 'arn:'
- Ref: AWS::Partition
- :iam::123456789012:root
Resource: 'arn:aws:iam::111122223333:foobar'
- Action:
- kms:Decrypt
- kms:DescribeKey
- kms:Encrypt
- kms:ReEncrypt*
- kms:GenerateDataKey*
Effect: Allow
Principal: '*'
Resource: 'arn:aws:ec2:us-east-1:111122223333:foobar'
Metadata:
cfn_nag:
rules_to_suppress:
- id: F76
reason: Suppressed for a very good reason
guard:
SuppressedRules:
- KMS_NO_WILDCARD_PRINCIPAL: Suppressed for a very good reason
expectations:
rules:
KMS_NO_WILDCARD_PRINCIPAL: SKIP
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#
#####################################
## AWS Solutions ##
#####################################
# Rule Identifier:
# MICROSOFT_AD_NO_PLAINTEXT_PASSWORD
#
# Description:
# Directory Service Microsoft AD password must not be a plaintext string or a Ref to a Parameter with a Default value.
# Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager/ssm-secure value.
# with a Default value. Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.
#
# Reports on:
# AWS::DirectoryService::MicrosoftAD
#
# Evaluates:
# AWS CloudFormation
#
# Rule Parameters:
# NA
#
# CFN_NAG Rule Id:
# F36
#
# Note: this rule works, however it sends the custom message twice for each resource
#
# Scenarios:
# a) SKIP: when there are no AWS::DirectoryService::MicrosoftAD present
# b) PASS: when all AWS::DirectoryService::MicrosoftAD use passwords from secure sources
# c) FAIL: when any AWS::DirectoryService::MicrosoftAD has a Password property not using a secure source
# d) SKIP: when metadata has rule suppression for MICROSOFT_AD_NO_PLAINTEXT_PASSWORD or CFN_NAG F36

let microsoft_ad_no_plaintext_password = Resources.*[ Type == 'AWS::DirectoryService::MicrosoftAD'
Metadata.cfn_nag.rules_to_suppress not exists or
Metadata.cfn_nag.rules_to_suppress.*.id != "F36"
Metadata.guard.SuppressedRules not exists or
Metadata.guard.SuppressedRules.* != "MICROSOFT_AD_NO_PLAINTEXT_PASSWORD"
]

# Get any AWS::DirectoryService::MicrosoftAD Refs for Password?
let microsoft_ad_password_refs = %microsoft_ad_no_plaintext_password.Properties.Password.'!Ref'

# Rule 1: when Microsoft AD password no plaintext password have Ref to Parameter for Password
rule MICROSOFT_AD_PASSWORD_USES_SECURE_PARAMETER when
%microsoft_ad_no_plaintext_password not empty
{
Parameters exists
Parameters not empty
%microsoft_ad_password_refs not empty
let parameter_refs = Parameters.%microsoft_ad_password_refs
when %parameter_refs !empty {
%parameter_refs.Type == 'String'
%parameter_refs.NoEcho exists
%parameter_refs.NoEcho == true
%parameter_refs.Default !exists
}
}

# Rule 2: when Microsoft AD password no plaintext password and above rule did not pass
rule MICROSOFT_AD_PASSWORD_USES_SECURE_SERVICE when
%microsoft_ad_no_plaintext_password not empty
!MICROSOFT_AD_PASSWORD_USES_SECURE_PARAMETER
{
%microsoft_ad_no_plaintext_password.Properties.Password exists
%microsoft_ad_no_plaintext_password.Properties.Password in [ /{{resolve\:secretsmanager\:.*}}/, /{{resolve\:ssm-secure\:.*}}/ ]
<<
Violation: Microsoft AD Password Endpoint password must not be a plaintext string or a Ref to a Parameter with a Default value. Can be Ref to a NoEcho Parameter without a Default, or a dynamic reference to a secretsmanager value.
Fix: Replace plaintext value with a secure one.
>>
}

# One rule to rule them all...
rule MICROSOFT_AD_NO_PLAINTEXT_PASSWORD when
%microsoft_ad_no_plaintext_password not empty
{
MICROSOFT_AD_PASSWORD_USES_SECURE_PARAMETER
OR
MICROSOFT_AD_PASSWORD_USES_SECURE_SERVICE
}
Loading

0 comments on commit 7529aa9

Please sign in to comment.