mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 23:05:05 +00:00
test(aws_provider): Role and User MFA (#2486)
This commit is contained in:
@@ -11,7 +11,6 @@ from prowler.lib.logger import logger
|
||||
timestamp = datetime.today()
|
||||
timestamp_utc = datetime.now(timezone.utc).replace(tzinfo=timezone.utc)
|
||||
prowler_version = "3.7.1"
|
||||
boto3_user_agent_extra = "APN_1826889"
|
||||
html_logo_url = "https://github.com/prowler-cloud/prowler/"
|
||||
html_logo_img = "https://user-images.githubusercontent.com/3985464/113734260-7ba06900-96fb-11eb-82bc-d4f68a1e2710.png"
|
||||
square_logo_img = "https://user-images.githubusercontent.com/38561120/235905862-9ece5bd7-9aa3-4e48-807a-3a9035eb8bfb.png"
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
AWS_STS_GLOBAL_ENDPOINT_REGION = "us-east-1"
|
||||
BOTO3_USER_AGENT_EXTRA = "APN_1826889"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from boto3 import session
|
||||
from botocore.config import Config
|
||||
|
||||
from prowler.config.config import boto3_user_agent_extra
|
||||
from prowler.providers.aws.config import BOTO3_USER_AGENT_EXTRA
|
||||
from prowler.providers.aws.lib.audit_info.models import AWS_Assume_Role, AWS_Audit_Info
|
||||
|
||||
# Default Current Audit Info
|
||||
@@ -15,7 +15,7 @@ current_audit_info = AWS_Audit_Info(
|
||||
# https://boto3.amazonaws.com/v1/documentation/api/latest/guide/retries.html
|
||||
session_config=Config(
|
||||
retries={"max_attempts": 3, "mode": "standard"},
|
||||
user_agent_extra=boto3_user_agent_extra,
|
||||
user_agent_extra=BOTO3_USER_AGENT_EXTRA,
|
||||
),
|
||||
audited_account=None,
|
||||
audited_account_arn=None,
|
||||
|
||||
@@ -3,7 +3,6 @@ import sys
|
||||
from botocore.config import Config
|
||||
from colorama import Fore, Style
|
||||
|
||||
from prowler.config.config import boto3_user_agent_extra
|
||||
from prowler.lib.logger import logger
|
||||
from prowler.providers.aws.aws_provider import (
|
||||
AWS_Provider,
|
||||
@@ -88,6 +87,7 @@ Azure Identity Type: {Fore.YELLOW}[{audit_info.identity.identity_type}]{Style.RE
|
||||
if input_session_duration and input_session_duration not in range(900, 43201):
|
||||
raise Exception("Value for -T option must be between 900 and 43200")
|
||||
|
||||
# Handle if session_duration is not the default value or external_id is set
|
||||
if (
|
||||
input_session_duration and input_session_duration != 3600
|
||||
) or input_external_id:
|
||||
@@ -114,7 +114,6 @@ Azure Identity Type: {Fore.YELLOW}[{audit_info.identity.identity_type}]{Style.RE
|
||||
"max_attempts": aws_retries_max_attempts,
|
||||
"mode": "standard",
|
||||
},
|
||||
user_agent_extra=boto3_user_agent_extra,
|
||||
)
|
||||
# Merge the new configuration
|
||||
new_boto3_config = current_audit_info.session_config.merge(config)
|
||||
|
||||
@@ -14,20 +14,17 @@ from prowler.providers.aws.aws_provider import (
|
||||
from prowler.providers.aws.lib.audit_info.models import AWS_Assume_Role, AWS_Audit_Info
|
||||
|
||||
ACCOUNT_ID = 123456789012
|
||||
AWS_REGION = "us-east-1"
|
||||
|
||||
|
||||
class Test_AWS_Provider:
|
||||
@mock_iam
|
||||
@mock_sts
|
||||
def test_assume_role_without_mfa(self):
|
||||
# Variables
|
||||
role_name = "test-role"
|
||||
role_arn = f"arn:aws:iam::{ACCOUNT_ID}:role/{role_name}"
|
||||
session_duration_seconds = 900
|
||||
def test_aws_provider_user_without_mfa(self):
|
||||
audited_regions = ["eu-west-1"]
|
||||
sessionName = "ProwlerAsessmentSession"
|
||||
# sessionName = "ProwlerAsessmentSession"
|
||||
# Boto 3 client to create our user
|
||||
iam_client = boto3.client("iam", region_name="us-east-1")
|
||||
iam_client = boto3.client("iam", region_name=AWS_REGION)
|
||||
# IAM user
|
||||
iam_user = iam_client.create_user(UserName="test-user")["User"]
|
||||
access_key = iam_client.create_access_key(UserName=iam_user["UserName"])[
|
||||
@@ -39,7 +36,7 @@ class Test_AWS_Provider:
|
||||
session = boto3.session.Session(
|
||||
aws_access_key_id=access_key_id,
|
||||
aws_secret_access_key=secret_access_key,
|
||||
region_name="us-east-1",
|
||||
region_name=AWS_REGION,
|
||||
)
|
||||
|
||||
# Fulfil the input session object for Prowler
|
||||
@@ -56,8 +53,8 @@ class Test_AWS_Provider:
|
||||
profile_region=None,
|
||||
credentials=None,
|
||||
assumed_role_info=AWS_Assume_Role(
|
||||
role_arn=role_arn,
|
||||
session_duration=session_duration_seconds,
|
||||
role_arn=None,
|
||||
session_duration=None,
|
||||
external_id=None,
|
||||
mfa_enabled=False,
|
||||
),
|
||||
@@ -68,47 +65,25 @@ class Test_AWS_Provider:
|
||||
)
|
||||
|
||||
# Call assume_role
|
||||
aws_provider = AWS_Provider(audit_info)
|
||||
assume_role_response = assume_role(
|
||||
aws_provider.aws_session, aws_provider.role_info
|
||||
)
|
||||
# Recover credentials for the assume role operation
|
||||
credentials = assume_role_response["Credentials"]
|
||||
# Test the response
|
||||
# SessionToken
|
||||
credentials["SessionToken"].should.have.length_of(356)
|
||||
credentials["SessionToken"].startswith("FQoGZXIvYXdzE")
|
||||
# AccessKeyId
|
||||
credentials["AccessKeyId"].should.have.length_of(20)
|
||||
credentials["AccessKeyId"].startswith("ASIA")
|
||||
# SecretAccessKey
|
||||
credentials["SecretAccessKey"].should.have.length_of(40)
|
||||
# Assumed Role
|
||||
assume_role_response["AssumedRoleUser"]["Arn"].should.equal(
|
||||
f"arn:aws:sts::{ACCOUNT_ID}:assumed-role/{role_name}/{sessionName}"
|
||||
)
|
||||
# AssumedRoleUser
|
||||
assert assume_role_response["AssumedRoleUser"]["AssumedRoleId"].startswith(
|
||||
"AROA"
|
||||
)
|
||||
assert assume_role_response["AssumedRoleUser"]["AssumedRoleId"].endswith(
|
||||
":" + sessionName
|
||||
)
|
||||
assume_role_response["AssumedRoleUser"]["AssumedRoleId"].should.have.length_of(
|
||||
21 + 1 + len(sessionName)
|
||||
)
|
||||
with patch(
|
||||
"prowler.providers.aws.aws_provider.input_role_mfa_token_and_code",
|
||||
return_value=(f"arn:aws:iam::{ACCOUNT_ID}:mfa/test-role-mfa", "111111"),
|
||||
):
|
||||
aws_provider = AWS_Provider(audit_info)
|
||||
assert aws_provider.aws_session.region_name is None
|
||||
assert aws_provider.role_info == AWS_Assume_Role(
|
||||
role_arn=None,
|
||||
session_duration=None,
|
||||
external_id=None,
|
||||
mfa_enabled=False,
|
||||
)
|
||||
|
||||
@mock_iam
|
||||
@mock_sts
|
||||
def test_assume_role_with_mfa(self):
|
||||
# Variables
|
||||
role_name = "test-role"
|
||||
role_arn = f"arn:aws:iam::{ACCOUNT_ID}:role/{role_name}"
|
||||
session_duration_seconds = 900
|
||||
audited_regions = ["eu-west-1"]
|
||||
sessionName = "ProwlerAsessmentSession"
|
||||
def test_aws_provider_user_with_mfa(self):
|
||||
audited_regions = "eu-west-1"
|
||||
# Boto 3 client to create our user
|
||||
iam_client = boto3.client("iam", region_name="us-east-1")
|
||||
iam_client = boto3.client("iam", region_name=AWS_REGION)
|
||||
# IAM user
|
||||
iam_user = iam_client.create_user(UserName="test-user")["User"]
|
||||
access_key = iam_client.create_access_key(UserName=iam_user["UserName"])[
|
||||
@@ -120,7 +95,71 @@ class Test_AWS_Provider:
|
||||
session = boto3.session.Session(
|
||||
aws_access_key_id=access_key_id,
|
||||
aws_secret_access_key=secret_access_key,
|
||||
region_name="us-east-1",
|
||||
region_name=AWS_REGION,
|
||||
)
|
||||
|
||||
# Fulfil the input session object for Prowler
|
||||
audit_info = AWS_Audit_Info(
|
||||
session_config=None,
|
||||
original_session=session,
|
||||
audit_session=None,
|
||||
audited_account=None,
|
||||
audited_account_arn=None,
|
||||
audited_partition=None,
|
||||
audited_identity_arn=None,
|
||||
audited_user_id=None,
|
||||
profile=None,
|
||||
profile_region=AWS_REGION,
|
||||
credentials=None,
|
||||
assumed_role_info=AWS_Assume_Role(
|
||||
role_arn=None,
|
||||
session_duration=None,
|
||||
external_id=None,
|
||||
mfa_enabled=False,
|
||||
),
|
||||
audited_regions=audited_regions,
|
||||
organizations_metadata=None,
|
||||
audit_resources=None,
|
||||
mfa_enabled=True,
|
||||
)
|
||||
|
||||
# # Call assume_role
|
||||
with patch(
|
||||
"prowler.providers.aws.aws_provider.input_role_mfa_token_and_code",
|
||||
return_value=(f"arn:aws:iam::{ACCOUNT_ID}:mfa/test-role-mfa", "111111"),
|
||||
):
|
||||
aws_provider = AWS_Provider(audit_info)
|
||||
assert aws_provider.aws_session.region_name is None
|
||||
assert aws_provider.role_info == AWS_Assume_Role(
|
||||
role_arn=None,
|
||||
session_duration=None,
|
||||
external_id=None,
|
||||
mfa_enabled=False,
|
||||
)
|
||||
|
||||
@mock_iam
|
||||
@mock_sts
|
||||
def test_aws_provider_assume_role_with_mfa(self):
|
||||
# Variables
|
||||
role_name = "test-role"
|
||||
role_arn = f"arn:aws:iam::{ACCOUNT_ID}:role/{role_name}"
|
||||
session_duration_seconds = 900
|
||||
audited_regions = ["eu-west-1"]
|
||||
sessionName = "ProwlerAsessmentSession"
|
||||
# Boto 3 client to create our user
|
||||
iam_client = boto3.client("iam", region_name=AWS_REGION)
|
||||
# IAM user
|
||||
iam_user = iam_client.create_user(UserName="test-user")["User"]
|
||||
access_key = iam_client.create_access_key(UserName=iam_user["UserName"])[
|
||||
"AccessKey"
|
||||
]
|
||||
access_key_id = access_key["AccessKeyId"]
|
||||
secret_access_key = access_key["SecretAccessKey"]
|
||||
# New Boto3 session with the previously create user
|
||||
session = boto3.session.Session(
|
||||
aws_access_key_id=access_key_id,
|
||||
aws_secret_access_key=secret_access_key,
|
||||
region_name=AWS_REGION,
|
||||
)
|
||||
|
||||
# Fulfil the input session object for Prowler
|
||||
@@ -186,17 +225,15 @@ class Test_AWS_Provider:
|
||||
|
||||
@mock_iam
|
||||
@mock_sts
|
||||
def test_assume_role_with_sts_endpoint_region(self):
|
||||
def test_aws_provider_assume_role_without_mfa(self):
|
||||
# Variables
|
||||
role_name = "test-role"
|
||||
role_arn = f"arn:aws:iam::{ACCOUNT_ID}:role/{role_name}"
|
||||
session_duration_seconds = 900
|
||||
aws_region = "eu-west-1"
|
||||
sts_endpoint_region = aws_region
|
||||
audited_regions = [aws_region]
|
||||
audited_regions = "eu-west-1"
|
||||
sessionName = "ProwlerAsessmentSession"
|
||||
# Boto 3 client to create our user
|
||||
iam_client = boto3.client("iam", region_name=aws_region)
|
||||
iam_client = boto3.client("iam", region_name=AWS_REGION)
|
||||
# IAM user
|
||||
iam_user = iam_client.create_user(UserName="test-user")["User"]
|
||||
access_key = iam_client.create_access_key(UserName=iam_user["UserName"])[
|
||||
@@ -208,7 +245,90 @@ class Test_AWS_Provider:
|
||||
session = boto3.session.Session(
|
||||
aws_access_key_id=access_key_id,
|
||||
aws_secret_access_key=secret_access_key,
|
||||
region_name=aws_region,
|
||||
region_name=AWS_REGION,
|
||||
)
|
||||
|
||||
# Fulfil the input session object for Prowler
|
||||
audit_info = AWS_Audit_Info(
|
||||
session_config=None,
|
||||
original_session=session,
|
||||
audit_session=None,
|
||||
audited_account=None,
|
||||
audited_account_arn=None,
|
||||
audited_partition=None,
|
||||
audited_identity_arn=None,
|
||||
audited_user_id=None,
|
||||
profile=None,
|
||||
profile_region=None,
|
||||
credentials=None,
|
||||
assumed_role_info=AWS_Assume_Role(
|
||||
role_arn=role_arn,
|
||||
session_duration=session_duration_seconds,
|
||||
external_id=None,
|
||||
mfa_enabled=False,
|
||||
),
|
||||
audited_regions=audited_regions,
|
||||
organizations_metadata=None,
|
||||
audit_resources=None,
|
||||
mfa_enabled=False,
|
||||
)
|
||||
|
||||
# Call assume_role
|
||||
aws_provider = AWS_Provider(audit_info)
|
||||
assume_role_response = assume_role(
|
||||
aws_provider.aws_session, aws_provider.role_info
|
||||
)
|
||||
# Recover credentials for the assume role operation
|
||||
credentials = assume_role_response["Credentials"]
|
||||
# Test the response
|
||||
# SessionToken
|
||||
credentials["SessionToken"].should.have.length_of(356)
|
||||
credentials["SessionToken"].startswith("FQoGZXIvYXdzE")
|
||||
# AccessKeyId
|
||||
credentials["AccessKeyId"].should.have.length_of(20)
|
||||
credentials["AccessKeyId"].startswith("ASIA")
|
||||
# SecretAccessKey
|
||||
credentials["SecretAccessKey"].should.have.length_of(40)
|
||||
# Assumed Role
|
||||
assume_role_response["AssumedRoleUser"]["Arn"].should.equal(
|
||||
f"arn:aws:sts::{ACCOUNT_ID}:assumed-role/{role_name}/{sessionName}"
|
||||
)
|
||||
# AssumedRoleUser
|
||||
assert assume_role_response["AssumedRoleUser"]["AssumedRoleId"].startswith(
|
||||
"AROA"
|
||||
)
|
||||
assert assume_role_response["AssumedRoleUser"]["AssumedRoleId"].endswith(
|
||||
":" + sessionName
|
||||
)
|
||||
assume_role_response["AssumedRoleUser"]["AssumedRoleId"].should.have.length_of(
|
||||
21 + 1 + len(sessionName)
|
||||
)
|
||||
|
||||
@mock_iam
|
||||
@mock_sts
|
||||
def test_assume_role_with_sts_endpoint_region(self):
|
||||
# Variables
|
||||
role_name = "test-role"
|
||||
role_arn = f"arn:aws:iam::{ACCOUNT_ID}:role/{role_name}"
|
||||
session_duration_seconds = 900
|
||||
aws_region = "eu-west-1"
|
||||
sts_endpoint_region = aws_region
|
||||
audited_regions = [aws_region]
|
||||
sessionName = "ProwlerAsessmentSession"
|
||||
# Boto 3 client to create our user
|
||||
iam_client = boto3.client("iam", region_name=AWS_REGION)
|
||||
# IAM user
|
||||
iam_user = iam_client.create_user(UserName="test-user")["User"]
|
||||
access_key = iam_client.create_access_key(UserName=iam_user["UserName"])[
|
||||
"AccessKey"
|
||||
]
|
||||
access_key_id = access_key["AccessKeyId"]
|
||||
secret_access_key = access_key["SecretAccessKey"]
|
||||
# New Boto3 session with the previously create user
|
||||
session = boto3.session.Session(
|
||||
aws_access_key_id=access_key_id,
|
||||
aws_secret_access_key=secret_access_key,
|
||||
region_name=AWS_REGION,
|
||||
)
|
||||
|
||||
# Fulfil the input session object for Prowler
|
||||
@@ -270,9 +390,9 @@ class Test_AWS_Provider:
|
||||
def test_generate_regional_clients(self):
|
||||
# New Boto3 session with the previously create user
|
||||
session = boto3.session.Session(
|
||||
region_name="us-east-1",
|
||||
region_name=AWS_REGION,
|
||||
)
|
||||
audited_regions = ["eu-west-1", "us-east-1"]
|
||||
audited_regions = ["eu-west-1", AWS_REGION]
|
||||
# Fulfil the input session object for Prowler
|
||||
audit_info = AWS_Audit_Info(
|
||||
session_config=None,
|
||||
@@ -301,10 +421,10 @@ class Test_AWS_Provider:
|
||||
def test_generate_regional_clients_global_service(self):
|
||||
# New Boto3 session with the previously create user
|
||||
session = boto3.session.Session(
|
||||
region_name="us-east-1",
|
||||
region_name=AWS_REGION,
|
||||
)
|
||||
audited_regions = ["eu-west-1", "us-east-1"]
|
||||
profile_region = "us-east-1"
|
||||
audited_regions = ["eu-west-1", AWS_REGION]
|
||||
profile_region = AWS_REGION
|
||||
# Fulfil the input session object for Prowler
|
||||
audit_info = AWS_Audit_Info(
|
||||
session_config=None,
|
||||
@@ -333,7 +453,7 @@ class Test_AWS_Provider:
|
||||
def test_generate_regional_clients_cn_partition(self):
|
||||
# New Boto3 session with the previously create user
|
||||
session = boto3.session.Session(
|
||||
region_name="us-east-1",
|
||||
region_name=AWS_REGION,
|
||||
)
|
||||
audited_regions = ["cn-northwest-1", "cn-north-1"]
|
||||
# Fulfil the input session object for Prowler
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import boto3
|
||||
import botocore
|
||||
import pytest
|
||||
import sure # noqa
|
||||
from boto3 import session
|
||||
from mock import patch
|
||||
@@ -119,37 +120,6 @@ class Test_Set_Audit_Info:
|
||||
|
||||
return audit_info
|
||||
|
||||
@patch(
|
||||
"prowler.providers.common.audit_info.validate_aws_credentials",
|
||||
new=mock_validate_credentials,
|
||||
)
|
||||
@patch(
|
||||
"prowler.providers.common.audit_info.print_aws_credentials",
|
||||
new=mock_print_audit_credentials,
|
||||
)
|
||||
def test_set_audit_info_aws(self):
|
||||
with patch(
|
||||
"prowler.providers.common.audit_info.current_audit_info",
|
||||
new=self.set_mocked_audit_info(),
|
||||
):
|
||||
provider = "aws"
|
||||
arguments = {
|
||||
"profile": None,
|
||||
"role": None,
|
||||
"session_duration": None,
|
||||
"external_id": None,
|
||||
"regions": None,
|
||||
"organizations_role": None,
|
||||
"subscriptions": None,
|
||||
"az_cli_auth": None,
|
||||
"sp_env_auth": None,
|
||||
"browser_auth": None,
|
||||
"managed_entity_auth": None,
|
||||
}
|
||||
|
||||
audit_info = set_provider_audit_info(provider, arguments)
|
||||
assert isinstance(audit_info, AWS_Audit_Info)
|
||||
|
||||
@patch(
|
||||
"prowler.providers.common.audit_info.azure_audit_info",
|
||||
new=mock_azure_audit_info,
|
||||
@@ -245,3 +215,89 @@ class Test_Set_Audit_Info:
|
||||
assert instance_id in str(
|
||||
get_tagged_resources(["MY_TAG1=MY_VALUE1"], mock_audit_info)
|
||||
)
|
||||
|
||||
@patch(
|
||||
"prowler.providers.common.audit_info.validate_aws_credentials",
|
||||
new=mock_validate_credentials,
|
||||
)
|
||||
@patch(
|
||||
"prowler.providers.common.audit_info.print_aws_credentials",
|
||||
new=mock_print_audit_credentials,
|
||||
)
|
||||
def test_set_audit_info_aws(self):
|
||||
with patch(
|
||||
"prowler.providers.common.audit_info.current_audit_info",
|
||||
new=self.set_mocked_audit_info(),
|
||||
):
|
||||
provider = "aws"
|
||||
arguments = {
|
||||
"profile": None,
|
||||
"role": None,
|
||||
"session_duration": None,
|
||||
"external_id": None,
|
||||
"regions": None,
|
||||
"organizations_role": None,
|
||||
}
|
||||
|
||||
audit_info = set_provider_audit_info(provider, arguments)
|
||||
assert isinstance(audit_info, AWS_Audit_Info)
|
||||
|
||||
def test_set_audit_info_aws_bad_session_duration(self):
|
||||
with patch(
|
||||
"prowler.providers.common.audit_info.current_audit_info",
|
||||
new=self.set_mocked_audit_info(),
|
||||
):
|
||||
provider = "aws"
|
||||
arguments = {
|
||||
"profile": None,
|
||||
"role": None,
|
||||
"session_duration": 100,
|
||||
"external_id": None,
|
||||
"regions": None,
|
||||
"organizations_role": None,
|
||||
}
|
||||
|
||||
with pytest.raises(SystemExit) as exception:
|
||||
_ = set_provider_audit_info(provider, arguments)
|
||||
# assert exception == "Value for -T option must be between 900 and 43200"
|
||||
assert isinstance(exception, pytest.ExceptionInfo)
|
||||
|
||||
def test_set_audit_info_aws_session_duration_without_role(self):
|
||||
with patch(
|
||||
"prowler.providers.common.audit_info.current_audit_info",
|
||||
new=self.set_mocked_audit_info(),
|
||||
):
|
||||
provider = "aws"
|
||||
arguments = {
|
||||
"profile": None,
|
||||
"role": None,
|
||||
"session_duration": 1000,
|
||||
"external_id": None,
|
||||
"regions": None,
|
||||
"organizations_role": None,
|
||||
}
|
||||
|
||||
with pytest.raises(SystemExit) as exception:
|
||||
_ = set_provider_audit_info(provider, arguments)
|
||||
# assert exception == "To use -I/-T options -R option is needed"
|
||||
assert isinstance(exception, pytest.ExceptionInfo)
|
||||
|
||||
def test_set_audit_info_external_id_without_role(self):
|
||||
with patch(
|
||||
"prowler.providers.common.audit_info.current_audit_info",
|
||||
new=self.set_mocked_audit_info(),
|
||||
):
|
||||
provider = "aws"
|
||||
arguments = {
|
||||
"profile": None,
|
||||
"role": None,
|
||||
"session_duration": 3600,
|
||||
"external_id": "test-external-id",
|
||||
"regions": None,
|
||||
"organizations_role": None,
|
||||
}
|
||||
|
||||
with pytest.raises(SystemExit) as exception:
|
||||
_ = set_provider_audit_info(provider, arguments)
|
||||
# assert exception == "To use -I/-T options -R option is needed"
|
||||
assert isinstance(exception, pytest.ExceptionInfo)
|
||||
|
||||
Reference in New Issue
Block a user