feat(cognito): add Amazon Cognito service (#3060)

This commit is contained in:
Sergio Garcia
2023-12-11 14:35:00 +01:00
committed by GitHub
parent c9cb9774c6
commit ba16330e20
8 changed files with 297 additions and 1 deletions

View File

@@ -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)

View File

@@ -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": [

View 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)

View 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] = []

View File

@@ -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,

View 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"

View File

@@ -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