Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(acm): Improve near-expiration certificates check #4207

Merged
29 changes: 16 additions & 13 deletions docs/tutorials/configuration_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,22 @@ The following list includes all the AWS checks with configurable variables that
| `organizations_delegated_administrators` | `organizations_trusted_delegated_administrators` | List of Strings |
| `ecr_repositories_scan_vulnerabilities_in_latest_image` | `ecr_repository_vulnerability_minimum_severity` | String |
| `trustedadvisor_premium_support_plan_subscribed` | `verify_premium_support_plans` | Boolean |
| `config_recorder_all_regions_enabled` | `mute_non_default_regions` | Boolean |
| `drs_job_exist` | `mute_non_default_regions` | Boolean |
| `guardduty_is_enabled` | `mute_non_default_regions` | Boolean |
| `securityhub_enabled` | `mute_non_default_regions` | Boolean |
| `cloudtrail_threat_detection_privilege_escalation` | `threat_detection_privilege_escalation_entropy` | Integer |
| `cloudtrail_threat_detection_privilege_escalation` | `threat_detection_privilege_escalation_minutes` | Integer |
| `cloudtrail_threat_detection_privilege_escalation` | `threat_detection_privilege_escalation_actions` | List of Strings |
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_entropy` | Integer |
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_minutes` | Integer |
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_actions` | List of Strings |
| `rds_instance_backup_enabled` | `check_rds_instance_replicas` | Boolean |
| `ec2_securitygroup_allow_ingress_from_internet_to_any_port` | `ec2_allowed_interface_types` | List of Strings |
| `ec2_securitygroup_allow_ingress_from_internet_to_any_port` | `ec2_allowed_instance_owners` | List of Strings |
| `config_recorder_all_regions_enabled` | `mute_non_default_regions` | Boolean |
| `drs_job_exist` | `mute_non_default_regions` | Boolean |
| `guardduty_is_enabled` | `mute_non_default_regions` | Boolean |
| `securityhub_enabled` | `mute_non_default_regions` | Boolean |
| `cloudtrail_threat_detection_privilege_escalation` | `threat_detection_privilege_escalation_entropy` | Integer |
| `cloudtrail_threat_detection_privilege_escalation` | `threat_detection_privilege_escalation_minutes` | Integer |
| `cloudtrail_threat_detection_privilege_escalation` | `threat_detection_privilege_escalation_actions` | List of Strings |
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_entropy` | Integer |
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_minutes` | Integer |
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_actions` | List of Strings |
| `rds_instance_backup_enabled` | `check_rds_instance_replicas` | Boolean |
| `ec2_securitygroup_allow_ingress_from_internet_to_any_port` | `ec2_allowed_interface_types` | List of Strings |
| `ec2_securitygroup_allow_ingress_from_internet_to_any_port` | `ec2_allowed_instance_owners` | List of Strings |
| `acm_certificates_expiration_check` | `days_to_expire_threshold` | Integer |


## Azure

### Configurable Checks
Expand Down
6 changes: 6 additions & 0 deletions docs/tutorials/scan-unused-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ prowler <provider> --scan-unused-services

## Services that are ignored
### AWS
#### ACM
You can have certificates in ACM that is not in use by any AWS resource.
Prowler will check if every certificate is going to expire soon, if this certificate is not in use by default it is not going to be check if it is expired, is going to expire soon or it is good.

- `acm_certificates_expiration_check`

#### Athena
When you create an AWS Account, Athena will create a default primary workgroup for you.
Prowler will check if that workgroup is enabled and if it is being used by checking if there were queries in the last 45 days.
Expand Down
3 changes: 3 additions & 0 deletions prowler/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ aws:
# aws.rds_instance_backup_enabled
# Whether to check RDS instance replicas or not
check_rds_instance_replicas: False
# AWS ACM Configuration
sergargar marked this conversation as resolved.
Show resolved Hide resolved
# aws.acm_certificates_expiration_check
days_to_expire_threshold: 7

# Azure Configuration
azure:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.acm.acm_client import acm_client

