# ################################### ## Rule Specification ## ##################################### # # Rule Identifier: # acm_certificate_domain_name_check # # Description: # This control checks whether any AWS Certificate Manager (ACM) Private CA certificates have wildcard domain names instead of single domain names. # # Reports on: # AWS::CertificateManager::Certificate # # 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 ACM certificate resources # Then: SKIP # Scenario: 2 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ACM certificate resource # And: 'CertificateAuthorityArn' has not been provided # Then: SKIP # Scenario: 3 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ACM certificate resource # And: 'CertificateAuthorityArn' has been provided # And: 'DomainName' has not been provided # Then: FAIL # Scenario: 4 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ACM certificate resource # And: 'CertificateAuthorityArn' has been provided # And: 'SubjectAlternativeNames' has not been provided or provided as an empty list # And: 'DomainName' has been provided with a string that begins with a wildcard character ('*'). # Then: FAIL # Scenario: 5 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ACM certificate resource # And: 'CertificateAuthorityArn' has been provided # And: 'DomainName' has been provided with a string that does not begin with a wildcard character ('*'). # And: 'SubjectAlternativeNames' has been provided as a non-empty list containing a string that # begins with a wildcard character ('*'). # Then: FAIL # Scenario: 6 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ACM certificate resource # And: 'CertificateAuthorityArn' has been provided # And: 'DomainName' has been provided with a string that does not begin with a wildcard character ('*'). # And: 'SubjectAlternativeNames' has not been provided or provided as an empty list # Then: PASS # Scenario: 7 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ACM certificate resource # And: 'CertificateAuthorityArn' has been provided # And: 'DomainName' has been provided with a string that does not begin with a wildcard character ('*'). # And: 'SubjectAlternativeNames' has been provided as a non-empty list where no entries are strings that # begin with a wildcard character ('*'). # Then: PASS # # Constants # let ACM_CERTIFICATE_TYPE = "AWS::CertificateManager::Certificate" let WILDCARD_DOMAIN_NAME_REGEX_PATTERN = /^(\*\.).*$/ let INPUT_DOCUMENT = this # # Assignments # let acm_certificates = Resources.*[ Type == %ACM_CERTIFICATE_TYPE ] # # Primary Rules # rule acm_certificate_domain_name_check when is_cfn_template(%INPUT_DOCUMENT) %acm_certificates not empty { check(%acm_certificates.Properties) << [CT.ACM.PR.1]: Require an AWS Private CA certificate to have a single domain name [FIX]: Set 'DomainName' and each entry within 'SubjectAlternativeNames' to a fully qualified domain name (FQDN) that does not contain a wildcard (*). >> } rule acm_certificate_domain_name_check when is_cfn_hook(%INPUT_DOCUMENT, %ACM_CERTIFICATE_TYPE) { check(%INPUT_DOCUMENT.%ACM_CERTIFICATE_TYPE.resourceProperties) << [CT.ACM.PR.1]: Require an AWS Private CA certificate to have a single domain name [FIX]: Set 'DomainName' and each entry within 'SubjectAlternativeNames' to a fully qualified domain name (FQDN) that does not contain a wildcard (*). >> } # # Parameterized Rules # rule check(acm_certificate) { %acm_certificate[ CertificateAuthorityArn exists ] { # Scenario 2 DomainName exists # Scenario 3 and 4 check_wildcarded_domain(DomainName) check_subject_alternative_names(this) } } rule check_subject_alternative_names(acm_certificate) { %acm_certificate [ SubjectAlternativeNames exists SubjectAlternativeNames is_list SubjectAlternativeNames not empty ] { SubjectAlternativeNames[*] { check_wildcarded_domain(this) } } } rule check_wildcarded_domain(domain) { %domain { this is_string this != %WILDCARD_DOMAIN_NAME_REGEX_PATTERN } } # # 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 }