From 570fcd83c9127927a57666bcbc3567ea2047d510 Mon Sep 17 00:00:00 2001 From: ysdholak <140545342+ysdholak@users.noreply.github.com> Date: Wed, 20 Mar 2024 06:37:27 -0700 Subject: [PATCH] Migrate AWS cfn-authentication lambda opensource_service secrets_manager resources to cfn-guard ruleset (#270) --- .../cfn_authentication_rule.guard | 58 ++++ .../tests/cfn_authentication_rule_tests.yml | 279 ++++++++++++++++++ .../aws/lambda/lambda_concurrency_check.guard | 2 + rules/aws/lambda/lambda_inside_vpc.guard | 2 + .../lambda/lambda_no_wildcard_principal.guard | 51 ++++ ...da_permission_invoke_function_action.guard | 49 +++ .../tests/lambda_concurrency_check_tests.yml | 21 +- .../lambda/tests/lambda_inside_vpc_tests.yml | 19 ++ .../lambda_no_wildcard_principal_tests.yml | 142 +++++++++ ...ermission_invoke_function_action_tests.yml | 131 ++++++++ .../elasticsearch_encrypted_at_rest.guard | 2 + .../elasticsearch_in_vpc_only.guard | 2 + ...search_node_to_node_encryption_check.guard | 2 + .../elasticsearch_encrypted_at_rest_tests.yml | 16 + .../tests/elasticsearch_in_vpc_only_tests.yml | 16 + ...ch_node_to_node_encryption_check_tests.yml | 16 + .../secretsmanager_using_cmk.guard | 2 + .../tests/secretsmanager_using_cmk_tests.yml | 34 ++- 18 files changed, 842 insertions(+), 2 deletions(-) create mode 100644 rules/aws/all_resources/cfn_authentication_rule.guard create mode 100644 rules/aws/all_resources/tests/cfn_authentication_rule_tests.yml create mode 100644 rules/aws/lambda/lambda_no_wildcard_principal.guard create mode 100644 rules/aws/lambda/lambda_permission_invoke_function_action.guard create mode 100644 rules/aws/lambda/tests/lambda_no_wildcard_principal_tests.yml create mode 100644 rules/aws/lambda/tests/lambda_permission_invoke_function_action_tests.yml diff --git a/rules/aws/all_resources/cfn_authentication_rule.guard b/rules/aws/all_resources/cfn_authentication_rule.guard new file mode 100644 index 0000000..831898d --- /dev/null +++ b/rules/aws/all_resources/cfn_authentication_rule.guard @@ -0,0 +1,58 @@ +# +##################################### +## AWS Solutions ## +##################################### +# Rule Identifier: +# CFN_AUTHENTICATION_RULE +# +# Description: +# Specifying credentials in the template itself is probably not the safest thing. +# +# Reports on: +# All Resources +# +# Evaluates: +# AWS CloudFormation +# +# Rule Parameters: +# NA +# +# CFN_NAG Rule Id: +# W1 +# +# Scenarios: +# a) SKIP: when there are no resource present +# b) PASS: When no resources specifies credentials in template. +# c) FAIL: When any resource specifies credentials in template. +# d) SKIP: when metadata has rule suppression for CFN_AUTHENTICATION_RULE + +# +# Select all Security Group resources from incoming template (payload) +# +let cfn_authentication_rule = Resources.Metadata +let skip_cfn_authentication = %cfn_authentication_rule[ + "AWS::CloudFormation::Authentication" exists + Metadata.cfn_nag.rules_to_suppress not exists or + Metadata.cfn_nag.rules_to_suppress.*.id != "W1" + Metadata.guard.SuppressedRules not exists or + Metadata.guard.SuppressedRules.* != "CFN_AUTHENTICATION_RULE" +] + +rule CFN_AUTHENTICATION_RULE when + %cfn_authentication_rule !empty + %skip_cfn_authentication !empty + { + let violation = %cfn_authentication_rule[ + "AWS::CloudFormation::Authentication".*.accessKeyId exists + OR + "AWS::CloudFormation::Authentication".*.password exists + OR + "AWS::CloudFormation::Authentication".*.secretKey exists + ] + + %violation empty + << + Violation: CFN template has sensitive credentials defined. + Fix: Remove sensitive credentials. + >> +} diff --git a/rules/aws/all_resources/tests/cfn_authentication_rule_tests.yml b/rules/aws/all_resources/tests/cfn_authentication_rule_tests.yml new file mode 100644 index 0000000..28e5230 --- /dev/null +++ b/rules/aws/all_resources/tests/cfn_authentication_rule_tests.yml @@ -0,0 +1,279 @@ +### +# CFN_AUTHENTICATION_RULE tests +### +--- +- name: Empty + input: {} + expectations: + rules: + CFN_AUTHENTICATION_RULE: SKIP + +- name: No resources + input: + Resources: {} + expectations: + rules: + CFN_AUTHENTICATION_RULE: SKIP + +- name: CFN Insensitive authentication + input: + Resources: + RootRole: + Type: "AWS::IAM::Role" + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Principal: + Service: + - "ec2.amazonaws.com" + AWS: "arn:aws:iam::324320755747:root" + Action: + - "sts:AssumeRole" + EC2I4LBA1: + Type: "AWS::EC2::Instance" + Properties: + ImageId: "ami-6df1e514" + InstanceType: "t2.micro" + SubnetId: + "Ref": "subnetId" + Metadata: + Type: AWS::CloudFormation::Authentication + AWS::CloudFormation::Authentication: + testS3: + type: "s3" + roleName: !Ref RootRole + buckets: + - "somebucket333" + expectations: + rules: + CFN_AUTHENTICATION_RULE: PASS + +- name: CFN Sensitive authentication + input: + Resources: + RootRole: + Type: "AWS::IAM::Role" + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Principal: + Service: + - "ec2.amazonaws.com" + AWS: "arn:aws:iam::324320755747:root" + Action: + - "sts:AssumeRole" + EC2I4LBA1: + Type: "AWS::EC2::Instance" + Properties: + ImageId: "ami-6df1e514" + InstanceType: "t2.micro" + SubnetId: + "Ref": "subnetId" + Metadata: + Type: AWS::CloudFormation::Authentication + AWS::CloudFormation::Authentication: + testBasic: + type: "basic" + username: "testUsername1" + password: "sensitive_password" + uris: + - "http://www.example.com/test" + expectations: + rules: + CFN_AUTHENTICATION_RULE: FAIL + +- name: CFN does not contains Metadata Resource + input: + Resources: + RootRole: + Type: "AWS::IAM::Role" + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Principal: + Service: + - "ec2.amazonaws.com" + AWS: "arn:aws:iam::324320755747:root" + Action: + - "sts:AssumeRole" + EC2I4LBA1: + Type: "AWS::EC2::Instance" + Properties: + ImageId: "ami-6df1e514" + InstanceType: "t2.micro" + SubnetId: + "Ref": "subnetId" + expectations: + rules: + CFN_AUTHENTICATION_RULE: SKIP + +- name: CFN_NAG suppression for W1 + input: + Resources: + RootRole: + Type: "AWS::IAM::Role" + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Principal: + Service: + - "ec2.amazonaws.com" + AWS: "arn:aws:iam::324320755747:root" + Action: + - "sts:AssumeRole" + Metadata: + cfn_nag: + rules_to_suppress: + - id: W1 + reason: Suppressed to test suppression works and skips this test + guard: + SuppressedRules: + - CFN_AUTHENTICATION_RULE + EC2I4LBA1: + Type: "AWS::EC2::Instance" + Properties: + ImageId: "ami-6df1e514" + InstanceType: "t2.micro" + SubnetId: + "Ref": "subnetId" + Metadata: + cfn_nag: + rules_to_suppress: + - id: W1 + reason: Suppressed to test suppression works and skips this test + guard: + SuppressedRules: + - CFN_AUTHENTICATION_RULE + Metadata: + Type: AWS::CloudFormation::Authentication + AWS::CloudFormation::Authentication: + testBasic: + type: "basic" + username: "testUsername1" + password: "sensitive_password" + uris: + - "http://www.example.com/test" + Metadata: + cfn_nag: + rules_to_suppress: + - id: W1 + reason: Suppressed to test suppression works and skips this test + expectations: + rules: + CFN_AUTHENTICATION_RULE: SKIP + +- name: Guard suppression for CFN_AUTHENTICATION_RULE + input: + Resources: + RootRole: + Type: "AWS::IAM::Role" + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Principal: + Service: + - "ec2.amazonaws.com" + AWS: "arn:aws:iam::324320755747:root" + Action: + - "sts:AssumeRole" + Metadata: + guard: + SuppressedRules: + - CFN_AUTHENTICATION_RULE + EC2I4LBA1: + Type: "AWS::EC2::Instance" + Properties: + ImageId: "ami-6df1e514" + InstanceType: "t2.micro" + SubnetId: + "Ref": "subnetId" + Metadata: + guard: + SuppressedRules: + - CFN_AUTHENTICATION_RULE + Metadata: + Type: AWS::CloudFormation::Authentication + AWS::CloudFormation::Authentication: + testBasic: + type: "basic" + username: "testUsername1" + password: "sensitive_password" + uris: + - "http://www.example.com/test" + Metadata: + guard: + SuppressedRules: + - CFN_AUTHENTICATION_RULE + expectations: + rules: + CFN_AUTHENTICATION_RULE: SKIP + +- name: Guard and CFN_NAG suppression for W1 & CFN_AUTHENTICATION_RULE + input: + Resources: + RootRole: + Type: "AWS::IAM::Role" + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Principal: + Service: + - "ec2.amazonaws.com" + AWS: "arn:aws:iam::324320755747:root" + Action: + - "sts:AssumeRole" + Metadata: + cfn_nag: + rules_to_suppress: + - id: W1 + reason: Suppressed to test suppression works and skips this test + guard: + SuppressedRules: + - CFN_AUTHENTICATION_RULE + EC2I4LBA1: + Type: "AWS::EC2::Instance" + Properties: + ImageId: "ami-6df1e514" + InstanceType: "t2.micro" + SubnetId: + "Ref": "subnetId" + Metadata: + cfn_nag: + rules_to_suppress: + - id: W1 + reason: Suppressed to test suppression works and skips this test + guard: + SuppressedRules: + - CFN_AUTHENTICATION_RULE + Metadata: + Type: AWS::CloudFormation::Authentication + AWS::CloudFormation::Authentication: + testBasic: + type: "basic" + username: "testUsername1" + password: "sensitive_password" + uris: + - "http://www.example.com/test" + Metadata: + cfn_nag: + rules_to_suppress: + - id: W1 + reason: Suppressed to test suppression works and skips this test + guard: + SuppressedRules: + - CFN_AUTHENTICATION_RULE + expectations: + rules: + CFN_AUTHENTICATION_RULE: SKIP diff --git a/rules/aws/lambda/lambda_concurrency_check.guard b/rules/aws/lambda/lambda_concurrency_check.guard index 61d8220..1550f11 100644 --- a/rules/aws/lambda/lambda_concurrency_check.guard +++ b/rules/aws/lambda/lambda_concurrency_check.guard @@ -27,6 +27,8 @@ # Select all AWS Lambda Function resources from incoming template (payload) # let aws_lambda_functions_concurrency = Resources.*[ Type == 'AWS::Lambda::Function' + Metadata.cfn_nag.rules_to_suppress not exists or + Metadata.cfn_nag.rules_to_suppress.*.id != "W92" Metadata.guard.SuppressedRules not exists or Metadata.guard.SuppressedRules.* != "LAMBDA_CONCURRENCY_CHECK" ] diff --git a/rules/aws/lambda/lambda_inside_vpc.guard b/rules/aws/lambda/lambda_inside_vpc.guard index 79f10d2..0d10e7c 100644 --- a/rules/aws/lambda/lambda_inside_vpc.guard +++ b/rules/aws/lambda/lambda_inside_vpc.guard @@ -27,6 +27,8 @@ # Select all AWS Lambda Function resources from incoming template (payload) # let aws_lambda_functions_inside_vpc = Resources.*[ Type == 'AWS::Lambda::Function' + Metadata.cfn_nag.rules_to_suppress not exists or + Metadata.cfn_nag.rules_to_suppress.*.id != "W89" Metadata.guard.SuppressedRules not exists or Metadata.guard.SuppressedRules.* != "LAMBDA_INSIDE_VPC" ] diff --git a/rules/aws/lambda/lambda_no_wildcard_principal.guard b/rules/aws/lambda/lambda_no_wildcard_principal.guard new file mode 100644 index 0000000..bbeb7db --- /dev/null +++ b/rules/aws/lambda/lambda_no_wildcard_principal.guard @@ -0,0 +1,51 @@ +# +##################################### +## AWS Solutions ## +##################################### +# Rule Identifier: +# LAMBDA_NO_WILDCARD_PRINCIPALS +# +# Description: +# Checks if the AWS Lambda permission uses open principal +# +# Reports on: +# AWS::Lambda::Permission +# AWS::Lambda::LayerVersionPermission +# +# Evaluates: +# AWS CloudFormation +# +# Rule Parameters: +# NA +# +# CFN_NAG Rule Id: +# F13 +# +# Scenarios: +# a) SKIP: when no AWS Lambda permission policies are present +# b) PASS: when no AWS Lambda permission policies allow all principals +# c) FAIL: when any AWS Lambda permission allows all principals +# d) SKIP: hen metadata includes the suppression for rule LAMBDA_NO_WILDCARD_PRINCIPALS + +let applicable_types = [ + "AWS::Lambda::Permission", + "AWS::Lambda::LayerVersionPermission" +] + +let lambda_no_wildcard_principal = Resources.*[ Type in %applicable_types + Metadata.cfn_nag.rules_to_suppress not exists or + Metadata.cfn_nag.rules_to_suppress.*.id != "F13" + Metadata.guard.SuppressedRules not exists or + Metadata.guard.SuppressedRules.* != "LAMBDA_NO_WILDCARD_PRINCIPALS" +] + +rule LAMBDA_NO_WILDCARD_PRINCIPALS when %lambda_no_wildcard_principal !empty { + let violations = %lambda_no_wildcard_principal[ + Properties.Principal == '*' + ] + %violations empty + << + Violation: Lambda permission principal should not be wildcard. + Fix: Specify principal or a list of principals. + >> +} diff --git a/rules/aws/lambda/lambda_permission_invoke_function_action.guard b/rules/aws/lambda/lambda_permission_invoke_function_action.guard new file mode 100644 index 0000000..1413fa8 --- /dev/null +++ b/rules/aws/lambda/lambda_permission_invoke_function_action.guard @@ -0,0 +1,49 @@ +# +##################################### +## AWS Solutions ## +##################################### +# Rule Identifier: +# LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION +# +# Description: +# Checks if the AWS Lambda permission uses any other action apart from 'lambda:InvokeFunction' +# +# Reports on: +# AWS::Lambda::Permission +# +# Evaluates: +# AWS CloudFormation +# +# Rule Parameters: +# NA +# +# CFN_NAG Rule Id: +# W24 +# +# Scenarios: +# a) SKIP: when no AWS Lambda permission policies are present +# b) PASS: when no AWS Lambda permission uses any other action apart from 'lambda:InvokeFunction' +# c) FAIL: when any AWS Lambda permission allows action apart from 'lambda:InvokeFunction' +# d) SKIP: When metadata includes the suppression for rule LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION + +let applicable_types = [ + "AWS::Lambda::Permission" +] + +let lambda_permission_invoke_function_action = Resources.*[ Type in %applicable_types + Metadata.cfn_nag.rules_to_suppress not exists or + Metadata.cfn_nag.rules_to_suppress.*.id != "W24" + Metadata.guard.SuppressedRules not exists or + Metadata.guard.SuppressedRules.* != "LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION" +] + +rule LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION when %lambda_permission_invoke_function_action !empty { + let violations = %lambda_permission_invoke_function_action[ + some Properties.Action != 'lambda:InvokeFunction' + ] + %violations empty + << + Violation: Lambda permission beside InvokeFunction might not be what you want. + Fix: Remove Actions beside 'lambda:InvokeFunction'. + >> +} diff --git a/rules/aws/lambda/tests/lambda_concurrency_check_tests.yml b/rules/aws/lambda/tests/lambda_concurrency_check_tests.yml index 56eaa18..fad6392 100644 --- a/rules/aws/lambda/tests/lambda_concurrency_check_tests.yml +++ b/rules/aws/lambda/tests/lambda_concurrency_check_tests.yml @@ -76,4 +76,23 @@ S3Key: function.zip expectations: rules: - LAMBDA_CONCURRENCY_CHECK: SKIP \ No newline at end of file + LAMBDA_CONCURRENCY_CHECK: SKIP + +- name: AWS Lambda Function reserved concurrent execution limit NOT set but rule suppressed, SKIP + input: + Resources: + ExampleLambda-1: + Type: "AWS::Lambda::Function" + Metadata: + cfn_nag: + rules_to_suppress: + - id: W92 + reason: Suppressed for a very good reason + Properties: + Role: arn:aws:iam::123456789012:role/lambda-role + Code: + S3Bucket: my-bucket + S3Key: function.zip + expectations: + rules: + LAMBDA_CONCURRENCY_CHECK: SKIP diff --git a/rules/aws/lambda/tests/lambda_inside_vpc_tests.yml b/rules/aws/lambda/tests/lambda_inside_vpc_tests.yml index d02aa58..c634986 100644 --- a/rules/aws/lambda/tests/lambda_inside_vpc_tests.yml +++ b/rules/aws/lambda/tests/lambda_inside_vpc_tests.yml @@ -66,3 +66,22 @@ expectations: rules: LAMBDA_INSIDE_VPC: SKIP + +- name: AWS Lambda function VPC Configuration NOT set but rule suppressed, SKIP + input: + Resources: + ExampleLambda: + Type: "AWS::Lambda::Function" + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: Suppressed for a very good reason + Properties: + Role: arn:aws:iam::123456789012:role/lambda-role + Code: + S3Bucket: my-bucket + S3Key: function.zip + expectations: + rules: + LAMBDA_INSIDE_VPC: SKIP diff --git a/rules/aws/lambda/tests/lambda_no_wildcard_principal_tests.yml b/rules/aws/lambda/tests/lambda_no_wildcard_principal_tests.yml new file mode 100644 index 0000000..97a0f8e --- /dev/null +++ b/rules/aws/lambda/tests/lambda_no_wildcard_principal_tests.yml @@ -0,0 +1,142 @@ +### +# LAMBDA_NO_WILDCARD_PRINCIPALS tests +### +--- +- name: Empty, SKIP + input: {} + expectations: + rules: + LAMBDA_NO_WILDCARD_PRINCIPALS: SKIP + +- name: No resources, SKIP + input: + Resources: {} + expectations: + rules: + LAMBDA_NO_WILDCARD_PRINCIPALS: SKIP + +- name: Lambda permission policy limited to an account as the principal, PASS + input: + Resources: + ExampleLambdaPermission1: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:InvokeFunction + FunctionName: test-function + Principal: 111122223333 + ExampleLambdaPermission2: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:InvokeFunction + FunctionName: test-function + Principal: "123456789012" + ExampleLambdaPermission3: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:InvokeFunction + FunctionName: test-function + Principal: !Ref AWS::AccountId + expectations: + rules: + LAMBDA_NO_WILDCARD_PRINCIPALS: PASS + +- name: Lambda permission policy limited to a service (not S3) as the principal scoped to a principal organization, PASS + input: + Resources: + ExampleLambdaPermission-1: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:InvokeFunction + FunctionName: test-function + Principal: sns.amazonaws.com + PrincipalOrgID: o-aa111bb222 + expectations: + rules: + LAMBDA_NO_WILDCARD_PRINCIPALS: PASS + +- name: Lambda permission policy not limited, FAIL + input: + Resources: + ExampleLambdaPermission1: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:InvokeFunction + FunctionName: test-function + Principal: '*' + SourceAccount: 123456789012 + expectations: + rules: + LAMBDA_NO_WILDCARD_PRINCIPALS: FAIL + +- name: Lambda layer version permission policy limited to an organization, FAIL + input: + Resources: + ExampleLambdaLayerVersionPermission: + Type: "AWS::Lambda::LayerVersionPermission" + Properties: + Action: lambda:GetLayerVersion + LayerVersionArn: arn:aws:lambda:us-west-2:123456789012:layer:my-layer:1 + Principal: "*" + OrganizationId: o-aa111bb222 + expectations: + rules: + LAMBDA_NO_WILDCARD_PRINCIPALS: FAIL + +- name: CFN_NAG suppression for F13, SKIP + input: + Resources: + ExampleLambdaLayerVersionPermission: + Type: "AWS::Lambda::LayerVersionPermission" + Properties: + Action: lambda:GetLayerVersion + LayerVersionArn: arn:aws:lambda:us-west-2:123456789012:layer:my-layer:1 + Principal: "*" + OrganizationId: o-aa111bb222 + Metadata: + cfn_nag: + rules_to_suppress: + - id: F13 + reason: Suppressed for a very good reason + expectations: + rules: + LAMBDA_NO_WILDCARD_PRINCIPALS: SKIP + +- name: Guard suppression for LAMBDA_NO_WILDCARD_PRINCIPALS, SKIP + input: + Resources: + ExampleLambdaLayerVersionPermission: + Type: "AWS::Lambda::LayerVersionPermission" + Properties: + Action: lambda:GetLayerVersion + LayerVersionArn: arn:aws:lambda:us-west-2:123456789012:layer:my-layer:1 + Principal: "*" + OrganizationId: o-aa111bb222 + Metadata: + guard: + SuppressedRules: + - LAMBDA_NO_WILDCARD_PRINCIPALS + expectations: + rules: + LAMBDA_NO_WILDCARD_PRINCIPALS: SKIP + +- name: Guard and CFN_NAG suppression for F13 & LAMBDA_NO_WILDCARD_PRINCIPALS, SKIP + input: + Resources: + ExampleLambdaLayerVersionPermission: + Type: "AWS::Lambda::LayerVersionPermission" + Properties: + Action: lambda:GetLayerVersion + LayerVersionArn: arn:aws:lambda:us-west-2:123456789012:layer:my-layer:1 + Principal: "*" + OrganizationId: o-aa111bb222 + Metadata: + cfn_nag: + rules_to_suppress: + - id: F13 + reason: Suppressed for a very good reason + guard: + SuppressedRules: + - LAMBDA_NO_WILDCARD_PRINCIPALS + expectations: + rules: + LAMBDA_NO_WILDCARD_PRINCIPALS: SKIP diff --git a/rules/aws/lambda/tests/lambda_permission_invoke_function_action_tests.yml b/rules/aws/lambda/tests/lambda_permission_invoke_function_action_tests.yml new file mode 100644 index 0000000..b412214 --- /dev/null +++ b/rules/aws/lambda/tests/lambda_permission_invoke_function_action_tests.yml @@ -0,0 +1,131 @@ +### +# LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION tests +### +--- +- name: Empty + input: {} + expectations: + rules: + LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION: SKIP + +- name: No resources + input: + Resources: {} + expectations: + rules: + LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION: SKIP + +- name: Lambda permission policy with only invokeFunction actions + input: + Resources: + ExampleLambdaPermission1: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:InvokeFunction + FunctionName: test-function + Principal: 111122223333 + ExampleLambdaPermission2: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:InvokeFunction + FunctionName: test-function + Principal: "123456789012" + ExampleLambdaPermission3: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:InvokeFunction + FunctionName: test-function + Principal: !Ref AWS::AccountId + expectations: + rules: + LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION: PASS + +- name: Lambda permission action is lambda:GetFunction + input: + Resources: + ExampleLambdaPermission1: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:GetFunction + FunctionName: test-function + Principal: 111122223333 + SourceAccount: 123456789012 + expectations: + rules: + LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION: FAIL + +- name: Lambda permission actions are lambda:GetFunction and lambda:InvokeFunction + input: + Resources: + ExampleLambdaPermission1: + Type: "AWS::Lambda::Permission" + Properties: + Action: [ + lambda:InvokeFunction, + lambda:GetFunction + ] + FunctionName: test-function + Principal: 111122223333 + SourceAccount: 123456789012 + expectations: + rules: + LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION: FAIL + +- name: CFN_NAG suppression for W24 + input: + Resources: + ExampleLambdaPermission: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:GetFunction + Principal: 111122223333 + FunctionName: test-function + OrganizationId: o-aa111bb222 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W24 + reason: Suppressed to test suppression works and skips this test + expectations: + rules: + LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION: SKIP + +- name: Guard suppression for LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION + input: + Resources: + ExampleLambdaPermission: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:GetFunction + Principal: 111122223333 + FunctionName: test-function + OrganizationId: o-aa111bb222 + Metadata: + guard: + SuppressedRules: + - LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION + expectations: + rules: + LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION: SKIP + +- name: Guard and CFN_NAG suppression for W24 & LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION + input: + Resources: + ExampleLambdaPermission: + Type: "AWS::Lambda::Permission" + Properties: + Action: lambda:GetFunction + Principal: 111122223333 + FunctionName: test-function + OrganizationId: o-aa111bb222 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W24 + reason: Suppressed to test suppression works and skips this test + guard: + SuppressedRules: + - LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION + expectations: + rules: + LAMBDA_PERMISSION_INVOKE_FUNCTION_ACTION: SKIP diff --git a/rules/aws/opensearch_service/elasticsearch_encrypted_at_rest.guard b/rules/aws/opensearch_service/elasticsearch_encrypted_at_rest.guard index 52e9359..272fe75 100644 --- a/rules/aws/opensearch_service/elasticsearch_encrypted_at_rest.guard +++ b/rules/aws/opensearch_service/elasticsearch_encrypted_at_rest.guard @@ -28,6 +28,8 @@ # Select all elasticsearch domains from incoming template # let elasticsearch_domains_encrypted = Resources.*[ Type == "AWS::Elasticsearch::Domain" + Metadata.cfn_nag.rules_to_suppress not exists or + Metadata.cfn_nag.rules_to_suppress.*.id != "W54" Metadata.guard.SuppressedRules not exists or Metadata.guard.SuppressedRules.* != "ELASTICSEARCH_ENCRYPTED_AT_REST" ] diff --git a/rules/aws/opensearch_service/elasticsearch_in_vpc_only.guard b/rules/aws/opensearch_service/elasticsearch_in_vpc_only.guard index 2526c7d..e756328 100644 --- a/rules/aws/opensearch_service/elasticsearch_in_vpc_only.guard +++ b/rules/aws/opensearch_service/elasticsearch_in_vpc_only.guard @@ -27,6 +27,8 @@ # Select all elasticsearch domains from incoming template # let elasticsearch_domains_vpc_required = Resources.*[ Type == "AWS::Elasticsearch::Domain" + Metadata.cfn_nag.rules_to_suppress not exists or + Metadata.cfn_nag.rules_to_suppress.*.id != "W90" Metadata.guard.SuppressedRules not exists or Metadata.guard.SuppressedRules.* != "ELASTICSEARCH_IN_VPC_ONLY" ] diff --git a/rules/aws/opensearch_service/opensearch_node_to_node_encryption_check.guard b/rules/aws/opensearch_service/opensearch_node_to_node_encryption_check.guard index 8653788..9a17b9b 100644 --- a/rules/aws/opensearch_service/opensearch_node_to_node_encryption_check.guard +++ b/rules/aws/opensearch_service/opensearch_node_to_node_encryption_check.guard @@ -28,6 +28,8 @@ # Select all elasticsearch domains from incoming template # let opensearch_node_to_node_encryption_check = Resources.*[ Type == "AWS::OpenSearchService::Domain" + Metadata.cfn_nag.rules_to_suppress not exists or + Metadata.cfn_nag.rules_to_suppress.*.id != "W85" Metadata.guard.SuppressedRules not exists or Metadata.guard.SuppressedRules.* != "OPENSEARCH_NODE_TO_NODE_ENCRYPTION_CHECK" ] diff --git a/rules/aws/opensearch_service/tests/elasticsearch_encrypted_at_rest_tests.yml b/rules/aws/opensearch_service/tests/elasticsearch_encrypted_at_rest_tests.yml index e1c84a2..e9addf6 100644 --- a/rules/aws/opensearch_service/tests/elasticsearch_encrypted_at_rest_tests.yml +++ b/rules/aws/opensearch_service/tests/elasticsearch_encrypted_at_rest_tests.yml @@ -30,6 +30,22 @@ rules: ELASTICSEARCH_ENCRYPTED_AT_REST: SKIP +- name: Scenario b) Rule fails when ElasticSearch domain has server side encryption property missing but rule suppressed, SKIP + input: + Resources: + ElasticsearchDomain: + Type: AWS::Elasticsearch::Domain + Metadata: + cfn_nag: + rules_to_suppress: + - id: W54 + reason: Suppressed for a very good reason + Properties: + DomainName: test + expectations: + rules: + ELASTICSEARCH_ENCRYPTED_AT_REST: SKIP + - name: Scenario c) Rule fails when ElasticSearch domain has server side encryption property missing, FAIL input: Resources: diff --git a/rules/aws/opensearch_service/tests/elasticsearch_in_vpc_only_tests.yml b/rules/aws/opensearch_service/tests/elasticsearch_in_vpc_only_tests.yml index bd7b902..8ef31ec 100644 --- a/rules/aws/opensearch_service/tests/elasticsearch_in_vpc_only_tests.yml +++ b/rules/aws/opensearch_service/tests/elasticsearch_in_vpc_only_tests.yml @@ -30,6 +30,22 @@ rules: ELASTICSEARCH_IN_VPC_ONLY: SKIP +- name: Scenario b) Rule fails when ElasticSearch domain does not have VPCOptions property but rule suppressed - CFN_NAG, SKIP + input: + Resources: + ElasticsearchDomain: + Type: AWS::Elasticsearch::Domain + Metadata: + cfn_nag: + rules_to_suppress: + - id: W90 + reason: Suppressed for a very good reason + Properties: + DomainName: test + expectations: + rules: + ELASTICSEARCH_IN_VPC_ONLY: SKIP + - name: Scenario c) Rule fails when ElasticSearch domain does not have VPCOptions property, FAIL input: Resources: diff --git a/rules/aws/opensearch_service/tests/opensearch_node_to_node_encryption_check_tests.yml b/rules/aws/opensearch_service/tests/opensearch_node_to_node_encryption_check_tests.yml index a8370bb..2a919ba 100644 --- a/rules/aws/opensearch_service/tests/opensearch_node_to_node_encryption_check_tests.yml +++ b/rules/aws/opensearch_service/tests/opensearch_node_to_node_encryption_check_tests.yml @@ -30,6 +30,22 @@ rules: OPENSEARCH_NODE_TO_NODE_ENCRYPTION_CHECK: SKIP +- name: Scenario b) Rule fails when OpenSearchService domain has Node-to-Node Encryption property missing but rule suppressed - CFN_NAG, SKIP + input: + Resources: + OpenSearchDomain: + Type: AWS::OpenSearchService::Domain + Metadata: + cfn_nag: + rules_to_suppress: + - id: W85 + reason: Suppressed for a very good reason + Properties: + DomainName: test + expectations: + rules: + OPENSEARCH_NODE_TO_NODE_ENCRYPTION_CHECK: SKIP + - name: Scenario c) Rule fails when OpenSearchService domain has Node-to-Node Encryption property missing input: Resources: diff --git a/rules/aws/secrets_manager/secretsmanager_using_cmk.guard b/rules/aws/secrets_manager/secretsmanager_using_cmk.guard index f72a41b..d91683b 100644 --- a/rules/aws/secrets_manager/secretsmanager_using_cmk.guard +++ b/rules/aws/secrets_manager/secretsmanager_using_cmk.guard @@ -28,6 +28,8 @@ # Select all AWS::SageMaker::EndpointConfig resources from incoming template (payload) # let aws_secretsmanager_secret_cmk = Resources.*[ Type == "AWS::SecretsManager::Secret" + Metadata.cfn_nag.rules_to_suppress not exists or + Metadata.cfn_nag.rules_to_suppress.*.id != "W77" Metadata.guard.SuppressedRules not exists or Metadata.guard.SuppressedRules.* != "SECRETSMANAGER_USING_CMK" ] diff --git a/rules/aws/secrets_manager/tests/secretsmanager_using_cmk_tests.yml b/rules/aws/secrets_manager/tests/secretsmanager_using_cmk_tests.yml index 819d07b..8d62ab5 100644 --- a/rules/aws/secrets_manager/tests/secretsmanager_using_cmk_tests.yml +++ b/rules/aws/secrets_manager/tests/secretsmanager_using_cmk_tests.yml @@ -125,4 +125,36 @@ AutomaticallyAfterDays: 30 expectations: rules: - SECRETSMANAGER_USING_CMK: SKIP \ No newline at end of file + SECRETSMANAGER_USING_CMK: SKIP + +- name: rule suppressed - CFN_NAG, SKIP + input: + Resources: + MySecret: + Type: 'AWS::SecretsManager::Secret' + Metadata: + cfn_nag: + rules_to_suppress: + - id: W77 + reason: Suppressed for a very good reason + Properties: + Name: MySecretForAppA + Description: "This secret has a dynamically generated secret password." + GenerateSecretString: + SecretStringTemplate: '{"username": "test-user"}' + GenerateStringKey: "password" + PasswordLength: 30 + ExcludeCharacters: '"@/\' + KmsKeyId: alias/aws/secretsmanager + MySecretRotationSchedule: + Type: AWS::SecretsManager::RotationSchedule + Properties: + SecretId: + Ref: MySecret + RotationLambdaARN: + Ref: MyCustomRotationLambda + RotationRules: + AutomaticallyAfterDays: 30 + expectations: + rules: + SECRETSMANAGER_USING_CMK: SKIP