From 724e5fb3d5f827c0f7f987310855f4e438b661a0 Mon Sep 17 00:00:00 2001 From: Aaron Bouey Date: Fri, 24 Jan 2025 09:55:57 -0800 Subject: [PATCH 1/4] Moving assume_role method to process_enable_ebs_encryption_by_default so that we can build a regional STS endpoint. --- .../lambda/src/app.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py index 38df8fa9..35d68d0a 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py @@ -64,7 +64,7 @@ raise ValueError("Unexpected error executing Lambda function. Review CloudWatch logs for details.") from None -def assume_role(role: str, role_session_name: str, account: str = None, session: boto3.Session = None) -> boto3.Session: +def assume_role(role: str, role_session_name: str, region: str, account: str = None, session: boto3.Session = None) -> boto3.Session: """Assumes the provided role in the given account and returns a session. Args: @@ -78,7 +78,7 @@ def assume_role(role: str, role_session_name: str, account: str = None, session: """ if not session: session = boto3.Session() - sts_client: STSClient = session.client("sts", config=BOTO3_CONFIG) + sts_client: STSClient = session.client("sts", endpoint_url=f"https://sts.{region}.amazonaws.com", region_name=region, config=BOTO3_CONFIG) sts_arn = sts_client.get_caller_identity()["Arn"] LOGGER.info(f"USER: {sts_arn}") if not account: @@ -200,7 +200,7 @@ def get_organization_resource_tags(resource_id: str) -> List[TagTypeDef]: return tags -def process_enable_ebs_encryption_by_default(account_session: boto3.Session, account_id: str, regions: list) -> None: +def process_enable_ebs_encryption_by_default(configuration_role_name: str, session_role_name: str, account_id: str, regions: list) -> None: """Process enable ec2 default EBS encryption. Args: @@ -209,6 +209,7 @@ def process_enable_ebs_encryption_by_default(account_session: boto3.Session, acc regions: regions to process """ for region in regions: + account_session = assume_role(configuration_role_name, session_role_name, region, account_id) ec2_client: EC2Client = account_session.client("ec2", region, config=BOTO3_CONFIG) response: GetEbsEncryptionByDefaultResultTypeDef = ec2_client.get_ebs_encryption_by_default() @@ -289,9 +290,10 @@ def local_testing(aws_account: AccountTypeDef, params: dict) -> None: aws_account: AWS account to update params: solution parameters """ - account_session = assume_role(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"]) + regions = get_enabled_regions(params["ENABLED_REGIONS"], params["CONTROL_TOWER_REGIONS_ONLY"]) - process_enable_ebs_encryption_by_default(account_session, aws_account["Id"], regions) + + process_enable_ebs_encryption_by_default(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"], regions) def process_accounts(event: Union[CloudFormationCustomResourceEvent, dict], params: dict) -> None: @@ -364,10 +366,10 @@ def process_event_sns(event: dict) -> None: LOGGER.info({"SNS Record": record}) message = record["Sns"]["Message"] params["action"] = message["Action"] - + aws_account = get_account_info(account_id=message["AccountId"]) - account_session = assume_role(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"]) - process_enable_ebs_encryption_by_default(account_session, aws_account["Id"], regions) + + process_enable_ebs_encryption_by_default(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"], regions) def process_event_organizations(event: dict) -> None: From 4c0947d65387590b75ca322016be7c52dc6b38e3 Mon Sep 17 00:00:00 2001 From: Aaron Bouey Date: Tue, 4 Feb 2025 11:04:50 -0800 Subject: [PATCH 2/4] Using AWS_STS_REGIONAL_ENDPOINTS env variable instead of generating regional endpoint. --- .../lambda/src/app.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py index 35d68d0a..f51ec837 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py @@ -64,7 +64,7 @@ raise ValueError("Unexpected error executing Lambda function. Review CloudWatch logs for details.") from None -def assume_role(role: str, role_session_name: str, region: str, account: str = None, session: boto3.Session = None) -> boto3.Session: +def assume_role(role: str, role_session_name: str, account: str = None, session: boto3.Session = None) -> boto3.Session: """Assumes the provided role in the given account and returns a session. Args: @@ -76,9 +76,12 @@ def assume_role(role: str, role_session_name: str, region: str, account: str = N Returns: Session object for the specified AWS account """ + # set regional endpoint environment variable to account for potential opt-in regions + os.environ["AWS_STS_REGIONAL_ENDPOINTS"] = "regional" + if not session: session = boto3.Session() - sts_client: STSClient = session.client("sts", endpoint_url=f"https://sts.{region}.amazonaws.com", region_name=region, config=BOTO3_CONFIG) + sts_client: STSClient = session.client("sts", config=BOTO3_CONFIG) sts_arn = sts_client.get_caller_identity()["Arn"] LOGGER.info(f"USER: {sts_arn}") if not account: @@ -200,7 +203,7 @@ def get_organization_resource_tags(resource_id: str) -> List[TagTypeDef]: return tags -def process_enable_ebs_encryption_by_default(configuration_role_name: str, session_role_name: str, account_id: str, regions: list) -> None: +def process_enable_ebs_encryption_by_default(account_session: boto3.Session, account_id: str, regions: list) -> None: """Process enable ec2 default EBS encryption. Args: @@ -209,7 +212,6 @@ def process_enable_ebs_encryption_by_default(configuration_role_name: str, sessi regions: regions to process """ for region in regions: - account_session = assume_role(configuration_role_name, session_role_name, region, account_id) ec2_client: EC2Client = account_session.client("ec2", region, config=BOTO3_CONFIG) response: GetEbsEncryptionByDefaultResultTypeDef = ec2_client.get_ebs_encryption_by_default() @@ -290,10 +292,9 @@ def local_testing(aws_account: AccountTypeDef, params: dict) -> None: aws_account: AWS account to update params: solution parameters """ - + account_session = assume_role(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"]) regions = get_enabled_regions(params["ENABLED_REGIONS"], params["CONTROL_TOWER_REGIONS_ONLY"]) - - process_enable_ebs_encryption_by_default(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"], regions) + process_enable_ebs_encryption_by_default(account_session, aws_account["Id"], regions) def process_accounts(event: Union[CloudFormationCustomResourceEvent, dict], params: dict) -> None: @@ -366,10 +367,10 @@ def process_event_sns(event: dict) -> None: LOGGER.info({"SNS Record": record}) message = record["Sns"]["Message"] params["action"] = message["Action"] - + aws_account = get_account_info(account_id=message["AccountId"]) - - process_enable_ebs_encryption_by_default(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"], regions) + account_session = assume_role(params["CONFIGURATION_ROLE_NAME"], params["ROLE_SESSION_NAME"], aws_account["Id"]) + process_enable_ebs_encryption_by_default(account_session, aws_account["Id"], regions) def process_event_organizations(event: dict) -> None: From ffad75bb7afbf441f72261f73c173122c87b092c Mon Sep 17 00:00:00 2001 From: Aaron Bouey Date: Tue, 4 Feb 2025 13:02:52 -0800 Subject: [PATCH 3/4] Adding entry to changelog and updating table of contents. --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad76f9dd..e66182b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ## Table of Contents - [Introduction](#introduction) +- [2025-02-04](#2025-02-04) +- [2025-01-21](#2025-01-21) +- [2025-01-08](#2025-01-08) - [2024-09-18](#2024-09-18) - [2024-08-22](#2024-08-22) - [2024-07-17](#2024-07-17) @@ -64,6 +67,10 @@ All notable changes to this project will be documented in this file. - Added [Bedrock](aws_sra_examples/solutions/genai/bedrock_org) solution to deploy the sra-bedrock-org solution for GenAI deep-dive Bedrock capability one security controls. See https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1u3sd7f8n) +### Updated + +- Updated [EC2 Default EBS Encryption](aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption) solution with STS environment variable to enable enforcement in opt-in regions. + ## 2025-01-21 ### Updated From 8c38f62ee9a11d52319744c690decd679bed5e36 Mon Sep 17 00:00:00 2001 From: Aaron Bouey Date: Tue, 4 Feb 2025 13:09:59 -0800 Subject: [PATCH 4/4] Resolving linting issue W293 --- .../solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py index f51ec837..a392561a 100644 --- a/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py +++ b/aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption/lambda/src/app.py @@ -78,7 +78,7 @@ def assume_role(role: str, role_session_name: str, account: str = None, session: """ # set regional endpoint environment variable to account for potential opt-in regions os.environ["AWS_STS_REGIONAL_ENDPOINTS"] = "regional" - + if not session: session = boto3.Session() sts_client: STSClient = session.client("sts", config=BOTO3_CONFIG)