mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-04 19:21:51 +00:00
feat(aws): add rolesanywhere service and pqc trust anchor check (#11319)
Co-authored-by: Hugo P.Brito <hugopbrit@gmail.com>
This commit is contained in:
@@ -461,6 +461,12 @@ mainConfig:
|
||||
- "TransferSecurityPolicy-AS2Restricted-2025-07"
|
||||
|
||||
|
||||
# aws.rolesanywhere_trust_anchor_pqc_pki
|
||||
rolesanywhere_pqc_pca_key_algorithms:
|
||||
- "ML_DSA_44"
|
||||
- "ML_DSA_65"
|
||||
- "ML_DSA_87"
|
||||
|
||||
# AWS Secrets Configuration
|
||||
# Patterns to ignore in the secrets checks
|
||||
secrets_ignore_patterns: []
|
||||
|
||||
@@ -57,6 +57,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 |
|
||||
| `rolesanywhere_trust_anchor_pqc_pki` | `rolesanywhere_pqc_pca_key_algorithms` | List of Strings |
|
||||
| `cloudfront_distributions_pqc_tls_enabled` | `cloudfront_pqc_min_protocol_versions` | List of Strings |
|
||||
| `apigateway_domain_name_pqc_tls_enabled` | `apigateway_pqc_tls_allowed_policies` | List of Strings |
|
||||
| `guardduty_is_enabled` | `mute_non_default_regions` | Boolean |
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
"lightsail:GetRelationalDatabases",
|
||||
"macie2:GetMacieSession",
|
||||
"macie2:GetAutomatedDiscoveryConfiguration",
|
||||
"rolesanywhere:ListTagsForResource",
|
||||
"rolesanywhere:ListTrustAnchors",
|
||||
"s3:GetAccountPublicAccessBlock",
|
||||
"shield:DescribeProtection",
|
||||
"shield:GetSubscriptionState",
|
||||
|
||||
@@ -129,6 +129,8 @@ Resources:
|
||||
- "lightsail:GetRelationalDatabases"
|
||||
- "macie2:GetMacieSession"
|
||||
- "macie2:GetAutomatedDiscoveryConfiguration"
|
||||
- "rolesanywhere:ListTagsForResource"
|
||||
- "rolesanywhere:ListTrustAnchors"
|
||||
- "s3:GetAccountPublicAccessBlock"
|
||||
- "shield:DescribeProtection"
|
||||
- "shield:GetSubscriptionState"
|
||||
|
||||
@@ -49,6 +49,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- `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)
|
||||
- `acmpca_certificate_authority_pqc_key_algorithm` check and new `acmpca` service for AWS provider to verify AWS Private CA certificate authorities use a post-quantum (ML-DSA) key algorithm [(#11318)](https://github.com/prowler-cloud/prowler/pull/11318)
|
||||
- `rolesanywhere_trust_anchor_pqc_pki` check and new `rolesanywhere` service for AWS provider to verify IAM Roles Anywhere trust anchors are backed by a post-quantum (ML-DSA) PKI [(#11319)](https://github.com/prowler-cloud/prowler/pull/11319)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
|
||||
@@ -398,6 +398,13 @@ aws:
|
||||
- "SecurityPolicy_TLS13_1_2_PFS_PQ_2025_09"
|
||||
- "SecurityPolicy_TLS13_1_2_PQ_2025_09"
|
||||
|
||||
# aws.rolesanywhere_trust_anchor_pqc_pki
|
||||
# Allowed post-quantum key algorithms for AWS Private CAs backing IAM Roles Anywhere trust anchors
|
||||
rolesanywhere_pqc_pca_key_algorithms:
|
||||
- "ML_DSA_44"
|
||||
- "ML_DSA_65"
|
||||
- "ML_DSA_87"
|
||||
|
||||
# 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
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_service import (
|
||||
RolesAnywhere,
|
||||
)
|
||||
from prowler.providers.common.provider import Provider
|
||||
|
||||
rolesanywhere_client = RolesAnywhere(Provider.get_global_provider())
|
||||
@@ -0,0 +1,64 @@
|
||||
from typing import Dict, List
|
||||
|
||||
from pydantic.v1 import BaseModel, Field
|
||||
|
||||
from prowler.lib.logger import logger
|
||||
from prowler.lib.scan_filters.scan_filters import is_resource_filtered
|
||||
from prowler.providers.aws.lib.service.service import AWSService
|
||||
|
||||
|
||||
class RolesAnywhere(AWSService):
|
||||
def __init__(self, provider):
|
||||
super().__init__(__class__.__name__, provider)
|
||||
self.trust_anchors = {}
|
||||
self.__threading_call__(self._list_trust_anchors)
|
||||
|
||||
def _list_trust_anchors(self, regional_client):
|
||||
logger.info("RolesAnywhere - Listing Trust Anchors...")
|
||||
try:
|
||||
paginator = regional_client.get_paginator("list_trust_anchors")
|
||||
for page in paginator.paginate():
|
||||
for ta in page.get("trustAnchors", []):
|
||||
arn = ta.get("trustAnchorArn", "")
|
||||
if not arn:
|
||||
continue
|
||||
if self.audit_resources and not is_resource_filtered(
|
||||
arn, self.audit_resources
|
||||
):
|
||||
continue
|
||||
source = ta.get("source", {}) or {}
|
||||
source_data = source.get("sourceData", {}) or {}
|
||||
tags = []
|
||||
try:
|
||||
tags = regional_client.list_tags_for_resource(
|
||||
resourceArn=arn
|
||||
).get("tags", [])
|
||||
except Exception as error:
|
||||
logger.warning(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
self.trust_anchors[arn] = TrustAnchor(
|
||||
arn=arn,
|
||||
id=ta.get("trustAnchorId", ""),
|
||||
name=ta.get("name", ""),
|
||||
region=regional_client.region,
|
||||
enabled=ta.get("enabled", False),
|
||||
source_type=source.get("sourceType", ""),
|
||||
acm_pca_arn=source_data.get("acmPcaArn", ""),
|
||||
tags=tags,
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
|
||||
class TrustAnchor(BaseModel):
|
||||
arn: str
|
||||
id: str
|
||||
name: str
|
||||
region: str
|
||||
enabled: bool = False
|
||||
source_type: str = ""
|
||||
acm_pca_arn: str = ""
|
||||
tags: List[Dict[str, str]] = Field(default_factory=list)
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "rolesanywhere_trust_anchor_pqc_pki",
|
||||
"CheckTitle": "IAM Roles Anywhere trust anchors are backed by a post-quantum (ML-DSA) PKI",
|
||||
"CheckType": [
|
||||
"Software and Configuration Checks/AWS Security Best Practices"
|
||||
],
|
||||
"ServiceName": "rolesanywhere",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "low",
|
||||
"ResourceType": "AwsRolesAnywhereTrustAnchor",
|
||||
"ResourceGroup": "security",
|
||||
"Description": "**IAM Roles Anywhere trust anchors** are assessed for use of a **post-quantum digital signature algorithm** (ML-DSA). A trust anchor backed by an AWS Private CA whose `KeyAlgorithm` is RSA or ECC produces signatures vulnerable to forgery by a future quantum attacker, allowing an unintended actor to issue certificates and obtain unauthorized AWS access.",
|
||||
"Risk": "Trust anchors are the root of trust for workloads authenticating to AWS via X.509 certificates. If the signing CA uses RSA or ECC, an attacker with quantum capability could forge end-entity certificates and impersonate workloads. Migrating trust anchors to **ML-DSA-backed PKI** (NIST FIPS 204) protects this control plane in the post-quantum era.",
|
||||
"RelatedUrl": "",
|
||||
"AdditionalURLs": [
|
||||
"https://docs.aws.amazon.com/rolesanywhere/latest/userguide/introduction.html",
|
||||
"https://aws.amazon.com/about-aws/whats-new/2026/03/iam-roles-anywhere-post-quantum-digital-certificates/",
|
||||
"https://aws.amazon.com/security/post-quantum-cryptography/",
|
||||
"https://csrc.nist.gov/pubs/fips/204/final"
|
||||
],
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "aws rolesanywhere create-trust-anchor --name pqc-trust --source 'sourceType=AWS_ACM_PCA,sourceData={acmPcaArn=<ml_dsa_ca_arn>}' --enabled",
|
||||
"NativeIaC": "```yaml\nResources:\n <example_resource_name>:\n Type: AWS::RolesAnywhere::TrustAnchor\n Properties:\n Name: pqc-trust\n Enabled: true\n Source:\n SourceType: AWS_ACM_PCA\n SourceData:\n AcmPcaArn: <ml_dsa_ca_arn> # FIX: PCA must use ML_DSA key algorithm\n```",
|
||||
"Other": "1. Create a new AWS Private CA with a post-quantum KeyAlgorithm (ML_DSA_44/65/87)\n2. Create a new Roles Anywhere trust anchor with sourceType=AWS_ACM_PCA pointing to the new CA\n3. Rotate end-entity certificates issued from the new CA\n4. Delete the legacy trust anchor once workloads have rotated",
|
||||
"Terraform": "```hcl\nresource \"aws_rolesanywhere_trust_anchor\" \"<example_resource_name>\" {\n name = \"pqc-trust\"\n enabled = true\n source {\n source_type = \"AWS_ACM_PCA\"\n source_data {\n acm_pca_arn = \"<ml_dsa_ca_arn>\" # FIX: PCA must use ML_DSA key algorithm\n }\n }\n}\n```"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Back IAM Roles Anywhere trust anchors with an **AWS Private CA that uses an ML-DSA key algorithm**. For trust anchors backed by an external certificate bundle, ensure the certificates were issued by an ML-DSA CA and re-verify periodically as the cryptographic landscape evolves.",
|
||||
"Url": "https://hub.prowler.com/check/rolesanywhere_trust_anchor_pqc_pki"
|
||||
}
|
||||
},
|
||||
"Categories": [
|
||||
"encryption"
|
||||
],
|
||||
"DependsOn": [
|
||||
"acmpca_certificate_authority_pqc_key_algorithm"
|
||||
],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Trust anchors backed by an external CERTIFICATE_BUNDLE cannot be evaluated automatically by this check and are reported as FAIL with guidance to migrate to an AWS Private CA using an ML-DSA key algorithm."
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
from prowler.lib.check.models import Check, Check_Report_AWS
|
||||
from prowler.providers.aws.services.acmpca.acmpca_client import acmpca_client
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_client import (
|
||||
rolesanywhere_client,
|
||||
)
|
||||
|
||||
PQC_PCA_KEY_ALGORITHMS_DEFAULT = [
|
||||
"ML_DSA_44",
|
||||
"ML_DSA_65",
|
||||
"ML_DSA_87",
|
||||
]
|
||||
|
||||
|
||||
class rolesanywhere_trust_anchor_pqc_pki(Check):
|
||||
"""Verify that IAM Roles Anywhere trust anchors are backed by a post-quantum PKI.
|
||||
|
||||
For trust anchors whose source is ``AWS_ACM_PCA``, the linked Private CA's
|
||||
``KeyAlgorithm`` is checked against the configured ML-DSA allowlist.
|
||||
Trust anchors backed by an external ``CERTIFICATE_BUNDLE`` are reported as
|
||||
FAIL because their certificate signature algorithm cannot be inspected
|
||||
from the IAM Roles Anywhere API alone.
|
||||
"""
|
||||
|
||||
def execute(self) -> list[Check_Report_AWS]:
|
||||
findings = []
|
||||
pqc_algorithms = rolesanywhere_client.audit_config.get(
|
||||
"rolesanywhere_pqc_pca_key_algorithms", PQC_PCA_KEY_ALGORITHMS_DEFAULT
|
||||
)
|
||||
for trust_anchor in rolesanywhere_client.trust_anchors.values():
|
||||
report = Check_Report_AWS(metadata=self.metadata(), resource=trust_anchor)
|
||||
if trust_anchor.source_type == "AWS_ACM_PCA":
|
||||
linked_ca = acmpca_client.certificate_authorities.get(
|
||||
trust_anchor.acm_pca_arn
|
||||
)
|
||||
if linked_ca and linked_ca.status != "ACTIVE":
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"IAM Roles Anywhere trust anchor {trust_anchor.name} is "
|
||||
f"backed by Private CA {linked_ca.id}, which is in "
|
||||
f"{linked_ca.status or '<unknown>'} status and cannot be "
|
||||
"used as an active post-quantum PKI trust root."
|
||||
)
|
||||
elif linked_ca and linked_ca.key_algorithm in pqc_algorithms:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"IAM Roles Anywhere trust anchor {trust_anchor.name} is "
|
||||
f"backed by Private CA {linked_ca.id} using post-quantum "
|
||||
f"key algorithm {linked_ca.key_algorithm}."
|
||||
)
|
||||
elif linked_ca:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"IAM Roles Anywhere trust anchor {trust_anchor.name} is "
|
||||
f"backed by Private CA {linked_ca.id} using key algorithm "
|
||||
f"{linked_ca.key_algorithm or '<unknown>'}, which is not "
|
||||
"post-quantum (ML-DSA)."
|
||||
)
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"IAM Roles Anywhere trust anchor {trust_anchor.name} is "
|
||||
f"backed by Private CA {trust_anchor.acm_pca_arn}, which "
|
||||
"could not be inspected (cross-account or missing "
|
||||
"acm-pca permissions). Verify the CA uses an ML-DSA key "
|
||||
"algorithm."
|
||||
)
|
||||
else:
|
||||
source = trust_anchor.source_type or "<none>"
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"IAM Roles Anywhere trust anchor {trust_anchor.name} uses "
|
||||
f"source type {source}; the certificate signature algorithm "
|
||||
"cannot be inspected automatically. Migrate to an AWS Private "
|
||||
"CA using an ML-DSA key algorithm to enable post-quantum "
|
||||
"evaluation."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,92 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
import botocore
|
||||
from moto import mock_aws
|
||||
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_service import (
|
||||
RolesAnywhere,
|
||||
TrustAnchor,
|
||||
)
|
||||
from tests.providers.aws.utils import (
|
||||
AWS_ACCOUNT_NUMBER,
|
||||
AWS_REGION_US_EAST_1,
|
||||
set_mocked_aws_provider,
|
||||
)
|
||||
|
||||
TA_ID = "11111111-2222-3333-4444-555555555555"
|
||||
TA_ARN = f"arn:aws:rolesanywhere:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:trust-anchor/{TA_ID}"
|
||||
PCA_ARN = f"arn:aws:acm-pca:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:certificate-authority/abc"
|
||||
|
||||
make_api_call = botocore.client.BaseClient._make_api_call
|
||||
|
||||
|
||||
def mock_make_api_call(self, operation_name, kwarg):
|
||||
if operation_name == "ListTrustAnchors":
|
||||
return {
|
||||
"trustAnchors": [
|
||||
{
|
||||
"trustAnchorArn": TA_ARN,
|
||||
"trustAnchorId": TA_ID,
|
||||
"name": "pqc-trust",
|
||||
"enabled": True,
|
||||
"source": {
|
||||
"sourceType": "AWS_ACM_PCA",
|
||||
"sourceData": {"acmPcaArn": PCA_ARN},
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
if operation_name == "ListTagsForResource":
|
||||
return {"tags": [{"key": "Environment", "value": "test"}]}
|
||||
return make_api_call(self, operation_name, kwarg)
|
||||
|
||||
|
||||
def mock_make_api_call_tags_failure(self, operation_name, kwarg):
|
||||
if operation_name == "ListTagsForResource":
|
||||
raise botocore.exceptions.ClientError(
|
||||
{
|
||||
"Error": {
|
||||
"Code": "AccessDeniedException",
|
||||
"Message": "Access denied",
|
||||
}
|
||||
},
|
||||
operation_name,
|
||||
)
|
||||
return mock_make_api_call(self, operation_name, kwarg)
|
||||
|
||||
|
||||
class Test_RolesAnywhere_Service:
|
||||
@mock_aws
|
||||
def test_service(self):
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
rolesanywhere = RolesAnywhere(aws_provider)
|
||||
assert rolesanywhere.service == "rolesanywhere"
|
||||
|
||||
@patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call)
|
||||
@mock_aws
|
||||
def test_list_trust_anchors(self):
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
rolesanywhere = RolesAnywhere(aws_provider)
|
||||
assert len(rolesanywhere.trust_anchors) == 1
|
||||
ta = rolesanywhere.trust_anchors[TA_ARN]
|
||||
assert isinstance(ta, TrustAnchor)
|
||||
assert ta.id == TA_ID
|
||||
assert ta.name == "pqc-trust"
|
||||
assert ta.enabled is True
|
||||
assert ta.source_type == "AWS_ACM_PCA"
|
||||
assert ta.acm_pca_arn == PCA_ARN
|
||||
assert ta.region == AWS_REGION_US_EAST_1
|
||||
assert ta.tags == [{"key": "Environment", "value": "test"}]
|
||||
|
||||
@patch(
|
||||
"botocore.client.BaseClient._make_api_call", new=mock_make_api_call_tags_failure
|
||||
)
|
||||
@mock_aws
|
||||
def test_list_trust_anchors_continues_when_tags_fail(self):
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
rolesanywhere = RolesAnywhere(aws_provider)
|
||||
assert len(rolesanywhere.trust_anchors) == 1
|
||||
ta = rolesanywhere.trust_anchors[TA_ARN]
|
||||
assert isinstance(ta, TrustAnchor)
|
||||
assert ta.id == TA_ID
|
||||
assert ta.tags == []
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.aws.services.acmpca.acmpca_service import CertificateAuthority
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_service import (
|
||||
TrustAnchor,
|
||||
)
|
||||
from tests.providers.aws.utils import (
|
||||
AWS_ACCOUNT_NUMBER,
|
||||
AWS_REGION_US_EAST_1,
|
||||
set_mocked_aws_provider,
|
||||
)
|
||||
|
||||
TA_ID = "11111111-2222-3333-4444-555555555555"
|
||||
TA_NAME = "pqc-trust"
|
||||
TA_ARN = f"arn:aws:rolesanywhere:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:trust-anchor/{TA_ID}"
|
||||
PCA_ID = "12345678-1234-1234-1234-123456789012"
|
||||
PCA_ARN = f"arn:aws:acm-pca:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:certificate-authority/{PCA_ID}"
|
||||
|
||||
|
||||
def _trust_anchor(*, source_type: str, acm_pca_arn: str = ""):
|
||||
return TrustAnchor(
|
||||
arn=TA_ARN,
|
||||
id=TA_ID,
|
||||
name=TA_NAME,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
enabled=True,
|
||||
source_type=source_type,
|
||||
acm_pca_arn=acm_pca_arn,
|
||||
)
|
||||
|
||||
|
||||
def _ca(key_algorithm: str, status: str = "ACTIVE"):
|
||||
return CertificateAuthority(
|
||||
arn=PCA_ARN,
|
||||
id=PCA_ID,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
status=status,
|
||||
type="SUBORDINATE",
|
||||
usage_mode="GENERAL_PURPOSE",
|
||||
key_algorithm=key_algorithm,
|
||||
signing_algorithm=(
|
||||
key_algorithm if "ML_DSA" in key_algorithm else "SHA256WITHRSA"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _build_clients(trust_anchors, certificate_authorities=None, audit_config=None):
|
||||
ra_client = mock.MagicMock()
|
||||
ra_client.trust_anchors = trust_anchors
|
||||
ra_client.audit_config = audit_config or {}
|
||||
pca_client = mock.MagicMock()
|
||||
pca_client.certificate_authorities = certificate_authorities or {}
|
||||
return ra_client, pca_client
|
||||
|
||||
|
||||
def _patched(ra_client, pca_client):
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
return [
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.rolesanywhere.rolesanywhere_trust_anchor_pqc_pki.rolesanywhere_trust_anchor_pqc_pki.rolesanywhere_client",
|
||||
new=ra_client,
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.rolesanywhere.rolesanywhere_trust_anchor_pqc_pki.rolesanywhere_trust_anchor_pqc_pki.acmpca_client",
|
||||
new=pca_client,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def _enter(patches):
|
||||
from contextlib import ExitStack
|
||||
|
||||
stack = ExitStack()
|
||||
for p in patches:
|
||||
stack.enter_context(p)
|
||||
return stack
|
||||
|
||||
|
||||
class Test_rolesanywhere_trust_anchor_pqc_pki:
|
||||
def test_no_trust_anchors(self):
|
||||
ra_client, pca_client = _build_clients({})
|
||||
with _enter(_patched(ra_client, pca_client)):
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_trust_anchor_pqc_pki.rolesanywhere_trust_anchor_pqc_pki import (
|
||||
rolesanywhere_trust_anchor_pqc_pki,
|
||||
)
|
||||
|
||||
result = rolesanywhere_trust_anchor_pqc_pki().execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_pca_backed_pqc(self):
|
||||
ra_client, pca_client = _build_clients(
|
||||
{TA_ARN: _trust_anchor(source_type="AWS_ACM_PCA", acm_pca_arn=PCA_ARN)},
|
||||
certificate_authorities={PCA_ARN: _ca("ML_DSA_65")},
|
||||
)
|
||||
with _enter(_patched(ra_client, pca_client)):
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_trust_anchor_pqc_pki.rolesanywhere_trust_anchor_pqc_pki import (
|
||||
rolesanywhere_trust_anchor_pqc_pki,
|
||||
)
|
||||
|
||||
result = rolesanywhere_trust_anchor_pqc_pki().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert "ML_DSA_65" in result[0].status_extended
|
||||
assert result[0].resource_id == TA_ID
|
||||
assert result[0].resource_arn == TA_ARN
|
||||
|
||||
def test_pca_backed_custom_allowlist_pqc(self):
|
||||
ra_client, pca_client = _build_clients(
|
||||
{TA_ARN: _trust_anchor(source_type="AWS_ACM_PCA", acm_pca_arn=PCA_ARN)},
|
||||
certificate_authorities={PCA_ARN: _ca("CUSTOM_PQC")},
|
||||
audit_config={"rolesanywhere_pqc_pca_key_algorithms": ["CUSTOM_PQC"]},
|
||||
)
|
||||
with _enter(_patched(ra_client, pca_client)):
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_trust_anchor_pqc_pki.rolesanywhere_trust_anchor_pqc_pki import (
|
||||
rolesanywhere_trust_anchor_pqc_pki,
|
||||
)
|
||||
|
||||
result = rolesanywhere_trust_anchor_pqc_pki().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert "CUSTOM_PQC" in result[0].status_extended
|
||||
assert result[0].resource_id == TA_ID
|
||||
assert result[0].resource_arn == TA_ARN
|
||||
|
||||
def test_custom_allowlist_replaces_default(self):
|
||||
ra_client, pca_client = _build_clients(
|
||||
{TA_ARN: _trust_anchor(source_type="AWS_ACM_PCA", acm_pca_arn=PCA_ARN)},
|
||||
certificate_authorities={PCA_ARN: _ca("ML_DSA_65")},
|
||||
audit_config={"rolesanywhere_pqc_pca_key_algorithms": ["ML_DSA_87"]},
|
||||
)
|
||||
with _enter(_patched(ra_client, pca_client)):
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_trust_anchor_pqc_pki.rolesanywhere_trust_anchor_pqc_pki import (
|
||||
rolesanywhere_trust_anchor_pqc_pki,
|
||||
)
|
||||
|
||||
result = rolesanywhere_trust_anchor_pqc_pki().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "ML_DSA_65" in result[0].status_extended
|
||||
assert "not post-quantum (ML-DSA)" in result[0].status_extended
|
||||
|
||||
def test_pca_backed_rsa(self):
|
||||
ra_client, pca_client = _build_clients(
|
||||
{TA_ARN: _trust_anchor(source_type="AWS_ACM_PCA", acm_pca_arn=PCA_ARN)},
|
||||
certificate_authorities={PCA_ARN: _ca("RSA_2048")},
|
||||
)
|
||||
with _enter(_patched(ra_client, pca_client)):
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_trust_anchor_pqc_pki.rolesanywhere_trust_anchor_pqc_pki import (
|
||||
rolesanywhere_trust_anchor_pqc_pki,
|
||||
)
|
||||
|
||||
result = rolesanywhere_trust_anchor_pqc_pki().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "RSA_2048" in result[0].status_extended
|
||||
|
||||
def test_pca_backed_inactive_pqc_ca(self):
|
||||
ra_client, pca_client = _build_clients(
|
||||
{TA_ARN: _trust_anchor(source_type="AWS_ACM_PCA", acm_pca_arn=PCA_ARN)},
|
||||
certificate_authorities={PCA_ARN: _ca("ML_DSA_65", status="DISABLED")},
|
||||
)
|
||||
with _enter(_patched(ra_client, pca_client)):
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_trust_anchor_pqc_pki.rolesanywhere_trust_anchor_pqc_pki import (
|
||||
rolesanywhere_trust_anchor_pqc_pki,
|
||||
)
|
||||
|
||||
result = rolesanywhere_trust_anchor_pqc_pki().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "DISABLED status" in result[0].status_extended
|
||||
|
||||
def test_pca_not_in_inventory(self):
|
||||
ra_client, pca_client = _build_clients(
|
||||
{TA_ARN: _trust_anchor(source_type="AWS_ACM_PCA", acm_pca_arn=PCA_ARN)},
|
||||
certificate_authorities={},
|
||||
)
|
||||
with _enter(_patched(ra_client, pca_client)):
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_trust_anchor_pqc_pki.rolesanywhere_trust_anchor_pqc_pki import (
|
||||
rolesanywhere_trust_anchor_pqc_pki,
|
||||
)
|
||||
|
||||
result = rolesanywhere_trust_anchor_pqc_pki().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "could not be inspected" in result[0].status_extended
|
||||
|
||||
def test_certificate_bundle_source(self):
|
||||
ra_client, pca_client = _build_clients(
|
||||
{TA_ARN: _trust_anchor(source_type="CERTIFICATE_BUNDLE")},
|
||||
)
|
||||
with _enter(_patched(ra_client, pca_client)):
|
||||
from prowler.providers.aws.services.rolesanywhere.rolesanywhere_trust_anchor_pqc_pki.rolesanywhere_trust_anchor_pqc_pki import (
|
||||
rolesanywhere_trust_anchor_pqc_pki,
|
||||
)
|
||||
|
||||
result = rolesanywhere_trust_anchor_pqc_pki().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert "CERTIFICATE_BUNDLE" in result[0].status_extended
|
||||
Reference in New Issue
Block a user