# ################################### ## Rule Specification ## ##################################### # # Rule Identifier: # ec2_instance_no_public_ip_check # # Description: # This control checks whether your Amazon EC2 instance is configured NOT to associate a public IP address by default, and it requires configuring the AssociatePublicIpAddress parameter to false on a new network interface created by means of the NetworkInterfaces property. # # Reports on: # AWS::EC2::Instance # # Evaluates: # AWS CloudFormation, AWS CloudFormation hook # # Rule Parameters: # None # # Scenarios: # Scenario: 1 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document does not contain any EC2 instance resources # Then: SKIP # Scenario: 2 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an EC2 instance resource # And: 'NetworkInterfaces' is not present on the EC2 instance resource or is an empty list # And: 'SubnetId' is not provided as a top-level resource property # Then: SKIP # Scenario: 3 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an EC2 instance resource # And: 'NetworkInterfaces' is present on the EC2 instance resource as a non-empty list # And: 'NetworkInterfaceId' is present for a configuration in 'NetworkInterfaces' and is a non-empty string or # valid local reference # Then: SKIP # Scenario: 4 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an EC2 instance resource # And: 'NetworkInterfaces' is not provided # And: 'SubnetId' is provided as a top-level resource property # Then: FAIL # Scenario: 5 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an EC2 instance resource # And: 'NetworkInterfaces' is present on the EC2 instance resource with one or more configurations # And: 'NetworkInterfaceId' is not present or is present and and is an empty string or invalid local reference for # a configuration in 'NetworkInterfaces' # And: 'AssociatePublicIpAddress' is not present for a configuration in 'NetworkInterfaces' # Then: FAIL # Scenario: 6 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an EC2 instance resource # And: 'NetworkInterfaces' is present on the EC2 instance resource # And: 'NetworkInterfaceId' is not present or is present and and is an empty string or invalid local reference for # a configuration in 'NetworkInterfaces' # And: 'AssociatePublicIpAddress' is present for a configuration in 'NetworkInterfaces' # And: 'AssociatePublicIpAddress' is set to bool(true) # Then: FAIL # Scenario: 7 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an EC2 instance resource # And: 'NetworkInterfaces' is present on the EC2 instance resource # And: 'NetworkInterfaceId' is not present or is present and and is an empty string or invalid local reference for # a configuration in 'NetworkInterfaces' # And: 'AssociatePublicIpAddress' is present for a configuration in 'NetworkInterfaces' # And: 'AssociatePublicIpAddress' is set to bool(false) # Then: PASS # # Constants # let EC2_INSTANCE_TYPE = "AWS::EC2::Instance" let INPUT_DOCUMENT = this # # Assignments # let ec2_instances = Resources.*[ Type == %EC2_INSTANCE_TYPE ] # # Primary Rules # rule ec2_instance_no_public_ip_check when is_cfn_template(%INPUT_DOCUMENT) %ec2_instances not empty { check(%ec2_instances.Properties) << [CT.EC2.PR.8]: Require an Amazon EC2 instance to set AssociatePublicIpAddress to false on a new network interface created by means of the NetworkInterfaces property in the AWS::EC2::Instance resource [FIX]: Specify network interfaces using the 'NetworkInterfaces' property instead of the root level 'SubnetId' property. Set 'AssociatePublicIpAddress' to false within each 'NetworkInterfaces' configuration. >> } rule ec2_instance_no_public_ip_check when is_cfn_hook(%INPUT_DOCUMENT, %EC2_INSTANCE_TYPE) { check(%INPUT_DOCUMENT.%EC2_INSTANCE_TYPE.resourceProperties) << [CT.EC2.PR.8]: Require an Amazon EC2 instance to set AssociatePublicIpAddress to false on a new network interface created by means of the NetworkInterfaces property in the AWS::EC2::Instance resource [FIX]: Specify network interfaces using the 'NetworkInterfaces' property instead of the root level 'SubnetId' property. Set 'AssociatePublicIpAddress' to false within each 'NetworkInterfaces' configuration. >> } # # Parameterized Rules # rule check(ec2_instance) { %ec2_instance[ SubnetId exists ] { # Scenario 5 SubnetId not exists } %ec2_instance[ # Scenario 2 NetworkInterfaces exists NetworkInterfaces is_list NetworkInterfaces not empty ] { NetworkInterfaces[ # Scenario 3 and 4 filter_network_interfaces(this) ] { # Scenario 6 AssociatePublicIpAddress exists # Scenarios 7 and 8 AssociatePublicIpAddress == false } } } rule filter_network_interfaces(network_interface) { %network_interface { NetworkInterfaceId not exists or filter_property_is_empty_string(NetworkInterfaceId) or filter_exclude_valid_local_reference(%INPUT_DOCUMENT, NetworkInterfaceId, "AWS::EC2::NetworkInterface") } } rule filter_property_is_empty_string(value) { %value { this is_string this == /\A\s*\z/ } } rule filter_exclude_valid_local_reference(doc, reference_properties, referenced_resource_type) { %reference_properties { this not is_string this is_struct when this.'Fn::GetAtt' exists { 'Fn::GetAtt' { when filter_query_template_resources(%doc, this[0], %referenced_resource_type) { this not exists } this exists } } when this.'Fn::GetAtt' not exists { this exists } } } rule filter_query_template_resources(doc, resource_key, referenced_resource_type) { let referenced_resource = %doc.Resources[ keys == %resource_key ] %referenced_resource not empty %referenced_resource { Type in %referenced_resource_type } } # # Utility Rules # rule is_cfn_template(doc) { %doc { AWSTemplateFormatVersion exists or Resources exists } } rule is_cfn_hook(doc, RESOURCE_TYPE) { %doc.%RESOURCE_TYPE.resourceProperties exists }