diff --git a/prowler/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled.py b/prowler/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled.py index db5d85dece..bd000bebb0 100644 --- a/prowler/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled.py +++ b/prowler/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled.py @@ -15,7 +15,7 @@ class codeartifact_packages_external_public_publishing_disabled(Check): for package in repository.packages: report = Check_Report_AWS(self.metadata()) report.region = repository.region - report.resource_id = package.name + report.resource_id = f"{repository.domain_name}/{package.name}" report.resource_arn = f"{repository.arn}/{package.namespace + ':' if package.namespace else ''}{package.name}" report.resource_tags = repository.tags @@ -28,10 +28,10 @@ class codeartifact_packages_external_public_publishing_disabled(Check): == RestrictionValues.ALLOW ): report.status = "FAIL" - report.status_extended = f"Internal package {package.name} is vulnerable to dependency confusion in repository {repository.arn}." + report.status_extended = f"Internal package {package.name} is vulnerable to dependency confusion in repository {repository.domain_name}." else: report.status = "PASS" - report.status_extended = f"Internal package {package.name} is not vulnerable to dependency confusion in repository {repository.arn}." + report.status_extended = f"Internal package {package.name} is not vulnerable to dependency confusion in repository {repository.domain_name}." findings.append(report) diff --git a/prowler/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled_fixer.py b/prowler/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled_fixer.py new file mode 100644 index 0000000000..1b140b11f7 --- /dev/null +++ b/prowler/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled_fixer.py @@ -0,0 +1,59 @@ +from prowler.lib.logger import logger +from prowler.providers.aws.services.codeartifact.codeartifact_client import ( + codeartifact_client, +) + + +def fixer(resource_id: str, region: str) -> bool: + """ + Modify the CodeArtifact package's configuration to restrict public access. + Specifically, this fixer changes the package's configuration to block public access by + setting restrictions on the "publish" and "upstream" actions. + Requires the codeartifact:PutPackageOriginConfiguration permission. + Permissions: + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "codeartifact:PutPackageOriginConfiguration", + "Resource": "*" + } + ] + } + Args: + resource_id (str): The CodeArtifact package name in the format "domain_name/package_name". + region (str): AWS region where the CodeArtifact package exists. + Returns: + bool: True if the operation is successful (configuration updated), False otherwise. + """ + try: + domain_name, package_name = resource_id.split("/") + + regional_client = codeartifact_client.regional_clients[region] + + for repository in codeartifact_client.repositories.values(): + if repository.domain_name == domain_name: + for package in repository.packages: + if package.name == package_name: + publish_value = ( + package.origin_configuration.restrictions.publish.value + ) + regional_client.put_package_origin_configuration( + domain=domain_name, + repository=repository.name, + format=package.format, + package=package_name, + restrictions={ + "publish": publish_value, + "upstream": "BLOCK", + }, + ) + + except Exception as error: + logger.error( + f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return False + else: + return True diff --git a/tests/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled_fixer_test.py b/tests/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled_fixer_test.py new file mode 100644 index 0000000000..9b1d67c811 --- /dev/null +++ b/tests/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled_fixer_test.py @@ -0,0 +1,85 @@ +from unittest import mock + +import botocore +from moto import mock_aws + +from prowler.providers.aws.services.codeartifact.codeartifact_service import ( + CodeArtifact, +) +from tests.providers.aws.utils import AWS_REGION_EU_WEST_1, set_mocked_aws_provider + +mock_make_api_call = botocore.client.BaseClient._make_api_call + + +def mock_make_api_call_codeartifact(self, operation_name, kwarg): + if operation_name == "PutPackageOriginConfiguration": + return { + "PackageOriginConfiguration": { + "Restrictions": { + "Publish": "BLOCK", + "Upstream": "BLOCK", + } + } + } + return mock_make_api_call(self, operation_name, kwarg) + + +def mock_make_api_call_codeartifact_error(self, operation_name, kwarg): + if operation_name == "PutPackageOriginConfiguration": + raise botocore.exceptions.ClientError( + { + "Error": { + "Code": "PackageNotFound", + "Message": "PackageNotFound", + } + }, + operation_name, + ) + return mock_make_api_call(self, operation_name, kwarg) + + +class Test_codeartifact_packages_external_public_publishing_disabled_fixer: + @mock_aws + def test_repository_package_public_publishing_origin_internal(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_codeartifact, + ): + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.codeartifact.codeartifact_client.codeartifact_client", + new=CodeArtifact(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled_fixer import ( + fixer, + ) + + assert fixer("test/test-package", AWS_REGION_EU_WEST_1) + + @mock_aws + def test_repository_package_public_publishing_origin_internal_error(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_codeartifact_error, + ): + + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.codeartifact.codeartifact_client.codeartifact_client", + new=CodeArtifact(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled_fixer import ( + fixer, + ) + + assert not fixer("non-existing-package", AWS_REGION_EU_WEST_1) diff --git a/tests/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled_test.py b/tests/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled_test.py index 9fb655b21a..f23c3463c5 100644 --- a/tests/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled_test.py +++ b/tests/providers/aws/services/codeartifact/codeartifact_packages_external_public_publishing_disabled/codeartifact_packages_external_public_publishing_disabled_test.py @@ -23,6 +23,9 @@ class Test_codeartifact_packages_external_public_publishing_disabled: with mock.patch( "prowler.providers.aws.services.codeartifact.codeartifact_service.CodeArtifact", new=codeartifact_client, + ), mock.patch( + "prowler.providers.aws.services.codeartifact.codeartifact_client.codeartifact_client", + new=codeartifact_client, ): # Test Check from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled import ( @@ -69,7 +72,7 @@ class Test_codeartifact_packages_external_public_publishing_disabled: "test-repository": Repository( name="test-repository", arn=repository_arn, - domain_name="", + domain_name="test", domain_owner="", region=AWS_REGION, packages=[ @@ -97,6 +100,9 @@ class Test_codeartifact_packages_external_public_publishing_disabled: with mock.patch( "prowler.providers.aws.services.codeartifact.codeartifact_service.CodeArtifact", new=codeartifact_client, + ), mock.patch( + "prowler.providers.aws.services.codeartifact.codeartifact_client.codeartifact_client", + new=codeartifact_client, ): # Test Check from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled import ( @@ -108,7 +114,7 @@ class Test_codeartifact_packages_external_public_publishing_disabled: assert len(result) == 1 assert result[0].region == AWS_REGION - assert result[0].resource_id == "test-package" + assert result[0].resource_id == "test/test-package" assert ( result[0].resource_arn == repository_arn + "/" + package_namespace + ":" + package_name @@ -117,7 +123,7 @@ class Test_codeartifact_packages_external_public_publishing_disabled: assert result[0].status == "FAIL" assert ( result[0].status_extended - == f"Internal package {package_name} is vulnerable to dependency confusion in repository {repository_arn}." + == f"Internal package {package_name} is vulnerable to dependency confusion in repository test." ) def test_repository_package_private_publishing_origin_internal(self): @@ -129,7 +135,7 @@ class Test_codeartifact_packages_external_public_publishing_disabled: "test-repository": Repository( name="test-repository", arn=repository_arn, - domain_name="", + domain_name="test", domain_owner="", region=AWS_REGION, packages=[ @@ -157,6 +163,9 @@ class Test_codeartifact_packages_external_public_publishing_disabled: with mock.patch( "prowler.providers.aws.services.codeartifact.codeartifact_service.CodeArtifact", new=codeartifact_client, + ), mock.patch( + "prowler.providers.aws.services.codeartifact.codeartifact_client.codeartifact_client", + new=codeartifact_client, ): # Test Check from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled import ( @@ -168,7 +177,7 @@ class Test_codeartifact_packages_external_public_publishing_disabled: assert len(result) == 1 assert result[0].region == AWS_REGION - assert result[0].resource_id == "test-package" + assert result[0].resource_id == "test/test-package" assert ( result[0].resource_arn == repository_arn + "/" + package_namespace + ":" + package_name @@ -177,5 +186,5 @@ class Test_codeartifact_packages_external_public_publishing_disabled: assert result[0].status == "PASS" assert ( result[0].status_extended - == f"Internal package {package_name} is not vulnerable to dependency confusion in repository {repository_arn}." + == f"Internal package {package_name} is not vulnerable to dependency confusion in repository test." )