mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 06:45:08 +00:00
feat(cognito): add Amazon Cognito service (#3060)
This commit is contained in:
@@ -240,6 +240,8 @@ def get_checks_from_input_arn(audit_resources: list, provider: str) -> set:
|
|||||||
service = "efs"
|
service = "efs"
|
||||||
elif service == "logs":
|
elif service == "logs":
|
||||||
service = "cloudwatch"
|
service = "cloudwatch"
|
||||||
|
elif service == "cognito":
|
||||||
|
service = "cognito-idp"
|
||||||
# Check if Prowler has checks in service
|
# Check if Prowler has checks in service
|
||||||
try:
|
try:
|
||||||
list_modules(provider, service)
|
list_modules(provider, service)
|
||||||
|
|||||||
@@ -2195,6 +2195,36 @@
|
|||||||
"aws-us-gov": []
|
"aws-us-gov": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cognito": {
|
||||||
|
"regions": {
|
||||||
|
"aws": [
|
||||||
|
"ap-northeast-1",
|
||||||
|
"ap-northeast-2",
|
||||||
|
"ap-northeast-3",
|
||||||
|
"ap-south-1",
|
||||||
|
"ap-southeast-1",
|
||||||
|
"ap-southeast-2",
|
||||||
|
"ca-central-1",
|
||||||
|
"eu-central-1",
|
||||||
|
"eu-north-1",
|
||||||
|
"eu-south-1",
|
||||||
|
"eu-west-1",
|
||||||
|
"eu-west-2",
|
||||||
|
"eu-west-3",
|
||||||
|
"il-central-1",
|
||||||
|
"me-south-1",
|
||||||
|
"sa-east-1",
|
||||||
|
"us-east-1",
|
||||||
|
"us-east-2",
|
||||||
|
"us-west-1",
|
||||||
|
"us-west-2"
|
||||||
|
],
|
||||||
|
"aws-cn": [],
|
||||||
|
"aws-us-gov": [
|
||||||
|
"us-gov-west-1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"cognito-identity": {
|
"cognito-identity": {
|
||||||
"regions": {
|
"regions": {
|
||||||
"aws": [
|
"aws": [
|
||||||
@@ -10683,4 +10713,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
0
prowler/providers/aws/services/cognito/__init__.py
Normal file
0
prowler/providers/aws/services/cognito/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from prowler.providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||||
|
from prowler.providers.aws.services.cognito.cognito_service import CognitoIDP
|
||||||
|
|
||||||
|
cognito_idp_client = CognitoIDP(current_audit_info)
|
||||||
122
prowler/providers/aws/services/cognito/cognito_service.py
Normal file
122
prowler/providers/aws/services/cognito/cognito_service.py
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
################## CognitoIDP
|
||||||
|
class CognitoIDP(AWSService):
|
||||||
|
def __init__(self, audit_info):
|
||||||
|
super().__init__("cognito-idp", audit_info)
|
||||||
|
self.user_pools = {}
|
||||||
|
self.__threading_call__(self.__list_user_pools__)
|
||||||
|
self.__describe_user_pools__()
|
||||||
|
self.__get_user_pool_mfa_config__()
|
||||||
|
|
||||||
|
def __list_user_pools__(self, regional_client):
|
||||||
|
logger.info("Cognito - Listing User Pools...")
|
||||||
|
try:
|
||||||
|
user_pools_paginator = regional_client.get_paginator("list_user_pools")
|
||||||
|
for page in user_pools_paginator.paginate(MaxResults=60):
|
||||||
|
for user_pool in page["UserPools"]:
|
||||||
|
arn = f"arn:{self.audited_partition}:cognito-idp:{regional_client.region}:{self.audited_account}:userpool/{user_pool['Id']}"
|
||||||
|
if not self.audit_resources or (
|
||||||
|
is_resource_filtered(arn, self.audit_resources)
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
self.user_pools[arn] = UserPool(
|
||||||
|
id=user_pool["Id"],
|
||||||
|
arn=arn,
|
||||||
|
name=user_pool["Name"],
|
||||||
|
region=regional_client.region,
|
||||||
|
last_modified=user_pool["LastModifiedDate"],
|
||||||
|
creation_date=user_pool["CreationDate"],
|
||||||
|
status=user_pool.get("Status", "Disabled"),
|
||||||
|
)
|
||||||
|
except Exception as error:
|
||||||
|
logger.error(
|
||||||
|
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||||
|
)
|
||||||
|
except Exception as error:
|
||||||
|
logger.error(
|
||||||
|
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __describe_user_pools__(self):
|
||||||
|
logger.info("Cognito - Describing User Pools...")
|
||||||
|
try:
|
||||||
|
for user_pool in self.user_pools.values():
|
||||||
|
try:
|
||||||
|
user_pool_details = self.regional_clients[
|
||||||
|
user_pool.region
|
||||||
|
].describe_user_pool(UserPoolId=user_pool.id)["UserPool"]
|
||||||
|
user_pool.password_policy = user_pool_details.get(
|
||||||
|
"Policies", {}
|
||||||
|
).get("PasswordPolicy", {})
|
||||||
|
user_pool.deletion_protection = user_pool_details.get(
|
||||||
|
"DeletionProtection", "INACTIVE"
|
||||||
|
)
|
||||||
|
user_pool.advanced_security_mode = user_pool_details.get(
|
||||||
|
"UserPoolAddOns", {}
|
||||||
|
).get("AdvancedSecurityMode", "OFF")
|
||||||
|
user_pool.tags = [user_pool_details.get("UserPoolTags", "")]
|
||||||
|
except Exception as error:
|
||||||
|
logger.error(
|
||||||
|
f"{user_pool.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||||
|
)
|
||||||
|
except Exception as error:
|
||||||
|
logger.error(
|
||||||
|
f"{user_pool.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __get_user_pool_mfa_config__(self):
|
||||||
|
logger.info("Cognito - Getting User Pool MFA Configuration...")
|
||||||
|
try:
|
||||||
|
for user_pool in self.user_pools.values():
|
||||||
|
try:
|
||||||
|
mfa_config = self.regional_clients[
|
||||||
|
user_pool.region
|
||||||
|
].get_user_pool_mfa_config(UserPoolId=user_pool.id)
|
||||||
|
if mfa_config["MfaConfiguration"] != "OFF":
|
||||||
|
user_pool.mfa_config = MFAConfig(
|
||||||
|
sms_authentication=mfa_config.get(
|
||||||
|
"SmsMfaConfiguration", {}
|
||||||
|
),
|
||||||
|
software_token_mfa_authentication=mfa_config.get(
|
||||||
|
"SoftwareTokenMfaConfiguration", {}
|
||||||
|
),
|
||||||
|
status=mfa_config["MfaConfiguration"],
|
||||||
|
)
|
||||||
|
except Exception as error:
|
||||||
|
logger.error(
|
||||||
|
f"{user_pool.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||||
|
)
|
||||||
|
except Exception as error:
|
||||||
|
logger.error(
|
||||||
|
f"{user_pool.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class MFAConfig(BaseModel):
|
||||||
|
sms_authentication: Optional[dict]
|
||||||
|
software_token_mfa_authentication: Optional[dict]
|
||||||
|
status: str
|
||||||
|
|
||||||
|
|
||||||
|
class UserPool(BaseModel):
|
||||||
|
id: str
|
||||||
|
arn: str
|
||||||
|
name: str
|
||||||
|
region: str
|
||||||
|
advanced_security_mode: str = "OFF"
|
||||||
|
deletion_protection: str = "INACTIVE"
|
||||||
|
last_modified: datetime
|
||||||
|
creation_date: datetime
|
||||||
|
status: str
|
||||||
|
password_policy: Optional[dict]
|
||||||
|
mfa_config: Optional[MFAConfig]
|
||||||
|
tags: Optional[list] = []
|
||||||
@@ -256,6 +256,10 @@ def mock_recover_checks_from_aws_provider_rds_service(*_):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def mock_recover_checks_from_aws_provider_cognito_service(*_):
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
class Test_Check:
|
class Test_Check:
|
||||||
def test_load_check_metadata(self):
|
def test_load_check_metadata(self):
|
||||||
test_cases = [
|
test_cases = [
|
||||||
@@ -565,6 +569,19 @@ class Test_Check:
|
|||||||
recovered_checks = get_checks_from_input_arn(audit_resources, provider)
|
recovered_checks = get_checks_from_input_arn(audit_resources, provider)
|
||||||
assert recovered_checks == expected_checks
|
assert recovered_checks == expected_checks
|
||||||
|
|
||||||
|
@patch(
|
||||||
|
"prowler.lib.check.check.recover_checks_from_provider",
|
||||||
|
new=mock_recover_checks_from_aws_provider_cognito_service,
|
||||||
|
)
|
||||||
|
def test_get_checks_from_input_arn_cognito(self):
|
||||||
|
audit_resources = [
|
||||||
|
f"arn:aws:cognito-idp:us-east-1:{AWS_ACCOUNT_NUMBER}:userpool/test"
|
||||||
|
]
|
||||||
|
provider = "aws"
|
||||||
|
expected_checks = []
|
||||||
|
recovered_checks = get_checks_from_input_arn(audit_resources, provider)
|
||||||
|
assert recovered_checks == expected_checks
|
||||||
|
|
||||||
@patch(
|
@patch(
|
||||||
"prowler.lib.check.check.recover_checks_from_provider",
|
"prowler.lib.check.check.recover_checks_from_provider",
|
||||||
new=mock_recover_checks_from_aws_provider_ec2_service,
|
new=mock_recover_checks_from_aws_provider_ec2_service,
|
||||||
|
|||||||
117
tests/providers/aws/services/cognito/cognito_service_test.py
Normal file
117
tests/providers/aws/services/cognito/cognito_service_test.py
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
from boto3 import client
|
||||||
|
from moto import mock_cognitoidp
|
||||||
|
|
||||||
|
from prowler.providers.aws.services.cognito.cognito_service import CognitoIDP
|
||||||
|
from tests.providers.aws.audit_info_utils import (
|
||||||
|
AWS_ACCOUNT_NUMBER,
|
||||||
|
AWS_REGION_EU_WEST_1,
|
||||||
|
AWS_REGION_US_EAST_1,
|
||||||
|
set_mocked_aws_audit_info,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Test_Cognito_Service:
|
||||||
|
# Test Cognito Service
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_service(self):
|
||||||
|
audit_info = set_mocked_aws_audit_info(
|
||||||
|
audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
|
||||||
|
)
|
||||||
|
cognito = CognitoIDP(audit_info)
|
||||||
|
assert cognito.service == "cognito-idp"
|
||||||
|
|
||||||
|
# Test Cognito client
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_client(self):
|
||||||
|
audit_info = set_mocked_aws_audit_info(
|
||||||
|
audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
|
||||||
|
)
|
||||||
|
cognito = CognitoIDP(audit_info)
|
||||||
|
for regional_client in cognito.regional_clients.values():
|
||||||
|
assert regional_client.__class__.__name__ == "CognitoIdentityProvider"
|
||||||
|
|
||||||
|
# Test Cognito session
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test__get_session__(self):
|
||||||
|
audit_info = set_mocked_aws_audit_info(
|
||||||
|
audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
|
||||||
|
)
|
||||||
|
cognito = CognitoIDP(audit_info)
|
||||||
|
assert cognito.session.__class__.__name__ == "Session"
|
||||||
|
|
||||||
|
# Test Cognito Session
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_audited_account(self):
|
||||||
|
audit_info = set_mocked_aws_audit_info(
|
||||||
|
audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
|
||||||
|
)
|
||||||
|
cognito = CognitoIDP(audit_info)
|
||||||
|
assert cognito.audited_account == AWS_ACCOUNT_NUMBER
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_list_user_pools(self):
|
||||||
|
user_pool_name_1 = "user_pool_test_1"
|
||||||
|
user_pool_name_2 = "user_pool_test_2"
|
||||||
|
audit_info = set_mocked_aws_audit_info(
|
||||||
|
audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
|
||||||
|
)
|
||||||
|
cognito_client_eu_west_1 = client("cognito-idp", region_name="eu-west-1")
|
||||||
|
cognito_client_us_east_1 = client("cognito-idp", region_name="us-east-1")
|
||||||
|
cognito_client_eu_west_1.create_user_pool(PoolName=user_pool_name_1)
|
||||||
|
cognito_client_us_east_1.create_user_pool(PoolName=user_pool_name_2)
|
||||||
|
cognito = CognitoIDP(audit_info)
|
||||||
|
assert len(cognito.user_pools) == 2
|
||||||
|
for user_pool in cognito.user_pools.values():
|
||||||
|
assert (
|
||||||
|
user_pool.name == user_pool_name_1 or user_pool.name == user_pool_name_2
|
||||||
|
)
|
||||||
|
assert user_pool.region == "eu-west-1" or user_pool.region == "us-east-1"
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_describe_user_pools(self):
|
||||||
|
user_pool_name_1 = "user_pool_test_1"
|
||||||
|
audit_info = set_mocked_aws_audit_info(
|
||||||
|
audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
|
||||||
|
)
|
||||||
|
cognito_client_eu_west_1 = client("cognito-idp", region_name="eu-west-1")
|
||||||
|
user_pool_id = cognito_client_eu_west_1.create_user_pool(
|
||||||
|
PoolName=user_pool_name_1
|
||||||
|
)["UserPool"]["Id"]
|
||||||
|
cognito = CognitoIDP(audit_info)
|
||||||
|
assert len(cognito.user_pools) == 1
|
||||||
|
for user_pool in cognito.user_pools.values():
|
||||||
|
assert user_pool.name == user_pool_name_1
|
||||||
|
assert user_pool.region == "eu-west-1"
|
||||||
|
assert user_pool.id == user_pool_id
|
||||||
|
assert user_pool.password_policy is not None
|
||||||
|
assert user_pool.deletion_protection is not None
|
||||||
|
assert user_pool.advanced_security_mode is not None
|
||||||
|
assert user_pool.tags is not None
|
||||||
|
|
||||||
|
@mock_cognitoidp
|
||||||
|
def test_get_user_pool_mfa_config(self):
|
||||||
|
user_pool_name_1 = "user_pool_test_1"
|
||||||
|
audit_info = set_mocked_aws_audit_info(
|
||||||
|
audited_regions=[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
|
||||||
|
)
|
||||||
|
cognito_client_eu_west_1 = client("cognito-idp", region_name="eu-west-1")
|
||||||
|
user_pool_id = cognito_client_eu_west_1.create_user_pool(
|
||||||
|
PoolName=user_pool_name_1
|
||||||
|
)["UserPool"]["Id"]
|
||||||
|
cognito_client_eu_west_1.set_user_pool_mfa_config(
|
||||||
|
UserPoolId=user_pool_id,
|
||||||
|
SoftwareTokenMfaConfiguration={"Enabled": True},
|
||||||
|
MfaConfiguration="ON",
|
||||||
|
)
|
||||||
|
cognito = CognitoIDP(audit_info)
|
||||||
|
assert len(cognito.user_pools) == 1
|
||||||
|
for user_pool in cognito.user_pools.values():
|
||||||
|
assert user_pool.name == user_pool_name_1
|
||||||
|
assert user_pool.region == "eu-west-1"
|
||||||
|
assert user_pool.id == user_pool_id
|
||||||
|
assert user_pool.mfa_config is not None
|
||||||
|
assert user_pool.mfa_config.sms_authentication == {}
|
||||||
|
assert user_pool.mfa_config.software_token_mfa_authentication == {
|
||||||
|
"Enabled": True
|
||||||
|
}
|
||||||
|
assert user_pool.mfa_config.status == "ON"
|
||||||
@@ -48,6 +48,10 @@ for page in get_parameters_by_path_paginator.paginate(
|
|||||||
logging.info("Updating subservices and the services not present in the original matrix")
|
logging.info("Updating subservices and the services not present in the original matrix")
|
||||||
# macie2 --> macie
|
# macie2 --> macie
|
||||||
regions_by_service["services"]["macie2"] = regions_by_service["services"]["macie"]
|
regions_by_service["services"]["macie2"] = regions_by_service["services"]["macie"]
|
||||||
|
# cognito --> cognito-idp
|
||||||
|
regions_by_service["services"]["cognito"] = regions_by_service["services"][
|
||||||
|
"cognito-idp"
|
||||||
|
]
|
||||||
# opensearch --> es
|
# opensearch --> es
|
||||||
regions_by_service["services"]["opensearch"] = regions_by_service["services"]["es"]
|
regions_by_service["services"]["opensearch"] = regions_by_service["services"]["es"]
|
||||||
# elbv2 --> elb
|
# elbv2 --> elb
|
||||||
|
|||||||
Reference in New Issue
Block a user