diff --git a/arch/lza_extensions/customizations/GCGuardrailsRoles.yaml b/arch/lza_extensions/customizations/GCGuardrailsRoles.yaml index 07cefdf..ee8b1e2 100644 --- a/arch/lza_extensions/customizations/GCGuardrailsRoles.yaml +++ b/arch/lza_extensions/customizations/GCGuardrailsRoles.yaml @@ -449,6 +449,41 @@ Resources: Roles: - Ref: GCLambdaExecutionRole + # OpenSearch Access + GCLambdaExecutionRoleOpenSearchPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: AllowOpenSearchAccess + Action: + - "es:Desc*" + Resource: + - "*" + Effect: Allow + PolicyName: !Sub "${OrganizationName}GCLambdaExecutionRoleOpenSearchPolicy" + Roles: + - !Ref GCLambdaExecutionRole2 + + + # MarketPlace Access + GCLambdaExecutionRoleMarketPlacePolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: AllowMarketPlaceAccess + Action: + - "aws-marketplace:Li*" + Resource: + - "*" + Effect: Allow + PolicyName: !Sub "${OrganizationName}GCLambdaExecutionRoleMarketPlacePolicy" + Roles: + - !Ref GCLambdaExecutionRole2 + # IAM Access GCLambdaExecutionRoleCloudFrontPolicy: Type: AWS::IAM::Policy diff --git a/arch/templates/EvidenceCollectionComponents.yaml b/arch/templates/EvidenceCollectionComponents.yaml index 7d65e2a..e95cdc2 100644 --- a/arch/templates/EvidenceCollectionComponents.yaml +++ b/arch/templates/EvidenceCollectionComponents.yaml @@ -222,6 +222,8 @@ Resources: - Effect: Allow Action: - organizations:ListTagsForResource + - organizations:Des* + - lambda:In* Resource: "*" - PolicyName: S3Policy PolicyDocument: @@ -268,7 +270,7 @@ Resources: - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${OrganizationName}gc*" Effect: Allow - ## Create schedule + ## Create schedule. CronjobsScheduledRule: Condition: IsAuditAccount Type: AWS::Events::Rule diff --git a/arch/templates/main.yaml b/arch/templates/main.yaml index 809d662..63526b1 100644 --- a/arch/templates/main.yaml +++ b/arch/templates/main.yaml @@ -655,6 +655,39 @@ Resources: Runtime: !Ref PythonRuntime Timeout: 90 + # OpenSearch Access + GCLambdaExecutionRoleOpenSearchPolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: AllowOpenSearchAccess + Action: + - "es:Desc*" + Resource: + - "*" + Effect: Allow + PolicyName: !Sub "${OrganizationName}GCLambdaExecutionRoleOpenSearchPolicy" + Roles: + - !Ref GCLambdaExecutionRole2 + + # MarketPlace Access + GCLambdaExecutionRoleMarketPlacePolicy: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: AllowMarketPlaceAccess + Action: + - "aws-marketplace:Li*" + Resource: + - "*" + Effect: Allow + PolicyName: !Sub "${OrganizationName}GCLambdaExecutionRoleMarketPlacePolicy" + Roles: + - !Ref GCLambdaExecutionRole2 GenerateEvidenceBucketName: Type: Custom::GenerateEvidenceBucketName Condition: GenerateEvidenceBucketName diff --git a/src/lambda/aws_compile_audit_report/app.py b/src/lambda/aws_compile_audit_report/app.py index 2f30330..321f171 100644 --- a/src/lambda/aws_compile_audit_report/app.py +++ b/src/lambda/aws_compile_audit_report/app.py @@ -10,6 +10,7 @@ import time import uuid import concurrent.futures +import botocore.exceptions import boto3 from botocore.exceptions import BotoCoreError, ClientError @@ -54,10 +55,26 @@ def create_boto3_clients(): "organizations": get_client("organizations", assume_role=False) } + # MAIN LAMBDA HANDLER def lambda_handler(event, context): logger.info("Lambda invocation started (structured).") clients = create_boto3_clients() + # Initialize AWS Organizations client + org_client = boto3.client("organizations") + + # Fetch Management Account ID + def get_management_account_id(): + try: + response = org_client.describe_organization() + return response["Organization"]["MasterAccountId"] # Older accounts use "MasterAccountId" + except Exception as e: + print(f"Error fetching management account ID: {e}") + return "unknown" + + # Retrieve Management Account ID + global management_account_id + management_account_id = get_management_account_id() # Handle concurrency limit current_concurrency = event.get("current_concurrency", 1) @@ -439,7 +456,7 @@ def finalize_and_cleanup_if_necessary(temp_dir, state, s3_client): logger.info("State is finished. Merging partial CSV files.") merged_csv = merge_chunk_files(state["chunks_written"], temp_dir) if merged_csv: - final_key = f'{datetime.datetime.now(tz=datetime.timezone.utc).strftime(config["DATE_FORMAT"])}.csv' + final_key = f'{management_account_id}_{datetime.datetime.now(tz=datetime.timezone.utc).strftime(config["DATE_FORMAT"])}.csv' try: with open(merged_csv, "rb") as f: safe_aws_call( @@ -487,7 +504,7 @@ def merge_chunk_files(chunk_files, temp_dir): return merged_path def cleanup_temp_directory(temp_dir): - """Remove the entire temporary directory.""" + """Remove the entire temporary directory..""" if os.path.exists(temp_dir): shutil.rmtree(temp_dir, ignore_errors=True) logger.info("Cleaned up temp directory: %s", temp_dir) \ No newline at end of file