DAYS_TO_EXPIRE_THRESHOLD = 7


class acm_certificates_expiration_check(Check):
def execute(self):
findings = []
for certificate in acm_client.certificates:
report = Check_Report_AWS(self.metadata())
report.region = certificate.region
if certificate.expiration_days > DAYS_TO_EXPIRE_THRESHOLD:
report.status = "PASS"
report.status_extended = f"ACM Certificate {certificate.id} for {certificate.name} expires in {certificate.expiration_days} days."
report.resource_id = certificate.id
report.resource_details = certificate.name
report.resource_arn = certificate.arn
report.resource_tags = certificate.tags
else:
report.status = "FAIL"
if certificate.expiration_days < 0:
report.status_extended = f"ACM Certificate {certificate.id} for {certificate.name} has expired ({abs(certificate.expiration_days)} days ago)."
if certificate.in_use or acm_client.provider.scan_unused_services:
report = Check_Report_AWS(self.metadata())
report.region = certificate.region
if certificate.expiration_days > acm_client.audit_config.get(
"days_to_expire_threshold", 7
):
report.status = "PASS"
report.status_extended = f"ACM Certificate {certificate.id} for {certificate.name} expires in {certificate.expiration_days} days."
report.resource_id = certificate.id
report.resource_details = certificate.name
report.resource_arn = certificate.arn
report.resource_tags = certificate.tags
else:
report.status_extended = f"ACM Certificate {certificate.id} for {certificate.name} is about to expire in {certificate.expiration_days} days."
report.status = "FAIL"
if certificate.expiration_days < 0:
report.status_extended = f"ACM Certificate {certificate.id} for {certificate.name} has expired ({abs(certificate.expiration_days)} days ago)."
report.check_metadata.Severity = "high"
else:
report.status_extended = f"ACM Certificate {certificate.id} for {certificate.name} is about to expire in {certificate.expiration_days} days."
report.check_metadata.Severity = "medium"

report.resource_id = certificate.id
report.resource_details = certificate.name
report.resource_arn = certificate.arn
report.resource_tags = certificate.tags
report.resource_id = certificate.id
report.resource_details = certificate.name
report.resource_arn = certificate.arn
report.resource_tags = certificate.tags

findings.append(report)
findings.append(report)
return findings
2 changes: 2 additions & 0 deletions prowler/providers/aws/services/acm/acm_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def __list_certificates__(self, regional_client):
id=certificate["CertificateArn"].split("/")[-1],
type=certificate["Type"],
expiration_days=certificate_expiration_time,
in_use=certificate["InUse"],
transparency_logging=False,
region=regional_client.region,
)
Expand Down Expand Up @@ -99,5 +100,6 @@ class Certificate(BaseModel):
type: str
tags: Optional[list] = []
expiration_days: int
in_use: bool
transparency_logging: Optional[bool]
region: str
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def test_acm_certificate_expirated(self):
certificate_name = "test-certificate.com"
certificate_type = "AMAZON_ISSUED"
expiration_days = 5
in_use = True

acm_client = mock.MagicMock
acm_client.certificates = [
Expand All @@ -42,11 +43,14 @@ def test_acm_certificate_expirated(self):
name=certificate_name,
type=certificate_type,
expiration_days=expiration_days,
in_use=in_use,
transparency_logging=True,
region=AWS_REGION,
)
]

acm_client.audit_config = {"days_to_expire_threshold": 7}

with mock.patch(
"prowler.providers.aws.services.acm.acm_service.ACM",
new=acm_client,
Expand Down Expand Up @@ -76,6 +80,7 @@ def test_acm_certificate_expirated_long_time(self):
certificate_name = "test-certificate.com"
certificate_type = "AMAZON_ISSUED"
expiration_days = -400
in_use = True

acm_client = mock.MagicMock
acm_client.certificates = [
Expand All @@ -85,16 +90,18 @@ def test_acm_certificate_expirated_long_time(self):
name=certificate_name,
type=certificate_type,
expiration_days=expiration_days,
in_use=in_use,
transparency_logging=True,
region=AWS_REGION,
)
]

