diff --git a/prowler/providers/aws/services/cloudfront/cloudfront_distributions_custom_ssl_certificate/__init__.py b/prowler/providers/aws/services/cloudfront/cloudfront_distributions_custom_ssl_certificate/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/cloudfront/cloudfront_distributions_custom_ssl_certificate/cloudfront_distributions_custom_ssl_certificate.metadata.json b/prowler/providers/aws/services/cloudfront/cloudfront_distributions_custom_ssl_certificate/cloudfront_distributions_custom_ssl_certificate.metadata.json new file mode 100644 index 0000000000..6a9f0717a6 --- /dev/null +++ b/prowler/providers/aws/services/cloudfront/cloudfront_distributions_custom_ssl_certificate/cloudfront_distributions_custom_ssl_certificate.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "aws", + "CheckID": "cloudfront_distributions_custom_ssl_certificate", + "CheckTitle": "CloudFront distributions should use custom SSL/TLS certificates.", + "CheckType": [], + "ServiceName": "cloudfront", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "Severity": "medium", + "ResourceType": "AWSCloudFrontDistribution", + "Description": "Ensure that your Amazon CloudFront distributions are configured to use a custom SSL/TLS certificate instead of the default one.", + "Risk": "Using the default SSL/TLS certificate provided by CloudFront can limit your ability to use custom domain names and may not align with your organization's security policies or branding requirements.", + "RelatedUrl": "https://aws.amazon.com/what-is/ssl-certificate/", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "https://docs.prowler.com/checks/aws/networking-policies/ensure-aws-cloudfront-distribution-uses-custom-ssl-certificate/", + "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/cloudfront-controls.html#cloudfront-7", + "Terraform": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/CloudFront/cloudfront-distro-custom-tls.html" + }, + "Recommendation": { + "Text": "Configure your CloudFront distributions to use a custom SSL/TLS certificate to enable secure access via your own domain names and meet specific security and branding needs. This allows for more control over encryption and authentication settings.", + "Url": "https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html#CreatingCNAME" + } + }, + "Categories": [ + "encryption" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/cloudfront/cloudfront_distributions_custom_ssl_certificate/cloudfront_distributions_custom_ssl_certificate.py b/prowler/providers/aws/services/cloudfront/cloudfront_distributions_custom_ssl_certificate/cloudfront_distributions_custom_ssl_certificate.py new file mode 100644 index 0000000000..e7ddaa8b98 --- /dev/null +++ b/prowler/providers/aws/services/cloudfront/cloudfront_distributions_custom_ssl_certificate/cloudfront_distributions_custom_ssl_certificate.py @@ -0,0 +1,25 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.cloudfront.cloudfront_client import ( + cloudfront_client, +) + + +class cloudfront_distributions_custom_ssl_certificate(Check): + def execute(self): + findings = [] + for distribution in cloudfront_client.distributions.values(): + report = Check_Report_AWS(self.metadata()) + report.region = distribution.region + report.resource_arn = distribution.arn + report.resource_id = distribution.id + report.resource_tags = distribution.tags + report.status = "PASS" + report.status_extended = f"CloudFront Distribution {distribution.id} is using a custom SSL/TLS certificate." + + if distribution.default_certificate: + report.status = "FAIL" + report.status_extended = f"CloudFront Distribution {distribution.id} is using the default SSL/TLS certificate." + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/cloudfront/cloudfront_distributions_https_sni_enabled/cloudfront_distributions_https_sni_enabled.metadata.json b/prowler/providers/aws/services/cloudfront/cloudfront_distributions_https_sni_enabled/cloudfront_distributions_https_sni_enabled.metadata.json index 2abfaad1dc..0a7e058abd 100644 --- a/prowler/providers/aws/services/cloudfront/cloudfront_distributions_https_sni_enabled/cloudfront_distributions_https_sni_enabled.metadata.json +++ b/prowler/providers/aws/services/cloudfront/cloudfront_distributions_https_sni_enabled/cloudfront_distributions_https_sni_enabled.metadata.json @@ -2,9 +2,7 @@ "Provider": "aws", "CheckID": "cloudfront_distributions_https_sni_enabled", "CheckTitle": "Check if CloudFront distributions are using SNI to serve HTTPS requests.", - "CheckType": [ - "NIST 800-53 Controls" - ], + "CheckType": [], "ServiceName": "cloudfront", "SubServiceName": "", "ResourceIdTemplate": "arn:partition:cloudfront:region:account-id:distribution/resource-id", diff --git a/prowler/providers/aws/services/cloudfront/cloudfront_service.py b/prowler/providers/aws/services/cloudfront/cloudfront_service.py index b35308134f..8fe9ad300b 100644 --- a/prowler/providers/aws/services/cloudfront/cloudfront_service.py +++ b/prowler/providers/aws/services/cloudfront/cloudfront_service.py @@ -30,6 +30,9 @@ class CloudFront(AWSService): ): distribution_id = item["Id"] distribution_arn = item["ARN"] + default_certificate = item["ViewerCertificate"][ + "CloudFrontDefaultCertificate" + ] certificate = item["ViewerCertificate"].get( "Certificate", "" ) @@ -59,6 +62,7 @@ class CloudFront(AWSService): id=distribution_id, origins=origins, region=region, + default_certificate=default_certificate, ssl_support_method=ssl_support_method, certificate=certificate, ) @@ -184,6 +188,7 @@ class Distribution(BaseModel): geo_restriction_type: Optional[GeoRestrictionType] origins: list[Origin] web_acl_id: str = "" + default_certificate: Optional[bool] default_root_object: Optional[str] tags: Optional[list] = [] ssl_support_method: Optional[SSLSupportMethod] diff --git a/tests/providers/aws/services/cloudfront/cloudfront_distributions_custom_ssl_certificate/cloudfront_distributions_custom_ssl_certificate_test.py b/tests/providers/aws/services/cloudfront/cloudfront_distributions_custom_ssl_certificate/cloudfront_distributions_custom_ssl_certificate_test.py new file mode 100644 index 0000000000..2c15423afe --- /dev/null +++ b/tests/providers/aws/services/cloudfront/cloudfront_distributions_custom_ssl_certificate/cloudfront_distributions_custom_ssl_certificate_test.py @@ -0,0 +1,99 @@ +from unittest import mock + +from prowler.providers.aws.services.cloudfront.cloudfront_service import Distribution +from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER + +DISTRIBUTION_ID = "E27LVI50CSW06W" +DISTRIBUTION_ARN = ( + f"arn:aws:cloudfront::{AWS_ACCOUNT_NUMBER}:distribution/{DISTRIBUTION_ID}" +) +REGION = "eu-west-1" + + +class Test_cloudfront_distributions_custom_ssl_certificate: + def test_no_distributions(self): + cloudfront_client = mock.MagicMock + cloudfront_client.distributions = {} + with mock.patch( + "prowler.providers.aws.services.cloudfront.cloudfront_service.CloudFront", + new=cloudfront_client, + ): + # Test Check + from prowler.providers.aws.services.cloudfront.cloudfront_distributions_custom_ssl_certificate.cloudfront_distributions_custom_ssl_certificate import ( + cloudfront_distributions_custom_ssl_certificate, + ) + + check = cloudfront_distributions_custom_ssl_certificate() + result = check.execute() + + assert len(result) == 0 + + def test_distribution_default_certificate(self): + cloudfront_client = mock.MagicMock + cloudfront_client.distributions = { + "DISTRIBUTION_ID": Distribution( + arn=DISTRIBUTION_ARN, + id=DISTRIBUTION_ID, + region=REGION, + logging_enabled=True, + origins=[], + default_certificate=True, + ) + } + + with mock.patch( + "prowler.providers.aws.services.cloudfront.cloudfront_service.CloudFront", + new=cloudfront_client, + ): + # Test Check + from prowler.providers.aws.services.cloudfront.cloudfront_distributions_custom_ssl_certificate.cloudfront_distributions_custom_ssl_certificate import ( + cloudfront_distributions_custom_ssl_certificate, + ) + + check = cloudfront_distributions_custom_ssl_certificate() + result = check.execute() + + assert len(result) == 1 + assert result[0].region == REGION + assert result[0].resource_arn == DISTRIBUTION_ARN + assert result[0].resource_id == DISTRIBUTION_ID + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"CloudFront Distribution {DISTRIBUTION_ID} is using the default SSL/TLS certificate." + ) + + def test_distribution_custom_certificate(self): + cloudfront_client = mock.MagicMock + cloudfront_client.distributions = { + "DISTRIBUTION_ID": Distribution( + arn=DISTRIBUTION_ARN, + id=DISTRIBUTION_ID, + region=REGION, + logging_enabled=True, + origins=[], + default_certificate=False, + ) + } + + with mock.patch( + "prowler.providers.aws.services.cloudfront.cloudfront_service.CloudFront", + new=cloudfront_client, + ): + # Test Check + from prowler.providers.aws.services.cloudfront.cloudfront_distributions_custom_ssl_certificate.cloudfront_distributions_custom_ssl_certificate import ( + cloudfront_distributions_custom_ssl_certificate, + ) + + check = cloudfront_distributions_custom_ssl_certificate() + result = check.execute() + + assert len(result) == 1 + assert result[0].region == REGION + assert result[0].resource_arn == DISTRIBUTION_ARN + assert result[0].resource_id == DISTRIBUTION_ID + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"CloudFront Distribution {DISTRIBUTION_ID} is using a custom SSL/TLS certificate." + )