From 36a843412a540265ca7a3d0f7d606699f242ebbb Mon Sep 17 00:00:00 2001 From: kagahd Date: Tue, 28 Jan 2025 08:01:19 +0100 Subject: [PATCH 1/4] fix(aws) key error for detect-secrets --- ...lambda_function_no_secrets_in_variables.py | 12 +- ...task_definitions_no_environment_secrets.py | 13 +- ...a_function_no_secrets_in_variables_test.py | 47 +++- ...definitions_no_environment_secrets_test.py | 227 +++++++++++++++++- 4 files changed, 275 insertions(+), 24 deletions(-) diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.py b/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.py index aea6617e163..e83633dd51e 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.py +++ b/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.py @@ -28,19 +28,13 @@ def execute(self): "detect_secrets_plugins", ), ) - original_env_vars = {} + original_env_vars = [] for name, value in function.environment.items(): - original_env_vars.update( - { - hashlib.sha1( # nosec B324 SHA1 is used here for non-security-critical unique identifiers - value.encode("utf-8") - ).hexdigest(): name - } - ) + original_env_vars.append(name) if detect_secrets_output: secrets_string = ", ".join( [ - f"{secret['type']} in variable {original_env_vars[secret['hashed_secret']]}" + f"{secret['type']} in variable {original_env_vars[secret['line_number'] - 2]}" for secret in detect_secrets_output ] ) diff --git a/prowler/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets.py b/prowler/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets.py index 42dc6b437cc..cd835d01498 100644 --- a/prowler/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets.py +++ b/prowler/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets.py @@ -1,4 +1,3 @@ -import hashlib from json import dumps from prowler.lib.check.models import Check, Check_Report_AWS @@ -25,16 +24,10 @@ def execute(self): if container.environment: dump_env_vars = {} - original_env_vars = {} + original_env_vars = [] for env_var in container.environment: dump_env_vars.update({env_var.name: env_var.value}) - original_env_vars.update( - { - hashlib.sha1( # nosec B324 SHA1 is used here for non-security-critical unique identifiers - env_var.value.encode("utf-8") - ).hexdigest(): env_var.name - } - ) + original_env_vars.append(env_var.name) env_data = dumps(dump_env_vars, indent=2) detect_secrets_output = detect_secrets_scan( @@ -47,7 +40,7 @@ def execute(self): if detect_secrets_output: secrets_string = ", ".join( [ - f"{secret['type']} on the environment variable {original_env_vars[secret['hashed_secret']]}" + f"{secret['type']} on the environment variable {original_env_vars[secret['line_number'] - 2]}" for secret in detect_secrets_output ] ) diff --git a/tests/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables_test.py b/tests/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables_test.py index 432b31e9279..bd38a225eba 100644 --- a/tests/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables_test.py +++ b/tests/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables_test.py @@ -76,7 +76,7 @@ def test_function_no_variables(self): ) assert result[0].resource_tags == [] - def test_function_secrets_in_variables(self): + def test_function_secrets_in_keyword(self): lambda_client = mock.MagicMock function_name = "test-lambda" function_runtime = "nodejs4.3" @@ -121,6 +121,51 @@ def test_function_secrets_in_variables(self): ) assert result[0].resource_tags == [] + def test_function_secrets_in_keyword_and_variable(self): + lambda_client = mock.MagicMock + function_name = "test-lambda" + function_runtime = "nodejs4.3" + function_arn = f"arn:aws:lambda:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:function/{function_name}" + + lambda_client.audit_config = {"secrets_ignore_patterns": []} + + lambda_client.functions = { + "function_name": Function( + name=function_name, + security_groups=[], + arn=function_arn, + region=AWS_REGION_US_EAST_1, + runtime=function_runtime, + environment={"db_password": "srv://admin:pass@db"}, + ) + } + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_aws_provider(), + ), mock.patch( + "prowler.providers.aws.services.awslambda.awslambda_function_no_secrets_in_variables.awslambda_function_no_secrets_in_variables.awslambda_client", + new=lambda_client, + ): + # Test Check + from prowler.providers.aws.services.awslambda.awslambda_function_no_secrets_in_variables.awslambda_function_no_secrets_in_variables import ( + awslambda_function_no_secrets_in_variables, + ) + + check = awslambda_function_no_secrets_in_variables() + result = check.execute() + + assert len(result) == 1 + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_id == function_name + assert result[0].resource_arn == function_arn + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Potential secret found in Lambda function {function_name} variables -> Secret Keyword in variable db_password, Basic Auth Credentials in variable db_password." + ) + assert result[0].resource_tags == [] + def test_function_secrets_in_variables_telegram_token(self): lambda_client = mock.MagicMock function_name = "test-lambda" diff --git a/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py b/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py index 18dc0077139..44806599a3e 100644 --- a/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py +++ b/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py @@ -10,8 +10,10 @@ CONTAINER_NAME = "test-container" ENV_VAR_NAME_NO_SECRETS = "host" ENV_VAR_VALUE_NO_SECRETS = "localhost:1234" -ENV_VAR_NAME_WITH_SECRETS = "DB_PASSWORD" -ENV_VAR_VALUE_WITH_SECRETS = "pass-12343" +ENV_VAR_NAME_WITH_KEYWORD = "DB_PASSWORD" +ENV_VAR_VALUE_WITH_SECRETS = "srv://admin:pass@db" +ENV_VAR_NAME_WITH_KEYWORD2 = "DATABASE_PASSWORD" +ENV_VAR_VALUE_WITH_SECRETS2 = "srv://admin:password@database" class Test_ecs_task_definitions_no_environment_secrets: @@ -88,7 +90,7 @@ def test_container_env_var_no_secrets(self): assert result[0].resource_tags == [] @mock_aws - def test_container_env_var_with_secrets(self): + def test_container_env_var_with_secret(self): ecs_client = client("ecs", region_name=AWS_REGION_US_EAST_1) task_arn = ecs_client.register_task_definition( @@ -103,7 +105,7 @@ def test_container_env_var_with_secrets(self): "user": "appuser", "environment": [ { - "name": ENV_VAR_NAME_WITH_SECRETS, + "name": ENV_VAR_NAME_NO_SECRETS, "value": ENV_VAR_VALUE_WITH_SECRETS, } ], @@ -115,6 +117,59 @@ def test_container_env_var_with_secrets(self): mocked_aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + with patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mocked_aws_provider, + ), patch( + "prowler.providers.aws.services.ecs.ecs_task_definitions_no_environment_secrets.ecs_task_definitions_no_environment_secrets.ecs_client", + new=ECS(mocked_aws_provider), + ): + from prowler.providers.aws.services.ecs.ecs_task_definitions_no_environment_secrets.ecs_task_definitions_no_environment_secrets import ( + ecs_task_definitions_no_environment_secrets, + ) + + check = ecs_task_definitions_no_environment_secrets() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Potential secrets found in ECS task definition {TASK_NAME} with revision {TASK_REVISION}: Secrets in container test-container -> Basic Auth Credentials on the environment variable host." + ) + assert result[0].resource_id == f"{TASK_NAME}:{TASK_REVISION}" + assert result[0].resource_arn == task_arn + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_tags == [] + + + @mock_aws + def test_container_env_var_with_keyword(self): + ecs_client = client("ecs", region_name=AWS_REGION_US_EAST_1) + + task_arn = ecs_client.register_task_definition( + family=TASK_NAME, + containerDefinitions=[ + { + "name": CONTAINER_NAME, + "image": "ubuntu", + "memory": 128, + "readonlyRootFilesystem": True, + "privileged": False, + "user": "appuser", + "environment": [ + { + "name": ENV_VAR_NAME_WITH_KEYWORD, + "value": ENV_VAR_VALUE_NO_SECRETS, + } + ], + } + ], + )["taskDefinition"]["taskDefinitionArn"] + + from prowler.providers.aws.services.ecs.ecs_service import ECS + + mocked_aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + with patch( "prowler.providers.common.provider.Provider.get_global_provider", return_value=mocked_aws_provider, @@ -138,3 +193,167 @@ def test_container_env_var_with_secrets(self): assert result[0].resource_arn == task_arn assert result[0].region == AWS_REGION_US_EAST_1 assert result[0].resource_tags == [] + + @mock_aws + def test_container_env_var_with_keyword_and_secret(self): + ecs_client = client("ecs", region_name=AWS_REGION_US_EAST_1) + + task_arn = ecs_client.register_task_definition( + family=TASK_NAME, + containerDefinitions=[ + { + "name": CONTAINER_NAME, + "image": "ubuntu", + "memory": 128, + "readonlyRootFilesystem": True, + "privileged": False, + "user": "appuser", + "environment": [ + { + "name": ENV_VAR_NAME_WITH_KEYWORD, + "value": ENV_VAR_VALUE_WITH_SECRETS, + } + ], + } + ], + )["taskDefinition"]["taskDefinitionArn"] + + from prowler.providers.aws.services.ecs.ecs_service import ECS + + mocked_aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mocked_aws_provider, + ), patch( + "prowler.providers.aws.services.ecs.ecs_task_definitions_no_environment_secrets.ecs_task_definitions_no_environment_secrets.ecs_client", + new=ECS(mocked_aws_provider), + ): + from prowler.providers.aws.services.ecs.ecs_task_definitions_no_environment_secrets.ecs_task_definitions_no_environment_secrets import ( + ecs_task_definitions_no_environment_secrets, + ) + + check = ecs_task_definitions_no_environment_secrets() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Potential secrets found in ECS task definition {TASK_NAME} with revision {TASK_REVISION}: Secrets in container test-container -> Secret Keyword on the environment variable DB_PASSWORD, Basic Auth Credentials on the environment variable DB_PASSWORD." + ) + assert result[0].resource_id == f"{TASK_NAME}:{TASK_REVISION}" + assert result[0].resource_arn == task_arn + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_tags == [] + + @mock_aws + def test_container_multiple_env_vars_with_keyword_and_secret(self): + ecs_client = client("ecs", region_name=AWS_REGION_US_EAST_1) + + task_arn = ecs_client.register_task_definition( + family=TASK_NAME, + containerDefinitions=[ + { + "name": CONTAINER_NAME, + "image": "ubuntu", + "memory": 128, + "readonlyRootFilesystem": True, + "privileged": False, + "user": "appuser", + "environment": [ + { + "name": ENV_VAR_NAME_WITH_KEYWORD, + "value": ENV_VAR_VALUE_WITH_SECRETS, + }, + { + "name": ENV_VAR_NAME_NO_SECRETS, + "value": ENV_VAR_VALUE_WITH_SECRETS2, + } + ], + } + ], + )["taskDefinition"]["taskDefinitionArn"] + + from prowler.providers.aws.services.ecs.ecs_service import ECS + + mocked_aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mocked_aws_provider, + ), patch( + "prowler.providers.aws.services.ecs.ecs_task_definitions_no_environment_secrets.ecs_task_definitions_no_environment_secrets.ecs_client", + new=ECS(mocked_aws_provider), + ): + from prowler.providers.aws.services.ecs.ecs_task_definitions_no_environment_secrets.ecs_task_definitions_no_environment_secrets import ( + ecs_task_definitions_no_environment_secrets, + ) + + check = ecs_task_definitions_no_environment_secrets() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Potential secrets found in ECS task definition {TASK_NAME} with revision {TASK_REVISION}: Secrets in container test-container -> Secret Keyword on the environment variable DB_PASSWORD, Basic Auth Credentials on the environment variable DB_PASSWORD, Basic Auth Credentials on the environment variable host." + ) + assert result[0].resource_id == f"{TASK_NAME}:{TASK_REVISION}" + assert result[0].resource_arn == task_arn + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_tags == [] + + @mock_aws + def test_container_all_env_vars_with_keyword_and_secret(self): + ecs_client = client("ecs", region_name=AWS_REGION_US_EAST_1) + + task_arn = ecs_client.register_task_definition( + family=TASK_NAME, + containerDefinitions=[ + { + "name": CONTAINER_NAME, + "image": "ubuntu", + "memory": 128, + "readonlyRootFilesystem": True, + "privileged": False, + "user": "appuser", + "environment": [ + { + "name": ENV_VAR_NAME_WITH_KEYWORD, + "value": ENV_VAR_VALUE_WITH_SECRETS, + }, + { + "name": ENV_VAR_NAME_WITH_KEYWORD2, + "value": ENV_VAR_VALUE_WITH_SECRETS2, + } + ], + } + ], + )["taskDefinition"]["taskDefinitionArn"] + + from prowler.providers.aws.services.ecs.ecs_service import ECS + + mocked_aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mocked_aws_provider, + ), patch( + "prowler.providers.aws.services.ecs.ecs_task_definitions_no_environment_secrets.ecs_task_definitions_no_environment_secrets.ecs_client", + new=ECS(mocked_aws_provider), + ): + from prowler.providers.aws.services.ecs.ecs_task_definitions_no_environment_secrets.ecs_task_definitions_no_environment_secrets import ( + ecs_task_definitions_no_environment_secrets, + ) + + check = ecs_task_definitions_no_environment_secrets() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Potential secrets found in ECS task definition {TASK_NAME} with revision {TASK_REVISION}: Secrets in container test-container -> Secret Keyword on the environment variable DB_PASSWORD, Basic Auth Credentials on the environment variable DB_PASSWORD, Basic Auth Credentials on the environment variable DATABASE_PASSWORD, Secret Keyword on the environment variable DATABASE_PASSWORD." + ) + assert result[0].resource_id == f"{TASK_NAME}:{TASK_REVISION}" + assert result[0].resource_arn == task_arn + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_tags == [] From 893f9a7b20fdb5a1c60cc6270665acb5c2a8d6be Mon Sep 17 00:00:00 2001 From: kagahd Date: Tue, 28 Jan 2025 08:33:58 +0100 Subject: [PATCH 2/4] remove unused hashlib import --- .../awslambda_function_no_secrets_in_variables.py | 1 - 1 file changed, 1 deletion(-) diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.py b/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.py index e83633dd51e..9448b0239f8 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.py +++ b/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.py @@ -1,4 +1,3 @@ -import hashlib import json from prowler.lib.check.models import Check, Check_Report_AWS From 68ec338d5879802fdf4f7400b975ffb8044e1aa7 Mon Sep 17 00:00:00 2001 From: kagahd Date: Tue, 28 Jan 2025 08:42:12 +0100 Subject: [PATCH 3/4] make flake8 happy --- .../ecs_task_definitions_no_environment_secrets_test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py b/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py index 44806599a3e..53078589605 100644 --- a/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py +++ b/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py @@ -2,7 +2,6 @@ from boto3 import client from moto import mock_aws - from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider TASK_NAME = "test-task" @@ -141,7 +140,6 @@ def test_container_env_var_with_secret(self): assert result[0].region == AWS_REGION_US_EAST_1 assert result[0].resource_tags == [] - @mock_aws def test_container_env_var_with_keyword(self): ecs_client = client("ecs", region_name=AWS_REGION_US_EAST_1) From 8c4a9f8f9d7eb0aa2d459742b86fbdd07f9923f1 Mon Sep 17 00:00:00 2001 From: kagahd Date: Tue, 28 Jan 2025 08:45:22 +0100 Subject: [PATCH 4/4] make black happy --- .../ecs_task_definitions_no_environment_secrets_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py b/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py index 53078589605..f6b5c411c2e 100644 --- a/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py +++ b/tests/providers/aws/services/ecs/ecs_task_definitions_no_environment_secrets/ecs_task_definitions_no_environment_secrets_test.py @@ -266,7 +266,7 @@ def test_container_multiple_env_vars_with_keyword_and_secret(self): { "name": ENV_VAR_NAME_NO_SECRETS, "value": ENV_VAR_VALUE_WITH_SECRETS2, - } + }, ], } ], @@ -322,7 +322,7 @@ def test_container_all_env_vars_with_keyword_and_secret(self): { "name": ENV_VAR_NAME_WITH_KEYWORD2, "value": ENV_VAR_VALUE_WITH_SECRETS2, - } + }, ], } ],