From 68f0916ce4bdeaf26c4a40759e4fb1b17d93ffd8 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Thu, 25 Jul 2024 11:21:36 +0200 Subject: [PATCH] test(iam): Add remaining GCP tests for IAM checks (#4519) --- ...am_sa_no_administrative_privileges_test.py | 446 ++++++++++++++++++ .../iam_sa_no_user_managed_keys_test.py | 236 +++++++++ ...sa_user_managed_key_rotate_90_days_test.py | 174 +++++++ 3 files changed, 856 insertions(+) create mode 100644 tests/providers/gcp/services/iam/iam_sa_no_administrative_privileges/iam_sa_no_administrative_privileges_test.py create mode 100644 tests/providers/gcp/services/iam/iam_sa_no_user_managed_keys/iam_sa_no_user_managed_keys_test.py create mode 100644 tests/providers/gcp/services/iam/iam_sa_user_managed_key_rotate_90_days/iam_sa_user_managed_key_rotate_90_days_test.py diff --git a/tests/providers/gcp/services/iam/iam_sa_no_administrative_privileges/iam_sa_no_administrative_privileges_test.py b/tests/providers/gcp/services/iam/iam_sa_no_administrative_privileges/iam_sa_no_administrative_privileges_test.py new file mode 100644 index 0000000000..6cbc34c5fe --- /dev/null +++ b/tests/providers/gcp/services/iam/iam_sa_no_administrative_privileges/iam_sa_no_administrative_privileges_test.py @@ -0,0 +1,446 @@ +from unittest import mock + +from tests.providers.gcp.gcp_fixtures import ( + GCP_PROJECT_ID, + GCP_US_CENTER1_LOCATION, + set_mocked_gcp_provider, +) + + +class Test_iam_sa_no_administrative_privileges: + def test_iam_no_sa(self): + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges import ( + iam_sa_no_administrative_privileges, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + iam_client.service_accounts = [] + + check = iam_sa_no_administrative_privileges() + result = check.execute() + assert len(result) == 0 + + def test_iam_sa_no_bindings(self): + cloudresourcemanager_client = mock.MagicMock + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.cloudresourcemanager_client", + new=cloudresourcemanager_client, + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges import ( + iam_sa_no_administrative_privileges, + ) + from prowler.providers.gcp.services.iam.iam_service import ServiceAccount + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[], + project_id=GCP_PROJECT_ID, + ) + ] + + cloudresourcemanager_client.bindings = [] + cloudresourcemanager_client.project_ids = [GCP_PROJECT_ID] + cloudresourcemanager_client.region = GCP_US_CENTER1_LOCATION + + check = iam_sa_no_administrative_privileges() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Account {iam_client.service_accounts[0].email} has no administrative privileges." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].name + + def test_iam_sa_binding_no_match_email(self): + cloudresourcemanager_client = mock.MagicMock + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.cloudresourcemanager_client", + new=cloudresourcemanager_client, + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.cloudresourcemanager.cloudresourcemanager_service import ( + Binding, + ) + from prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges import ( + iam_sa_no_administrative_privileges, + ) + from prowler.providers.gcp.services.iam.iam_service import ServiceAccount + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[], + project_id=GCP_PROJECT_ID, + ) + ] + + cloudresourcemanager_client.project_ids = [GCP_PROJECT_ID] + cloudresourcemanager_client.region = GCP_US_CENTER1_LOCATION + + cloudresourcemanager_client.bindings = [ + Binding( + role="roles/admin", + members=[ + "serviceAccount:not-my-service-account@my-project.iam.gserviceaccount.com" + ], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_no_administrative_privileges() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Account {iam_client.service_accounts[0].email} has no administrative privileges." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].name + + def test_iam_sa_viewer_role_binding(self): + cloudresourcemanager_client = mock.MagicMock + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.cloudresourcemanager_client", + new=cloudresourcemanager_client, + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.cloudresourcemanager.cloudresourcemanager_service import ( + Binding, + ) + from prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges import ( + iam_sa_no_administrative_privileges, + ) + from prowler.providers.gcp.services.iam.iam_service import ServiceAccount + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[], + project_id=GCP_PROJECT_ID, + ) + ] + + cloudresourcemanager_client.project_ids = [GCP_PROJECT_ID] + cloudresourcemanager_client.region = GCP_US_CENTER1_LOCATION + + cloudresourcemanager_client.bindings = [ + Binding( + role="roles/viewer", + members=[ + "serviceAccount:my-service-account@my-project.iam.gserviceaccount.com" + ], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_no_administrative_privileges() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Account {iam_client.service_accounts[0].email} has no administrative privileges." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].name + + def test_iam_sa_admin_role_binding(self): + cloudresourcemanager_client = mock.MagicMock + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.cloudresourcemanager_client", + new=cloudresourcemanager_client, + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.cloudresourcemanager.cloudresourcemanager_service import ( + Binding, + ) + from prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges import ( + iam_sa_no_administrative_privileges, + ) + from prowler.providers.gcp.services.iam.iam_service import ServiceAccount + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[], + project_id=GCP_PROJECT_ID, + ) + ] + + cloudresourcemanager_client.project_ids = [GCP_PROJECT_ID] + cloudresourcemanager_client.region = GCP_US_CENTER1_LOCATION + + cloudresourcemanager_client.bindings = [ + Binding( + role="roles/admin", + members=[ + "serviceAccount:my-service-account@my-project.iam.gserviceaccount.com" + ], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_no_administrative_privileges() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Account {iam_client.service_accounts[0].email} has administrative privileges with {cloudresourcemanager_client.bindings[0].role}." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].name + + def test_iam_sa_owner_role_binding(self): + cloudresourcemanager_client = mock.MagicMock + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.cloudresourcemanager_client", + new=cloudresourcemanager_client, + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.cloudresourcemanager.cloudresourcemanager_service import ( + Binding, + ) + from prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges import ( + iam_sa_no_administrative_privileges, + ) + from prowler.providers.gcp.services.iam.iam_service import ServiceAccount + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[], + project_id=GCP_PROJECT_ID, + ) + ] + + cloudresourcemanager_client.project_ids = [GCP_PROJECT_ID] + cloudresourcemanager_client.region = GCP_US_CENTER1_LOCATION + + cloudresourcemanager_client.bindings = [ + Binding( + role="roles/owner", + members=[ + "serviceAccount:my-service-account@my-project.iam.gserviceaccount.com" + ], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_no_administrative_privileges() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Account {iam_client.service_accounts[0].email} has administrative privileges with {cloudresourcemanager_client.bindings[0].role}." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].name + + def test_iam_sa_editor_role_binding(self): + cloudresourcemanager_client = mock.MagicMock + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.cloudresourcemanager_client", + new=cloudresourcemanager_client, + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.cloudresourcemanager.cloudresourcemanager_service import ( + Binding, + ) + from prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges import ( + iam_sa_no_administrative_privileges, + ) + from prowler.providers.gcp.services.iam.iam_service import ServiceAccount + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[], + project_id=GCP_PROJECT_ID, + ) + ] + + cloudresourcemanager_client.project_ids = [GCP_PROJECT_ID] + cloudresourcemanager_client.region = GCP_US_CENTER1_LOCATION + + cloudresourcemanager_client.bindings = [ + Binding( + role="roles/editor", + members=[ + "serviceAccount:my-service-account@my-project.iam.gserviceaccount.com" + ], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_no_administrative_privileges() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Account {iam_client.service_accounts[0].email} has administrative privileges with {cloudresourcemanager_client.bindings[0].role}." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].name + + def test_iam_sa_role_binding_different_email(self): + cloudresourcemanager_client = mock.MagicMock + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.cloudresourcemanager_client", + new=cloudresourcemanager_client, + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.cloudresourcemanager.cloudresourcemanager_service import ( + Binding, + ) + from prowler.providers.gcp.services.iam.iam_sa_no_administrative_privileges.iam_sa_no_administrative_privileges import ( + iam_sa_no_administrative_privileges, + ) + from prowler.providers.gcp.services.iam.iam_service import ServiceAccount + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[], + project_id=GCP_PROJECT_ID, + ) + ] + + cloudresourcemanager_client.project_ids = [GCP_PROJECT_ID] + cloudresourcemanager_client.region = GCP_US_CENTER1_LOCATION + + cloudresourcemanager_client.bindings = [ + Binding( + role="roles/admin", + members=[ + "serviceAccount:my-new-service-account@my-project.iam.gserviceaccount.com" + ], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_no_administrative_privileges() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Account {iam_client.service_accounts[0].email} has no administrative privileges." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].name diff --git a/tests/providers/gcp/services/iam/iam_sa_no_user_managed_keys/iam_sa_no_user_managed_keys_test.py b/tests/providers/gcp/services/iam/iam_sa_no_user_managed_keys/iam_sa_no_user_managed_keys_test.py new file mode 100644 index 0000000000..2c9d734377 --- /dev/null +++ b/tests/providers/gcp/services/iam/iam_sa_no_user_managed_keys/iam_sa_no_user_managed_keys_test.py @@ -0,0 +1,236 @@ +from datetime import datetime +from unittest import mock + +from tests.providers.gcp.gcp_fixtures import ( + GCP_PROJECT_ID, + GCP_US_CENTER1_LOCATION, + set_mocked_gcp_provider, +) + + +class Test_iam_sa_no_user_managed_keys: + def test_iam_no_sa(self): + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_user_managed_keys.iam_sa_no_user_managed_keys.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.iam.iam_sa_no_user_managed_keys.iam_sa_no_user_managed_keys import ( + iam_sa_no_user_managed_keys, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + iam_client.service_accounts = [] + + check = iam_sa_no_user_managed_keys() + result = check.execute() + assert len(result) == 0 + + def test_iam_sa_no_keys(self): + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_user_managed_keys.iam_sa_no_user_managed_keys.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.iam.iam_sa_no_user_managed_keys.iam_sa_no_user_managed_keys import ( + iam_sa_no_user_managed_keys, + ) + from prowler.providers.gcp.services.iam.iam_service import ServiceAccount + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_no_user_managed_keys() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Account {iam_client.service_accounts[0].email} does not have user-managed keys." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].name + + def test_iam_sa_no_user_managed_keys(self): + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_user_managed_keys.iam_sa_no_user_managed_keys.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.iam.iam_sa_no_user_managed_keys.iam_sa_no_user_managed_keys import ( + iam_sa_no_user_managed_keys, + ) + from prowler.providers.gcp.services.iam.iam_service import ( + Key, + ServiceAccount, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[ + Key( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com/keys/90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c", + origin="GOOGLE_PROVIDED", + type="SYSTEM_MANAGED", + valid_after=datetime.strptime("2024-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ) + ], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_no_user_managed_keys() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Account {iam_client.service_accounts[0].email} does not have user-managed keys." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].name + + def test_iam_sa_user_managed_keys(self): + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_user_managed_keys.iam_sa_no_user_managed_keys.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.iam.iam_sa_no_user_managed_keys.iam_sa_no_user_managed_keys import ( + iam_sa_no_user_managed_keys, + ) + from prowler.providers.gcp.services.iam.iam_service import ( + Key, + ServiceAccount, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[ + Key( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com/keys/90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c", + origin="GOOGLE_PROVIDED", + type="USER_MANAGED", + valid_after=datetime.strptime("2024-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ) + ], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_no_user_managed_keys() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Account {iam_client.service_accounts[0].email} has user-managed keys." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].name + + def test_iam_sa_mixed_keys(self): + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_no_user_managed_keys.iam_sa_no_user_managed_keys.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.iam.iam_sa_no_user_managed_keys.iam_sa_no_user_managed_keys import ( + iam_sa_no_user_managed_keys, + ) + from prowler.providers.gcp.services.iam.iam_service import ( + Key, + ServiceAccount, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[ + Key( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com/keys/90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c", + origin="GOOGLE_PROVIDED", + type="SYSTEM_MANAGED", + valid_after=datetime.strptime("2024-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ), + Key( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com/keys/e5e3800831ac1adc8a5849da7d827b4724b1fce8", + origin="GOOGLE_PROVIDED", + type="USER_MANAGED", + valid_after=datetime.strptime("2024-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ), + ], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_no_user_managed_keys() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Account {iam_client.service_accounts[0].email} has user-managed keys." + ) + assert result[0].resource_id == iam_client.service_accounts[0].email + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].name diff --git a/tests/providers/gcp/services/iam/iam_sa_user_managed_key_rotate_90_days/iam_sa_user_managed_key_rotate_90_days_test.py b/tests/providers/gcp/services/iam/iam_sa_user_managed_key_rotate_90_days/iam_sa_user_managed_key_rotate_90_days_test.py new file mode 100644 index 0000000000..620f5483d6 --- /dev/null +++ b/tests/providers/gcp/services/iam/iam_sa_user_managed_key_rotate_90_days/iam_sa_user_managed_key_rotate_90_days_test.py @@ -0,0 +1,174 @@ +from datetime import datetime +from unittest import mock + +from tests.providers.gcp.gcp_fixtures import ( + GCP_PROJECT_ID, + GCP_US_CENTER1_LOCATION, + set_mocked_gcp_provider, +) + + +class Test_iam_sa_user_managed_key_rotate_90_days: + def test_iam_no_sa(self): + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_rotate_90_days.iam_sa_user_managed_key_rotate_90_days.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.iam.iam_sa_user_managed_key_rotate_90_days.iam_sa_user_managed_key_rotate_90_days import ( + iam_sa_user_managed_key_rotate_90_days, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + iam_client.service_accounts = [] + + check = iam_sa_user_managed_key_rotate_90_days() + result = check.execute() + assert len(result) == 0 + + def test_iam_sa_no_keys(self): + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_rotate_90_days.iam_sa_user_managed_key_rotate_90_days.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.iam.iam_sa_user_managed_key_rotate_90_days.iam_sa_user_managed_key_rotate_90_days import ( + iam_sa_user_managed_key_rotate_90_days, + ) + from prowler.providers.gcp.services.iam.iam_service import ServiceAccount + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_user_managed_key_rotate_90_days() + result = check.execute() + assert len(result) == 0 + + def test_iam_sa_user_managed_key_rotate_90_days(self): + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_rotate_90_days.iam_sa_user_managed_key_rotate_90_days.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.iam.iam_sa_user_managed_key_rotate_90_days.iam_sa_user_managed_key_rotate_90_days import ( + iam_sa_user_managed_key_rotate_90_days, + ) + from prowler.providers.gcp.services.iam.iam_service import ( + Key, + ServiceAccount, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[ + Key( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com/keys/90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c", + origin="GOOGLE_PROVIDED", + type="USER_MANAGED", + valid_after=datetime.now(), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ) + ], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_user_managed_key_rotate_90_days() + last_rotated = ( + datetime.now() - iam_client.service_accounts[0].keys[0].valid_after + ).days + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"User-managed key {iam_client.service_accounts[0].keys[0].name} for account {iam_client.service_accounts[0].email} was rotated over the last 90 days ({last_rotated} days ago)." + ) + assert result[0].resource_id == iam_client.service_accounts[0].keys[0].name + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].email + + def test_iam_sa_user_managed_key_no_rotate_90_days(self): + iam_client = mock.MagicMock + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_gcp_provider(), + ), mock.patch( + "prowler.providers.gcp.services.iam.iam_sa_user_managed_key_rotate_90_days.iam_sa_user_managed_key_rotate_90_days.iam_client", + new=iam_client, + ): + from prowler.providers.gcp.services.iam.iam_sa_user_managed_key_rotate_90_days.iam_sa_user_managed_key_rotate_90_days import ( + iam_sa_user_managed_key_rotate_90_days, + ) + from prowler.providers.gcp.services.iam.iam_service import ( + Key, + ServiceAccount, + ) + + iam_client.project_ids = [GCP_PROJECT_ID] + iam_client.region = GCP_US_CENTER1_LOCATION + + iam_client.service_accounts = [ + ServiceAccount( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com", + email="my-service-account@my-project.iam.gserviceaccount.com", + display_name="My service account", + keys=[ + Key( + name="projects/my-project/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com/keys/90c48f61c65cd56224a12ab18e6ee9ca9c3aee7c", + origin="GOOGLE_PROVIDED", + type="USER_MANAGED", + valid_after=datetime.strptime("2023-07-10", "%Y-%m-%d"), + valid_before=datetime.strptime("9999-12-31", "%Y-%m-%d"), + ) + ], + project_id=GCP_PROJECT_ID, + ) + ] + + check = iam_sa_user_managed_key_rotate_90_days() + last_rotated = ( + datetime.now() - iam_client.service_accounts[0].keys[0].valid_after + ).days + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"User-managed key {iam_client.service_accounts[0].keys[0].name} for account {iam_client.service_accounts[0].email} was not rotated over the last 90 days ({last_rotated} days ago)." + ) + assert result[0].resource_id == iam_client.service_accounts[0].keys[0].name + assert result[0].project_id == GCP_PROJECT_ID + assert result[0].location == GCP_US_CENTER1_LOCATION + assert result[0].resource_name == iam_client.service_accounts[0].email