From f3863e9f34040ce9272aba3f9a2f7de448620d91 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Fri, 20 Sep 2024 17:48:51 +0200 Subject: [PATCH] fix(gcp): solve errors in GCP services (#5123) Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com> --- .../apikeys_api_restrictions_configured.py | 4 +- .../gcp/services/compute/compute_service.py | 29 +- .../providers/gcp/services/dns/dns_service.py | 5 +- .../kms_key_rotation_enabled.py | 44 +- .../providers/gcp/services/kms/kms_service.py | 4 + tests/providers/gcp/gcp_fixtures.py | 1 + ...pikeys_api_restrictions_configured_test.py | 4 +- .../kms_key_rotation_enabled_test.py | 572 ++++++++++++++++++ 8 files changed, 632 insertions(+), 31 deletions(-) create mode 100644 tests/providers/gcp/services/kms/kms_key_rotation_enabled/kms_key_rotation_enabled_test.py diff --git a/prowler/providers/gcp/services/apikeys/apikeys_api_restrictions_configured/apikeys_api_restrictions_configured.py b/prowler/providers/gcp/services/apikeys/apikeys_api_restrictions_configured/apikeys_api_restrictions_configured.py index b354996c08..e2f8442992 100644 --- a/prowler/providers/gcp/services/apikeys/apikeys_api_restrictions_configured/apikeys_api_restrictions_configured.py +++ b/prowler/providers/gcp/services/apikeys/apikeys_api_restrictions_configured/apikeys_api_restrictions_configured.py @@ -16,12 +16,12 @@ class apikeys_api_restrictions_configured(Check): if key.restrictions == {} or any( [ target.get("service") == "cloudapis.googleapis.com" - for target in key.restrictions["apiTargets"] + for target in key.restrictions.get("apiTargets", []) ] ): report.status = "FAIL" report.status_extended = ( - f"API key {key.name} doens't have restrictions configured." + f"API key {key.name} does not have restrictions configured." ) findings.append(report) diff --git a/prowler/providers/gcp/services/compute/compute_service.py b/prowler/providers/gcp/services/compute/compute_service.py index 2bddce8e98..e7ac14b978 100644 --- a/prowler/providers/gcp/services/compute/compute_service.py +++ b/prowler/providers/gcp/services/compute/compute_service.py @@ -282,20 +282,23 @@ class Compute(GCPService): def __describe_backend_service__(self): for balancer in self.load_balancers: - try: - response = ( - self.client.backendServices() - .get( - project=balancer.project_id, - backendService=balancer.service.split("/")[-1], + if balancer.service: + try: + response = ( + self.client.backendServices() + .get( + project=balancer.project_id, + backendService=balancer.service.split("/")[-1], + ) + .execute() + ) + balancer.logging = response.get("logConfig", {}).get( + "enable", False + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) - .execute() - ) - balancer.logging = response.get("logConfig", {}).get("enable", False) - except Exception as error: - logger.error( - f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) class Instance(BaseModel): diff --git a/prowler/providers/gcp/services/dns/dns_service.py b/prowler/providers/gcp/services/dns/dns_service.py index 7c58f95532..7a9190a88b 100644 --- a/prowler/providers/gcp/services/dns/dns_service.py +++ b/prowler/providers/gcp/services/dns/dns_service.py @@ -24,8 +24,9 @@ class DNS(GCPService): ManagedZone( name=managed_zone["name"], id=managed_zone["id"], - dnssec=managed_zone["dnssecConfig"]["state"] == "on", - key_specs=managed_zone["dnssecConfig"][ + dnssec=managed_zone.get("dnssecConfig", {})["state"] + == "on", + key_specs=managed_zone.get("dnssecConfig", {})[ "defaultKeySpecs" ], project_id=project_id, diff --git a/prowler/providers/gcp/services/kms/kms_key_rotation_enabled/kms_key_rotation_enabled.py b/prowler/providers/gcp/services/kms/kms_key_rotation_enabled/kms_key_rotation_enabled.py index df9a81ebf2..44128ce68f 100644 --- a/prowler/providers/gcp/services/kms/kms_key_rotation_enabled/kms_key_rotation_enabled.py +++ b/prowler/providers/gcp/services/kms/kms_key_rotation_enabled/kms_key_rotation_enabled.py @@ -1,3 +1,5 @@ +import datetime + from prowler.lib.check.models import Check, Check_Report_GCP from prowler.providers.gcp.services.kms.kms_client import kms_client @@ -8,21 +10,39 @@ class kms_key_rotation_enabled(Check): for key in kms_client.crypto_keys: report = Check_Report_GCP(self.metadata()) report.project_id = key.project_id - report.resource_id = key.name + report.resource_id = key.id report.resource_name = key.name report.location = key.location - report.status = "FAIL" - report.status_extended = ( - f"Key {key.name} is not rotated every 90 days or less." - ) - if key.rotation_period: - if ( - int(key.rotation_period[:-1]) // (24 * 3600) <= 90 - ): # Convert seconds to days and check if less or equal than 90 - report.status = "PASS" - report.status_extended = ( - f"Key {key.name} is rotated every 90 days or less." + now = datetime.datetime.now() + condition_next_rotation_time = False + if key.next_rotation_time: + try: + next_rotation_time = datetime.datetime.strptime( + key.next_rotation_time, "%Y-%m-%dT%H:%M:%S.%fZ" ) + except ValueError: + next_rotation_time = datetime.datetime.strptime( + key.next_rotation_time, "%Y-%m-%dT%H:%M:%SZ" + ) + condition_next_rotation_time = ( + abs((next_rotation_time - now).days) <= 90 + ) + condition_rotation_period = False + if key.rotation_period: + condition_rotation_period = ( + int(key.rotation_period[:-1]) // (24 * 3600) <= 90 + ) + if condition_rotation_period and condition_next_rotation_time: + report.status = "PASS" + report.status_extended = f"Key {key.name} is rotated every 90 days or less and the next rotation time is in less than 90 days." + else: + report.status = "FAIL" + if condition_rotation_period: + report.status_extended = f"Key {key.name} is rotated every 90 days or less but the next rotation time is in more than 90 days." + elif condition_next_rotation_time: + report.status_extended = f"Key {key.name} is not rotated every 90 days or less but the next rotation time is in less than 90 days." + else: + report.status_extended = f"Key {key.name} is not rotated every 90 days or less and the next rotation time is in more than 90 days." findings.append(report) return findings diff --git a/prowler/providers/gcp/services/kms/kms_service.py b/prowler/providers/gcp/services/kms/kms_service.py index f5c30ba3f2..691c47731a 100644 --- a/prowler/providers/gcp/services/kms/kms_service.py +++ b/prowler/providers/gcp/services/kms/kms_service.py @@ -87,9 +87,11 @@ class KMS(GCPService): for key in response.get("cryptoKeys", []): self.crypto_keys.append( CriptoKey( + id=key["name"], name=key["name"].split("/")[-1], location=key["name"].split("/")[3], rotation_period=key.get("rotationPeriod"), + next_rotation_time=key.get("nextRotationTime"), key_ring=ring.name, project_id=ring.project_id, ) @@ -138,9 +140,11 @@ class KeyRing(BaseModel): class CriptoKey(BaseModel): + id: str name: str location: str rotation_period: Optional[str] + next_rotation_time: Optional[str] key_ring: str members: list = [] project_id: str diff --git a/tests/providers/gcp/gcp_fixtures.py b/tests/providers/gcp/gcp_fixtures.py index fab6d41949..95d7c3f93a 100644 --- a/tests/providers/gcp/gcp_fixtures.py +++ b/tests/providers/gcp/gcp_fixtures.py @@ -6,6 +6,7 @@ from mock import MagicMock from prowler.providers.gcp.lib.audit_info.models import GCP_Audit_Info GCP_PROJECT_ID = "123456789012" +GCP_US_CENTER1_LOCATION = "us-central1" # Mocked Azure Audit Info diff --git a/tests/providers/gcp/services/apikeys/apikeys_api_restrictions_configured/apikeys_api_restrictions_configured_test.py b/tests/providers/gcp/services/apikeys/apikeys_api_restrictions_configured/apikeys_api_restrictions_configured_test.py index 45cca513c1..13c6e95f62 100644 --- a/tests/providers/gcp/services/apikeys/apikeys_api_restrictions_configured/apikeys_api_restrictions_configured_test.py +++ b/tests/providers/gcp/services/apikeys/apikeys_api_restrictions_configured/apikeys_api_restrictions_configured_test.py @@ -91,7 +91,7 @@ class Test_apikeys_api_restrictions_configured: assert len(result) == 1 assert result[0].status == "FAIL" assert search( - f"API key {key.name} doens't have restrictions configured.", + f"API key {key.name} does not have restrictions configured.", result[0].status_extended, ) assert result[0].resource_id == key.id @@ -132,7 +132,7 @@ class Test_apikeys_api_restrictions_configured: assert len(result) == 1 assert result[0].status == "FAIL" assert search( - f"API key {key.name} doens't have restrictions configured.", + f"API key {key.name} does not have restrictions configured.", result[0].status_extended, ) assert result[0].resource_id == key.id diff --git a/tests/providers/gcp/services/kms/kms_key_rotation_enabled/kms_key_rotation_enabled_test.py b/tests/providers/gcp/services/kms/kms_key_rotation_enabled/kms_key_rotation_enabled_test.py new file mode 100644 index 0000000000..db04aab822 --- /dev/null +++ b/tests/providers/gcp/services/kms/kms_key_rotation_enabled/kms_key_rotation_enabled_test.py @@ -0,0 +1,572 @@ +from unittest import mock + +from tests.providers.gcp.gcp_fixtures import GCP_PROJECT_ID, GCP_US_CENTER1_LOCATION + + +class Test_kms_key_rotation_enabled: + def test_kms_no_key(self): + kms_client = mock.MagicMock + + with mock.patch( + "prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled.kms_client", + new=kms_client, + ): + from prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled import ( + kms_key_rotation_enabled, + ) + + kms_client.project_ids = [GCP_PROJECT_ID] + kms_client.region = GCP_US_CENTER1_LOCATION + kms_client.crypto_keys = [] + + check = kms_key_rotation_enabled() + result = check.execute() + assert len(result) == 0 + + def test_kms_key_no_next_rotation_time_and_no_rotation_period(self): + kms_client = mock.MagicMock + + with mock.patch( + "prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled.kms_client", + new=kms_client, + ): + from prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled import ( + kms_key_rotation_enabled, + ) + from prowler.providers.gcp.services.kms.kms_service import ( + CriptoKey, + KeyLocation, + KeyRing, + ) + + kms_client.project_ids = [GCP_PROJECT_ID] + kms_client.region = GCP_US_CENTER1_LOCATION + + keyring = KeyRing( + name="projects/123/locations/us-central1/keyRings/keyring1", + project_id=GCP_PROJECT_ID, + ) + + keylocation = KeyLocation( + name=GCP_US_CENTER1_LOCATION, + project_id=GCP_PROJECT_ID, + ) + + kms_client.crypto_keys = [ + CriptoKey( + name="key1", + id="projects/123/locations/us-central1/keyRings/keyring1/cryptoKeys/key1", + project_id=GCP_PROJECT_ID, + key_ring=keyring.name, + location=keylocation.name, + members=["user:jane@example.com"], + ) + ] + + check = kms_key_rotation_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Key {kms_client.crypto_keys[0].name} is not rotated every 90 days or less and the next rotation time is in more than 90 days." + ) + assert result[0].resource_id == kms_client.crypto_keys[0].id + assert result[0].resource_name == kms_client.crypto_keys[0].name + assert result[0].location == kms_client.crypto_keys[0].location + assert result[0].project_id == kms_client.crypto_keys[0].project_id + + def test_kms_key_no_next_rotation_time_and_big_rotation_period(self): + kms_client = mock.MagicMock + + with mock.patch( + "prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled.kms_client", + new=kms_client, + ): + from prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled import ( + kms_key_rotation_enabled, + ) + from prowler.providers.gcp.services.kms.kms_service import ( + CriptoKey, + KeyLocation, + KeyRing, + ) + + kms_client.project_ids = [GCP_PROJECT_ID] + kms_client.region = GCP_US_CENTER1_LOCATION + + keyring = KeyRing( + name="projects/123/locations/us-central1/keyRings/keyring1", + project_id=GCP_PROJECT_ID, + ) + + keylocation = KeyLocation( + name=GCP_US_CENTER1_LOCATION, + project_id=GCP_PROJECT_ID, + ) + + kms_client.crypto_keys = [ + CriptoKey( + name="key1", + id="projects/123/locations/us-central1/keyRings/keyring1/cryptoKeys/key1", + project_id=GCP_PROJECT_ID, + key_ring=keyring.name, + location=keylocation.name, + rotation_period="8776000s", + members=["user:jane@example.com"], + ) + ] + + check = kms_key_rotation_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Key {kms_client.crypto_keys[0].name} is not rotated every 90 days or less and the next rotation time is in more than 90 days." + ) + assert result[0].resource_id == kms_client.crypto_keys[0].id + assert result[0].resource_name == kms_client.crypto_keys[0].name + assert result[0].location == kms_client.crypto_keys[0].location + assert result[0].project_id == kms_client.crypto_keys[0].project_id + + def test_kms_key_no_next_rotation_time_and_appropriate_rotation_period(self): + kms_client = mock.MagicMock + + with mock.patch( + "prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled.kms_client", + new=kms_client, + ): + from prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled import ( + kms_key_rotation_enabled, + ) + from prowler.providers.gcp.services.kms.kms_service import ( + CriptoKey, + KeyLocation, + KeyRing, + ) + + kms_client.project_ids = [GCP_PROJECT_ID] + kms_client.region = GCP_US_CENTER1_LOCATION + + keyring = KeyRing( + name="projects/123/locations/us-central1/keyRings/keyring1", + project_id=GCP_PROJECT_ID, + ) + + keylocation = KeyLocation( + name=GCP_US_CENTER1_LOCATION, + project_id=GCP_PROJECT_ID, + ) + + kms_client.crypto_keys = [ + CriptoKey( + name="key1", + id="projects/123/locations/us-central1/keyRings/keyring1/cryptoKeys/key1", + project_id=GCP_PROJECT_ID, + key_ring=keyring.name, + location=keylocation.name, + rotation_period="7776000s", + members=["user:jane@example.com"], + ) + ] + + check = kms_key_rotation_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Key {kms_client.crypto_keys[0].name} is rotated every 90 days or less but the next rotation time is in more than 90 days." + ) + assert result[0].resource_id == kms_client.crypto_keys[0].id + assert result[0].resource_name == kms_client.crypto_keys[0].name + assert result[0].location == kms_client.crypto_keys[0].location + assert result[0].project_id == kms_client.crypto_keys[0].project_id + + def test_kms_key_no_rotation_period_and_big_next_rotation_time(self): + kms_client = mock.MagicMock + + with mock.patch( + "prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled.kms_client", + new=kms_client, + ): + from prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled import ( + kms_key_rotation_enabled, + ) + from prowler.providers.gcp.services.kms.kms_service import ( + CriptoKey, + KeyLocation, + KeyRing, + ) + + kms_client.project_ids = [GCP_PROJECT_ID] + kms_client.region = GCP_US_CENTER1_LOCATION + + keyring = KeyRing( + name="projects/123/locations/us-central1/keyRings/keyring1", + project_id=GCP_PROJECT_ID, + ) + + keylocation = KeyLocation( + name=GCP_US_CENTER1_LOCATION, + project_id=GCP_PROJECT_ID, + ) + + kms_client.crypto_keys = [ + CriptoKey( + name="key1", + id="projects/123/locations/us-central1/keyRings/keyring1/cryptoKeys/key1", + project_id=GCP_PROJECT_ID, + key_ring=keyring.name, + location=keylocation.name, + next_rotation_time="2025-09-01T00:00:00Z", + members=["user:jane@example.com"], + ) + ] + + check = kms_key_rotation_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Key {kms_client.crypto_keys[0].name} is not rotated every 90 days or less and the next rotation time is in more than 90 days." + ) + assert result[0].resource_id == kms_client.crypto_keys[0].id + assert result[0].resource_name == kms_client.crypto_keys[0].name + assert result[0].location == kms_client.crypto_keys[0].location + assert result[0].project_id == kms_client.crypto_keys[0].project_id + + def test_kms_key_no_rotation_period_and_appropriate_next_rotation_time(self): + kms_client = mock.MagicMock + + with mock.patch( + "prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled.kms_client", + new=kms_client, + ): + from prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled import ( + kms_key_rotation_enabled, + ) + from prowler.providers.gcp.services.kms.kms_service import ( + CriptoKey, + KeyLocation, + KeyRing, + ) + + kms_client.project_ids = [GCP_PROJECT_ID] + kms_client.region = GCP_US_CENTER1_LOCATION + + keyring = KeyRing( + name="projects/123/locations/us-central1/keyRings/keyring1", + project_id=GCP_PROJECT_ID, + ) + + keylocation = KeyLocation( + name=GCP_US_CENTER1_LOCATION, + project_id=GCP_PROJECT_ID, + ) + + kms_client.crypto_keys = [ + CriptoKey( + name="key1", + id="projects/123/locations/us-central1/keyRings/keyring1/cryptoKeys/key1", + project_id=GCP_PROJECT_ID, + key_ring=keyring.name, + location=keylocation.name, + next_rotation_time="2024-09-01T00:00:00Z", + members=["user:jane@example.com"], + ) + ] + + check = kms_key_rotation_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Key {kms_client.crypto_keys[0].name} is not rotated every 90 days or less but the next rotation time is in less than 90 days." + ) + assert result[0].resource_id == kms_client.crypto_keys[0].id + assert result[0].resource_name == kms_client.crypto_keys[0].name + assert result[0].location == kms_client.crypto_keys[0].location + assert result[0].project_id == kms_client.crypto_keys[0].project_id + + def test_kms_key_rotation_period_greater_90_days_and_big_next_rotation_time(self): + kms_client = mock.MagicMock + + with mock.patch( + "prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled.kms_client", + new=kms_client, + ): + from prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled import ( + kms_key_rotation_enabled, + ) + from prowler.providers.gcp.services.kms.kms_service import ( + CriptoKey, + KeyLocation, + KeyRing, + ) + + kms_client.project_ids = [GCP_PROJECT_ID] + kms_client.region = GCP_US_CENTER1_LOCATION + + keyring = KeyRing( + name="projects/123/locations/us-central1/keyRings/keyring1", + project_id=GCP_PROJECT_ID, + ) + + keylocation = KeyLocation( + name=GCP_US_CENTER1_LOCATION, + project_id=GCP_PROJECT_ID, + ) + + kms_client.crypto_keys = [ + CriptoKey( + name="key1", + id="projects/123/locations/us-central1/keyRings/keyring1/cryptoKeys/key1", + project_id=GCP_PROJECT_ID, + rotation_period="8776000s", + next_rotation_time="2025-09-01T00:00:00Z", + key_ring=keyring.name, + location=keylocation.name, + members=["user:jane@example.com"], + ) + ] + + check = kms_key_rotation_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Key {kms_client.crypto_keys[0].name} is not rotated every 90 days or less and the next rotation time is in more than 90 days." + ) + assert result[0].resource_id == kms_client.crypto_keys[0].id + assert result[0].resource_name == kms_client.crypto_keys[0].name + assert result[0].location == kms_client.crypto_keys[0].location + assert result[0].project_id == kms_client.crypto_keys[0].project_id + + def test_kms_key_rotation_period_greater_90_days_and_appropriate_next_rotation_time( + self, + ): + kms_client = mock.MagicMock + + with mock.patch( + "prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled.kms_client", + new=kms_client, + ): + from prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled import ( + kms_key_rotation_enabled, + ) + from prowler.providers.gcp.services.kms.kms_service import ( + CriptoKey, + KeyLocation, + KeyRing, + ) + + kms_client.project_ids = [GCP_PROJECT_ID] + kms_client.region = GCP_US_CENTER1_LOCATION + + keyring = KeyRing( + name="projects/123/locations/us-central1/keyRings/keyring1", + project_id=GCP_PROJECT_ID, + ) + + keylocation = KeyLocation( + name=GCP_US_CENTER1_LOCATION, + project_id=GCP_PROJECT_ID, + ) + + kms_client.crypto_keys = [ + CriptoKey( + name="key1", + id="projects/123/locations/us-central1/keyRings/keyring1/cryptoKeys/key1", + project_id=GCP_PROJECT_ID, + rotation_period="8776000s", + next_rotation_time="2024-09-01T00:00:00Z", + key_ring=keyring.name, + location=keylocation.name, + members=["user:jane@example.com"], + ) + ] + + check = kms_key_rotation_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Key {kms_client.crypto_keys[0].name} is not rotated every 90 days or less but the next rotation time is in less than 90 days." + ) + assert result[0].resource_id == kms_client.crypto_keys[0].id + assert result[0].resource_name == kms_client.crypto_keys[0].name + assert result[0].location == kms_client.crypto_keys[0].location + assert result[0].project_id == kms_client.crypto_keys[0].project_id + + def test_kms_key_rotation_period_less_90_days_and_big_next_rotation_time(self): + kms_client = mock.MagicMock + + with mock.patch( + "prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled.kms_client", + new=kms_client, + ): + from prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled import ( + kms_key_rotation_enabled, + ) + from prowler.providers.gcp.services.kms.kms_service import ( + CriptoKey, + KeyLocation, + KeyRing, + ) + + kms_client.project_ids = [GCP_PROJECT_ID] + kms_client.region = GCP_US_CENTER1_LOCATION + + keyring = KeyRing( + name="projects/123/locations/us-central1/keyRings/keyring1", + project_id=GCP_PROJECT_ID, + ) + + keylocation = KeyLocation( + name=GCP_US_CENTER1_LOCATION, + project_id=GCP_PROJECT_ID, + ) + + kms_client.crypto_keys = [ + CriptoKey( + name="key1", + id="projects/123/locations/us-central1/keyRings/keyring1/cryptoKeys/key1", + project_id=GCP_PROJECT_ID, + rotation_period="7776000s", + next_rotation_time="2025-09-01T00:00:00Z", + key_ring=keyring.name, + location=keylocation.name, + members=["user:jane@example.com"], + ) + ] + + check = kms_key_rotation_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Key {kms_client.crypto_keys[0].name} is rotated every 90 days or less but the next rotation time is in more than 90 days." + ) + assert result[0].resource_id == kms_client.crypto_keys[0].id + assert result[0].resource_name == kms_client.crypto_keys[0].name + assert result[0].location == kms_client.crypto_keys[0].location + assert result[0].project_id == kms_client.crypto_keys[0].project_id + + def test_kms_key_rotation_period_less_90_days_and_appropriate_next_rotation_time( + self, + ): + kms_client = mock.MagicMock + + with mock.patch( + "prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled.kms_client", + new=kms_client, + ): + from prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled import ( + kms_key_rotation_enabled, + ) + from prowler.providers.gcp.services.kms.kms_service import ( + CriptoKey, + KeyLocation, + KeyRing, + ) + + kms_client.project_ids = [GCP_PROJECT_ID] + kms_client.region = GCP_US_CENTER1_LOCATION + + keyring = KeyRing( + name="projects/123/locations/us-central1/keyRings/keyring1", + project_id=GCP_PROJECT_ID, + ) + + keylocation = KeyLocation( + name=GCP_US_CENTER1_LOCATION, + project_id=GCP_PROJECT_ID, + ) + + kms_client.crypto_keys = [ + CriptoKey( + name="key1", + id="projects/123/locations/us-central1/keyRings/keyring1/cryptoKeys/key1", + project_id=GCP_PROJECT_ID, + rotation_period="7776000s", + next_rotation_time="2024-09-01T00:00:00Z", + key_ring=keyring.name, + location=keylocation.name, + members=["user:jane@example.com"], + ) + ] + + check = kms_key_rotation_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Key {kms_client.crypto_keys[0].name} is rotated every 90 days or less and the next rotation time is in less than 90 days." + ) + assert result[0].resource_id == kms_client.crypto_keys[0].id + assert result[0].resource_name == kms_client.crypto_keys[0].name + assert result[0].location == kms_client.crypto_keys[0].location + assert result[0].project_id == kms_client.crypto_keys[0].project_id + + def test_kms_key_rotation_with_fractional_seconds(self): + kms_client = mock.MagicMock + + with mock.patch( + "prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled.kms_client", + new=kms_client, + ): + from prowler.providers.gcp.services.kms.kms_key_rotation_enabled.kms_key_rotation_enabled import ( + kms_key_rotation_enabled, + ) + from prowler.providers.gcp.services.kms.kms_service import ( + CriptoKey, + KeyLocation, + KeyRing, + ) + + kms_client.project_ids = [GCP_PROJECT_ID] + kms_client.region = GCP_US_CENTER1_LOCATION + + keyring = KeyRing( + name="projects/123/locations/us-central1/keyRings/keyring1", + project_id=GCP_PROJECT_ID, + ) + + keylocation = KeyLocation( + name=GCP_US_CENTER1_LOCATION, + project_id=GCP_PROJECT_ID, + ) + + kms_client.crypto_keys = [ + CriptoKey( + name="key1", + id="projects/123/locations/us-central1/keyRings/keyring1/cryptoKeys/key1", + project_id=GCP_PROJECT_ID, + rotation_period="7776000s", + next_rotation_time="2025-07-06T22:00:00.561275Z", + key_ring=keyring.name, + location=keylocation.name, + members=["user:jane@example.com"], + ) + ] + + check = kms_key_rotation_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Key {kms_client.crypto_keys[0].name} is rotated every 90 days or less but the next rotation time is in more than 90 days." + ) + assert result[0].resource_id == kms_client.crypto_keys[0].id + assert result[0].resource_name == kms_client.crypto_keys[0].name + assert result[0].location == kms_client.crypto_keys[0].location + assert result[0].project_id == kms_client.crypto_keys[0].project_id