mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-04 19:21:51 +00:00
feat(aws): add apigateway_domain_name_pqc_tls_enabled check (#11316)
Co-authored-by: Hugo P.Brito <hugopbrit@gmail.com>
This commit is contained in:
@@ -438,6 +438,13 @@ mainConfig:
|
||||
# Minimum number of Availability Zones that an ELBv2 must be in
|
||||
elbv2_min_azs: 2
|
||||
|
||||
# AWS Post-Quantum TLS Configuration
|
||||
# aws.apigateway_domain_name_pqc_tls_enabled
|
||||
apigateway_pqc_tls_allowed_policies:
|
||||
- "SecurityPolicy_TLS13_1_2_FIPS_PFS_PQ_2025_09"
|
||||
- "SecurityPolicy_TLS13_1_2_PFS_PQ_2025_09"
|
||||
- "SecurityPolicy_TLS13_1_2_PQ_2025_09"
|
||||
|
||||
# AWS Post-Quantum SSH Key Exchange Configuration
|
||||
# aws.transfer_server_pqc_ssh_kex_enabled
|
||||
transfer_pqc_ssh_allowed_policies:
|
||||
|
||||
@@ -55,6 +55,7 @@ The following list includes all the AWS checks with configurable variables that
|
||||
| `elasticache_redis_cluster_backup_enabled` | `minimum_snapshot_retention_period` | Integer |
|
||||
| `elb_is_in_multiple_az` | `elb_min_azs` | Integer |
|
||||
| `elbv2_is_in_multiple_az` | `elbv2_min_azs` | Integer |
|
||||
| `apigateway_domain_name_pqc_tls_enabled` | `apigateway_pqc_tls_allowed_policies` | List of Strings |
|
||||
| `guardduty_is_enabled` | `mute_non_default_regions` | Boolean |
|
||||
| `iam_user_access_not_stale_to_sagemaker` | `max_unused_sagemaker_access_days` | Integer |
|
||||
| `iam_user_accesskey_unused` | `max_unused_access_keys_days` | Integer |
|
||||
|
||||
@@ -61,7 +61,9 @@
|
||||
],
|
||||
"Resource": [
|
||||
"arn:*:apigateway:*::/restapis/*",
|
||||
"arn:*:apigateway:*::/apis/*"
|
||||
"arn:*:apigateway:*::/apis/*",
|
||||
"arn:*:apigateway:*::/domainnames",
|
||||
"arn:*:apigateway:*::/domainnames/*"
|
||||
],
|
||||
"Sid": "AllowAPIGatewayReadOnly"
|
||||
}
|
||||
|
||||
@@ -150,6 +150,8 @@ Resources:
|
||||
Resource:
|
||||
- "arn:*:apigateway:*::/restapis/*"
|
||||
- "arn:*:apigateway:*::/apis/*"
|
||||
- "arn:*:apigateway:*::/domainnames"
|
||||
- "arn:*:apigateway:*::/domainnames/*"
|
||||
- !If
|
||||
- OrganizationsEnabled
|
||||
- PolicyName: ProwlerOrganizations
|
||||
|
||||
@@ -43,6 +43,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554) compliance coverage for the GCP provider, mapping existing GCP checks across the five DORA pillars [(#11642)](https://github.com/prowler-cloud/prowler/pull/11642)
|
||||
- DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554) compliance coverage for the Cloudflare provider, mapping existing Cloudflare edge/network checks across the applicable DORA pillars [(#11645)](https://github.com/prowler-cloud/prowler/pull/11645)
|
||||
- DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554) compliance coverage for the AlibabaCloud provider, mapping existing AlibabaCloud checks across the applicable DORA pillars [(#11646)](https://github.com/prowler-cloud/prowler/pull/11646)
|
||||
- `apigateway_domain_name_pqc_tls_enabled` check for AWS provider to verify API Gateway custom domain names use a post-quantum TLS security policy [(#11316)](https://github.com/prowler-cloud/prowler/pull/11316)
|
||||
- `transfer_server_pqc_ssh_kex_enabled` check for AWS provider to verify Transfer Family servers use a post-quantum hybrid SSH key exchange security policy [(#11315)](https://github.com/prowler-cloud/prowler/pull/11315)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
@@ -1151,6 +1151,7 @@
|
||||
"elb_insecure_ssl_ciphers",
|
||||
"elb_ssl_listeners",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_ssl_listeners",
|
||||
"s3_bucket_secure_transport_policy"
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
"elb_insecure_ssl_ciphers",
|
||||
"elb_ssl_listeners",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_ssl_listeners",
|
||||
"elbv2_nlb_tls_termination_enabled",
|
||||
|
||||
@@ -2367,6 +2367,7 @@
|
||||
],
|
||||
"Checks": [
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled"
|
||||
]
|
||||
},
|
||||
@@ -2391,6 +2392,7 @@
|
||||
],
|
||||
"Checks": [
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1145,6 +1145,7 @@
|
||||
"Checks": [
|
||||
"apigateway_restapi_client_certificate_enabled",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elb_ssl_listeners",
|
||||
"opensearch_service_domains_node_to_node_encryption_enabled",
|
||||
@@ -1165,6 +1166,7 @@
|
||||
"Checks": [
|
||||
"apigateway_restapi_client_certificate_enabled",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elb_ssl_listeners",
|
||||
"opensearch_service_domains_node_to_node_encryption_enabled",
|
||||
|
||||
@@ -487,6 +487,7 @@
|
||||
"Checks": [
|
||||
"apigateway_restapi_client_certificate_enabled",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elb_ssl_listeners",
|
||||
"s3_bucket_secure_transport_policy"
|
||||
|
||||
@@ -266,6 +266,7 @@
|
||||
"ec2_ebs_default_encryption",
|
||||
"efs_encryption_at_rest_enabled",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elb_ssl_listeners",
|
||||
"opensearch_service_domains_encryption_at_rest_enabled",
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
"Checks": [
|
||||
"elb_insecure_ssl_ciphers",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -2040,6 +2040,7 @@
|
||||
"elb_ssl_listeners",
|
||||
"elb_ssl_listeners_use_acm_certificate",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_nlb_tls_termination_enabled",
|
||||
"elbv2_ssl_listeners",
|
||||
@@ -3091,6 +3092,7 @@
|
||||
"elb_ssl_listeners_use_acm_certificate",
|
||||
"elbv2_desync_mitigation_mode",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_internet_facing",
|
||||
"elbv2_listeners_underneath",
|
||||
|
||||
@@ -2042,6 +2042,7 @@
|
||||
"elb_ssl_listeners",
|
||||
"elb_ssl_listeners_use_acm_certificate",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_nlb_tls_termination_enabled",
|
||||
"elbv2_ssl_listeners",
|
||||
@@ -3094,6 +3095,7 @@
|
||||
"elb_ssl_listeners_use_acm_certificate",
|
||||
"elbv2_desync_mitigation_mode",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elbv2_internet_facing",
|
||||
"elbv2_listeners_underneath",
|
||||
|
||||
@@ -653,6 +653,7 @@
|
||||
"apigateway_restapi_client_certificate_enabled",
|
||||
"ec2_ebs_volume_encryption",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"opensearch_service_domains_node_to_node_encryption_enabled",
|
||||
"s3_bucket_default_encryption",
|
||||
|
||||
@@ -5262,6 +5262,7 @@
|
||||
"Checks": [
|
||||
"apigateway_restapi_client_certificate_enabled",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elb_ssl_listeners",
|
||||
"opensearch_service_domains_node_to_node_encryption_enabled",
|
||||
@@ -5550,6 +5551,7 @@
|
||||
],
|
||||
"Checks": [
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elb_ssl_listeners"
|
||||
]
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"ec2_instance_public_ip",
|
||||
"efs_encryption_at_rest_enabled",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"elb_ssl_listeners",
|
||||
"ec2_ebs_default_encryption",
|
||||
|
||||
@@ -474,6 +474,7 @@
|
||||
"elbv2_ssl_listeners",
|
||||
"elb_insecure_ssl_ciphers",
|
||||
"elbv2_insecure_ssl_ciphers",
|
||||
"apigateway_domain_name_pqc_tls_enabled",
|
||||
"transfer_server_pqc_ssh_kex_enabled",
|
||||
"redshift_cluster_in_transit_encryption_enabled",
|
||||
"elasticache_redis_cluster_in_transit_encryption_enabled",
|
||||
|
||||
@@ -380,6 +380,14 @@ aws:
|
||||
# Minimum number of Availability Zones that an ELBv2 must be in
|
||||
elbv2_min_azs: 2
|
||||
|
||||
# AWS Post-Quantum TLS Configuration
|
||||
# aws.apigateway_domain_name_pqc_tls_enabled
|
||||
# Allowed post-quantum TLS security policies for API Gateway custom domain names
|
||||
apigateway_pqc_tls_allowed_policies:
|
||||
- "SecurityPolicy_TLS13_1_2_FIPS_PFS_PQ_2025_09"
|
||||
- "SecurityPolicy_TLS13_1_2_PFS_PQ_2025_09"
|
||||
- "SecurityPolicy_TLS13_1_2_PQ_2025_09"
|
||||
|
||||
# AWS Post-Quantum SSH Key Exchange Configuration
|
||||
# aws.transfer_server_pqc_ssh_kex_enabled
|
||||
# Allowed AWS Transfer Family security policies with post-quantum SSH key exchange
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "apigateway_domain_name_pqc_tls_enabled",
|
||||
"CheckTitle": "API Gateway custom domain names use a post-quantum TLS security policy",
|
||||
"CheckType": [
|
||||
"Software and Configuration Checks/AWS Security Best Practices"
|
||||
],
|
||||
"ServiceName": "apigateway",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "low",
|
||||
"ResourceType": "AwsApiGatewayDomainName",
|
||||
"ResourceGroup": "network",
|
||||
"Description": "**API Gateway custom domain names** for REST APIs are assessed for use of a **post-quantum (PQ) TLS security policy** such as `SecurityPolicy_TLS13_1_2_PQ_2025_09`. Custom domains with legacy policies such as `TLS_1_0` or `TLS_1_2` lack hybrid ML-KEM key exchange, leaving captured traffic vulnerable to future quantum decryption.",
|
||||
"Risk": "Without a PQ-ready TLS policy, traffic to API Gateway custom domains captured today can be decrypted once a **cryptographically relevant quantum computer** exists (**harvest-now, decrypt-later** attack). This threatens long-term **confidentiality** of API payloads, credentials, and bearer tokens.",
|
||||
"RelatedUrl": "",
|
||||
"AdditionalURLs": [
|
||||
"https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-custom-domain-tls-version.html",
|
||||
"https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-security-policies-list.html",
|
||||
"https://aws.amazon.com/security/post-quantum-cryptography/",
|
||||
"https://csrc.nist.gov/projects/post-quantum-cryptography"
|
||||
],
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "aws apigateway update-domain-name --domain-name <domain_name> --patch-operations op=replace,path=/securityPolicy,value=SecurityPolicy_TLS13_1_2_PQ_2025_09",
|
||||
"NativeIaC": "```yaml\nResources:\n <example_resource_name>:\n Type: AWS::ApiGateway::DomainName\n Properties:\n DomainName: api.example.com\n RegionalCertificateArn: <example_certificate_arn>\n SecurityPolicy: SecurityPolicy_TLS13_1_2_PQ_2025_09 # FIX: enhanced post-quantum security policy\n EndpointConfiguration:\n Types:\n - REGIONAL\n```",
|
||||
"Other": "1. In the AWS Console, go to API Gateway > Custom domain names\n2. Select the custom domain and choose Edit on Domain name configurations\n3. Set Security policy to SecurityPolicy_TLS13_1_2_PQ_2025_09 (post-quantum) and Endpoint access mode to Strict\n4. Save the changes",
|
||||
"Terraform": "```hcl\nresource \"aws_api_gateway_domain_name\" \"<example_resource_name>\" {\n domain_name = \"api.example.com\"\n regional_certificate_arn = \"<example_certificate_arn>\"\n security_policy = \"SecurityPolicy_TLS13_1_2_PQ_2025_09\" # FIX: enhanced post-quantum security policy\n endpoint_configuration {\n types = [\"REGIONAL\"]\n }\n}\n```"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Migrate every API Gateway custom domain name to an **enhanced post-quantum TLS policy** such as `SecurityPolicy_TLS13_1_2_PQ_2025_09` that enables hybrid ML-KEM key exchange. Note that you must also enable Strict endpoint access mode and that mutual TLS is not supported on enhanced policies. Review allowed policies regularly as AWS publishes new PQ-ready options.",
|
||||
"Url": "https://hub.prowler.com/check/apigateway_domain_name_pqc_tls_enabled"
|
||||
}
|
||||
},
|
||||
"Categories": [
|
||||
"encryption"
|
||||
],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "API Gateway HTTP and WebSocket APIs only support the legacy TLS_1_2 security policy and therefore cannot use post-quantum TLS today; this check evaluates REST API custom domain names only."
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_AWS
|
||||
from prowler.providers.aws.services.apigateway.apigateway_client import (
|
||||
apigateway_client,
|
||||
)
|
||||
|
||||
PQC_APIGATEWAY_POLICIES_DEFAULT = [
|
||||
"SecurityPolicy_TLS13_1_2_FIPS_PFS_PQ_2025_09",
|
||||
"SecurityPolicy_TLS13_1_2_PFS_PQ_2025_09",
|
||||
"SecurityPolicy_TLS13_1_2_PQ_2025_09",
|
||||
]
|
||||
|
||||
|
||||
def _get_allowed_policies(configured_policies: object) -> list[str]:
|
||||
if not isinstance(configured_policies, list):
|
||||
return PQC_APIGATEWAY_POLICIES_DEFAULT
|
||||
|
||||
return configured_policies
|
||||
|
||||
|
||||
class apigateway_domain_name_pqc_tls_enabled(Check):
|
||||
"""Verify that every API Gateway custom domain name uses a post-quantum TLS policy.
|
||||
|
||||
A custom domain name PASSES when its ``securityPolicy`` belongs to the
|
||||
configured allowlist of enhanced post-quantum policies.
|
||||
"""
|
||||
|
||||
def execute(self) -> list[Check_Report_AWS]:
|
||||
"""Execute the API Gateway custom domain post-quantum TLS check.
|
||||
|
||||
Returns:
|
||||
A list of reports for API Gateway custom domain names and their
|
||||
post-quantum TLS policy compliance status.
|
||||
"""
|
||||
findings = []
|
||||
pqc_policies = _get_allowed_policies(
|
||||
apigateway_client.audit_config.get("apigateway_pqc_tls_allowed_policies")
|
||||
)
|
||||
for domain in apigateway_client.domain_names:
|
||||
report = Check_Report_AWS(metadata=self.metadata(), resource=domain)
|
||||
policy = domain.security_policy or "<none>"
|
||||
if domain.security_policy in pqc_policies:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"API Gateway custom domain {domain.name} uses post-quantum "
|
||||
f"TLS policy {policy}."
|
||||
)
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"API Gateway custom domain {domain.name} uses TLS policy "
|
||||
f"{policy}, which is not in the post-quantum allowlist."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from botocore.exceptions import ClientError
|
||||
from pydantic.v1 import BaseModel
|
||||
@@ -13,12 +13,45 @@ class APIGateway(AWSService):
|
||||
# Call AWSService's __init__
|
||||
super().__init__(__class__.__name__, provider)
|
||||
self.rest_apis = []
|
||||
self.domain_names = []
|
||||
self.__threading_call__(self._get_rest_apis)
|
||||
self.__threading_call__(self._get_domain_names)
|
||||
self._get_authorizers()
|
||||
self._get_rest_api()
|
||||
self._get_stages()
|
||||
self._get_resources()
|
||||
|
||||
def _get_domain_names(self, regional_client: Any) -> None:
|
||||
"""Get API Gateway custom domain names for a regional client.
|
||||
|
||||
Args:
|
||||
regional_client: Regional API Gateway boto3 client used to list
|
||||
custom domain names.
|
||||
"""
|
||||
logger.info("APIGateway - Getting custom domain names...")
|
||||
try:
|
||||
paginator = regional_client.get_paginator("get_domain_names")
|
||||
for page in paginator.paginate():
|
||||
for item in page.get("items", []):
|
||||
domain_name = item.get("domainName", "")
|
||||
arn = f"arn:{self.audited_partition}:apigateway:{regional_client.region}::/domainnames/{domain_name}"
|
||||
if not self.audit_resources or (
|
||||
is_resource_filtered(arn, self.audit_resources)
|
||||
):
|
||||
self.domain_names.append(
|
||||
DomainName(
|
||||
name=domain_name,
|
||||
arn=arn,
|
||||
region=regional_client.region,
|
||||
security_policy=item.get("securityPolicy", ""),
|
||||
tags=[item.get("tags", {})],
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def _get_rest_apis(self, regional_client):
|
||||
logger.info("APIGateway - Getting Rest APIs...")
|
||||
try:
|
||||
@@ -249,3 +282,21 @@ class RestAPI(BaseModel):
|
||||
stages: list[Stage] = []
|
||||
tags: Optional[list] = []
|
||||
resources: list[PathResourceMethods] = []
|
||||
|
||||
|
||||
class DomainName(BaseModel):
|
||||
"""API Gateway custom domain name metadata.
|
||||
|
||||
Attributes:
|
||||
name: Custom domain name.
|
||||
arn: Custom domain name ARN.
|
||||
region: AWS region where the custom domain name exists.
|
||||
security_policy: TLS security policy configured for the custom domain.
|
||||
tags: Custom domain tags.
|
||||
"""
|
||||
|
||||
name: str
|
||||
arn: str
|
||||
region: str
|
||||
security_policy: str = ""
|
||||
tags: Optional[list] = []
|
||||
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
from unittest import mock
|
||||
|
||||
from moto import mock_aws
|
||||
|
||||
from prowler.providers.aws.services.apigateway.apigateway_service import DomainName
|
||||
from tests.providers.aws.utils import (
|
||||
AWS_REGION_US_EAST_1,
|
||||
set_mocked_aws_provider,
|
||||
)
|
||||
|
||||
DOMAIN_NAME = "api.example.com"
|
||||
DOMAIN_ARN = f"arn:aws:apigateway:{AWS_REGION_US_EAST_1}::/domainnames/{DOMAIN_NAME}"
|
||||
|
||||
|
||||
def _build_client(security_policy: str):
|
||||
apigw_client = mock.MagicMock()
|
||||
apigw_client.audit_config = {}
|
||||
apigw_client.domain_names = [
|
||||
DomainName(
|
||||
name=DOMAIN_NAME,
|
||||
arn=DOMAIN_ARN,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
security_policy=security_policy,
|
||||
)
|
||||
]
|
||||
return apigw_client
|
||||
|
||||
|
||||
class Test_apigateway_domain_name_pqc_tls_enabled:
|
||||
@mock_aws
|
||||
def test_no_domains(self):
|
||||
apigw_client = mock.MagicMock()
|
||||
apigw_client.audit_config = {}
|
||||
apigw_client.domain_names = []
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled.apigateway_client",
|
||||
new=apigw_client,
|
||||
):
|
||||
from prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled import (
|
||||
apigateway_domain_name_pqc_tls_enabled,
|
||||
)
|
||||
|
||||
check = apigateway_domain_name_pqc_tls_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
@mock_aws
|
||||
def test_tls13_only_policy_fails_by_default(self):
|
||||
apigw_client = _build_client("SecurityPolicy_TLS13_1_3_2025_09")
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled.apigateway_client",
|
||||
new=apigw_client,
|
||||
):
|
||||
from prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled import (
|
||||
apigateway_domain_name_pqc_tls_enabled,
|
||||
)
|
||||
|
||||
check = apigateway_domain_name_pqc_tls_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "SecurityPolicy_TLS13_1_3_2025_09" in result[0].status_extended
|
||||
assert "not in the post-quantum allowlist" in result[0].status_extended
|
||||
assert result[0].resource_id == DOMAIN_NAME
|
||||
assert result[0].resource_arn == DOMAIN_ARN
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
|
||||
@mock_aws
|
||||
def test_alternate_pq_policy(self):
|
||||
apigw_client = _build_client("SecurityPolicy_TLS13_1_2_PQ_2025_09")
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled.apigateway_client",
|
||||
new=apigw_client,
|
||||
):
|
||||
from prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled import (
|
||||
apigateway_domain_name_pqc_tls_enabled,
|
||||
)
|
||||
|
||||
check = apigateway_domain_name_pqc_tls_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
"SecurityPolicy_TLS13_1_2_PQ_2025_09" in result[0].status_extended
|
||||
)
|
||||
|
||||
@mock_aws
|
||||
def test_legacy_tls_1_2(self):
|
||||
apigw_client = _build_client("TLS_1_2")
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled.apigateway_client",
|
||||
new=apigw_client,
|
||||
):
|
||||
from prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled import (
|
||||
apigateway_domain_name_pqc_tls_enabled,
|
||||
)
|
||||
|
||||
check = apigateway_domain_name_pqc_tls_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "TLS_1_2" in result[0].status_extended
|
||||
assert "not in the post-quantum allowlist" in result[0].status_extended
|
||||
|
||||
@mock_aws
|
||||
def test_missing_security_policy(self):
|
||||
apigw_client = _build_client("")
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled.apigateway_client",
|
||||
new=apigw_client,
|
||||
):
|
||||
from prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled import (
|
||||
apigateway_domain_name_pqc_tls_enabled,
|
||||
)
|
||||
|
||||
check = apigateway_domain_name_pqc_tls_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "<none>" in result[0].status_extended
|
||||
|
||||
@mock_aws
|
||||
def test_configurable_allowlist(self):
|
||||
apigw_client = _build_client("TLS_1_2")
|
||||
apigw_client.audit_config = {
|
||||
"apigateway_pqc_tls_allowed_policies": [
|
||||
"TLS_1_2",
|
||||
]
|
||||
}
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled.apigateway_client",
|
||||
new=apigw_client,
|
||||
):
|
||||
from prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled import (
|
||||
apigateway_domain_name_pqc_tls_enabled,
|
||||
)
|
||||
|
||||
check = apigateway_domain_name_pqc_tls_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
|
||||
@mock_aws
|
||||
def test_null_config_uses_default_allowlist(self):
|
||||
apigw_client = _build_client("SecurityPolicy_TLS13_1_2_PQ_2025_09")
|
||||
apigw_client.audit_config = {
|
||||
"apigateway_pqc_tls_allowed_policies": None,
|
||||
}
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled.apigateway_client",
|
||||
new=apigw_client,
|
||||
):
|
||||
from prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled import (
|
||||
apigateway_domain_name_pqc_tls_enabled,
|
||||
)
|
||||
|
||||
check = apigateway_domain_name_pqc_tls_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
|
||||
@mock_aws
|
||||
def test_non_iterable_config_uses_default_allowlist(self):
|
||||
apigw_client = _build_client("SecurityPolicy_TLS13_1_2_PQ_2025_09")
|
||||
apigw_client.audit_config = {
|
||||
"apigateway_pqc_tls_allowed_policies": 123,
|
||||
}
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled.apigateway_client",
|
||||
new=apigw_client,
|
||||
):
|
||||
from prowler.providers.aws.services.apigateway.apigateway_domain_name_pqc_tls_enabled.apigateway_domain_name_pqc_tls_enabled import (
|
||||
apigateway_domain_name_pqc_tls_enabled,
|
||||
)
|
||||
|
||||
check = apigateway_domain_name_pqc_tls_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
@@ -206,3 +206,26 @@ class Test_APIGateway_Service:
|
||||
assert list(apigateway.rest_apis[0].resources[1].resource_methods.values()) == [
|
||||
"AWS_IAM"
|
||||
]
|
||||
|
||||
# Test APIGateway _get_domain_names
|
||||
@mock_aws
|
||||
def test_get_domain_names(self):
|
||||
apigateway_client = client("apigateway", region_name=AWS_REGION_US_EAST_1)
|
||||
|
||||
apigateway_client.create_domain_name(
|
||||
domainName="api.example.com",
|
||||
securityPolicy="SecurityPolicy_TLS13_1_3_2025_09",
|
||||
)
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
apigateway = APIGateway(aws_provider)
|
||||
|
||||
assert len(apigateway.domain_names) == 1
|
||||
domain = apigateway.domain_names[0]
|
||||
assert domain.name == "api.example.com"
|
||||
assert domain.region == AWS_REGION_US_EAST_1
|
||||
assert domain.security_policy == "SecurityPolicy_TLS13_1_3_2025_09"
|
||||
assert (
|
||||
domain.arn
|
||||
== f"arn:aws:apigateway:{AWS_REGION_US_EAST_1}::/domainnames/api.example.com"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user