acm_client.audit_config = {"days_to_expire_threshold": 7}

with mock.patch(
"prowler.providers.aws.services.acm.acm_service.ACM",
new=acm_client,
):
# Test Check
from prowler.providers.aws.services.acm.acm_certificates_expiration_check.acm_certificates_expiration_check import (
acm_certificates_expiration_check,
)
Expand All @@ -119,6 +126,7 @@ def test_acm_certificate_not_expirated(self):
certificate_name = "test-certificate.com"
certificate_type = "AMAZON_ISSUED"
expiration_days = 365
in_use = True

acm_client = mock.MagicMock
acm_client.certificates = [
Expand All @@ -128,16 +136,18 @@ def test_acm_certificate_not_expirated(self):
name=certificate_name,
type=certificate_type,
expiration_days=expiration_days,
in_use=in_use,
transparency_logging=True,
region=AWS_REGION,
)
]

acm_client.audit_config = {"days_to_expire_threshold": 7}

with mock.patch(
"prowler.providers.aws.services.acm.acm_service.ACM",
new=acm_client,
):
# Test Check
from prowler.providers.aws.services.acm.acm_certificates_expiration_check.acm_certificates_expiration_check import (
acm_certificates_expiration_check,
)
Expand All @@ -155,3 +165,90 @@ def test_acm_certificate_not_expirated(self):
assert result[0].resource_arn == certificate_arn
assert result[0].region == AWS_REGION
assert result[0].resource_tags == []

def test_acm_certificate_not_in_use(self):
certificate_id = str(uuid.uuid4())
certificate_arn = f"arn:aws:acm:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:certificate/{certificate_id}"
certificate_name = "test-certificate.com"
certificate_type = "AMAZON_ISSUED"
expiration_days = 365
in_use = False

acm_client = mock.MagicMock
acm_client.certificates = [
Certificate(
arn=certificate_arn,
id=certificate_id,
name=certificate_name,
type=certificate_type,
expiration_days=expiration_days,
in_use=in_use,
transparency_logging=True,
region=AWS_REGION,
)
]

acm_client.audit_config = {"days_to_expire_threshold": 7}

acm_client.provider = mock.MagicMock(scan_unused_services=False)

with mock.patch(
"prowler.providers.aws.services.acm.acm_service.ACM",
new=acm_client,
):
from prowler.providers.aws.services.acm.acm_certificates_expiration_check.acm_certificates_expiration_check import (
acm_certificates_expiration_check,
)

check = acm_certificates_expiration_check()
result = check.execute()

assert len(result) == 0

def test_acm_certificate_not_in_use_expired_scan_unused_services(self):
certificate_id = str(uuid.uuid4())
certificate_arn = f"arn:aws:acm:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:certificate/{certificate_id}"
certificate_name = "test-certificate.com"
certificate_type = "AMAZON_ISSUED"
expiration_days = -400
in_use = False

acm_client = mock.MagicMock
acm_client.certificates = [
Certificate(
arn=certificate_arn,
id=certificate_id,
name=certificate_name,
type=certificate_type,
expiration_days=expiration_days,
in_use=in_use,
transparency_logging=True,
region=AWS_REGION,
)
]

acm_client.audit_config = {"days_to_expire_threshold": 7}

acm_client.provider = mock.MagicMock(scan_unused_services=True)

with mock.patch(
"prowler.providers.aws.services.acm.acm_service.ACM",
new=acm_client,
):
from prowler.providers.aws.services.acm.acm_certificates_expiration_check.acm_certificates_expiration_check import (
acm_certificates_expiration_check,
)

check = acm_certificates_expiration_check()
result = check.execute()

assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"ACM Certificate {certificate_id} for {certificate_name} has expired ({abs(expiration_days)} days ago)."
)
assert result[0].resource_id == certificate_id
assert result[0].resource_arn == certificate_arn
assert result[0].region == AWS_REGION
assert result[0].resource_tags == []
Loading