From caa3c62cd6c7616b7270518e1182a8a6ef3cbf21 Mon Sep 17 00:00:00 2001 From: Ryan_c_wu Date: Fri, 22 Jul 2022 17:41:38 +0800 Subject: [PATCH 1/6] lambda for handle the scan result --- .../handler.py | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 post-scan-actions/aws-python-publish-malware-to-sns/handler.py diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/handler.py b/post-scan-actions/aws-python-publish-malware-to-sns/handler.py new file mode 100644 index 00000000..8edbcb3c --- /dev/null +++ b/post-scan-actions/aws-python-publish-malware-to-sns/handler.py @@ -0,0 +1,78 @@ +import os +import json +from datetime import datetime +from urllib.parse import urlparse + +import boto3 + + +def get_bucket_name(file_url): + + url = urlparse(file_url) + return url.hostname.split('.')[0] + + +def get_iso_str(ts): + + dt = datetime.fromtimestamp(ts) + return dt.isoformat() + + +def fetch_account_name(): + + account_client = boto3.client('account') + response = account_client.get_alternate_contact( + AlternateContactType='SECURITY' + ) + + return response['AlternateContact']['Name'] + + +def lambda_handler(event, context): + + target_sns_arn = os.environ['TARGET_SNS_ARN'] + + scan_results = [] + + for record in event['Records']: + + print('record', record) + + # Message details from SNS event + message = json.loads(record['Sns']['Message']) + findings = message['scanning_result'].get('Findings') + + # ARN info to get AWS Account ID + # arn = json.dumps(record['EventSubscriptionArn']) + # account_id = arn.split(":")[4].strip() + + if not findings: + continue + + finding = findings[0] + + scan_results.append({ + 'bucket_name': get_bucket_name(message['file_url']), + 'account_name': fetch_account_name(), + 'malware_type': finding['malware'], + 'type': finding['type'], + 'time': get_iso_str(message['timestamp']) + }) + + print('scan_results', scan_results) + + sns_client = boto3.client('sns') + request_entries = [ + { + 'Message': json.dumps(scan_result), + 'Id': str(i) + } + for i, scan_result in enumerate(scan_results) + ] + + response = sns_client.publish_batch( + TopicArn=target_sns_arn, + PublishBatchRequestEntries=request_entries, + ) + + print(response) From 353be9c457fb2567580965730c84d0fa3fb7d7d4 Mon Sep 17 00:00:00 2001 From: Ryan_c_wu Date: Tue, 26 Jul 2022 14:26:55 +0800 Subject: [PATCH 2/6] add makefile and cloudformation template --- .../Makefile | 62 +++++++++++++ .../template.yml | 90 +++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 post-scan-actions/aws-python-publish-malware-to-sns/Makefile create mode 100644 post-scan-actions/aws-python-publish-malware-to-sns/template.yml diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/Makefile b/post-scan-actions/aws-python-publish-malware-to-sns/Makefile new file mode 100644 index 00000000..5f12b448 --- /dev/null +++ b/post-scan-actions/aws-python-publish-malware-to-sns/Makefile @@ -0,0 +1,62 @@ +.PHONY: zip + +MKDIR := mkdir +ZIP := zip + +zip: + $(MKDIR) -p zip + $(ZIP) zip/send-malware-to-sns.zip handler.py + +create-target-sns-topic: + aws sns create-topic --name $(TARGET_SNS_TOPIC_NAME) + +create-publish-malware-policy: + aws iam create-policy \ + --policy-name $(PUBLISH_MALWARE_POLICY_NAME) \ + --policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"VisualEditor0\",\"Effect\":\"Allow\",\"Action\":[\"sns:TagResource\",\"sns:Publish\",\"account:GetAlternateContact\"],\"Resource\":\"*\"}]}" + +create-publish-malware-role: + aws iam create-role \ + --role-name $(PUBLISH_MALWARE_ROLE_NAME) \ + --assume-role-policy-document "{\"Version\": \"2012-10-17\",\"Statement\": [{\"Action\": \"sts:AssumeRole\",\"Effect\": \"Allow\",\"Principal\": {\"Service\": \"lambda.amazonaws.com\"}}]}" + +attach-policy: + aws iam attach-role-policy \ + --role-name $(PUBLISH_MALWARE_ROLE_NAME) \ + --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + + aws iam attach-role-policy \ + --role-name $(PUBLISH_MALWARE_ROLE_NAME) \ + --policy-arn $(PUBLISH_MALWARE_POLICY_ARN) + +create-function: zip + aws lambda create-function \ + --function-name $(PUBLISH_MALWARE_LAMBDA_NAME) \ + --role $(PUBLISH_MALWARE_ROLE_ARN) \ + --runtime python3.9 \ + --timeout 30 \ + --memory-size 128 \ + --handler handler.lambda_handler \ + --environment Variables=\{TARGET_SNS_ARN=$(TARGET_SNS_TOPIC_ARN)\} \ + --zip-file fileb://zip/send-malware-to-sns.zip + +subscribe-to-sns-topic: + aws sns subscribe \ + --topic-arn $(SCAN_RESULT_TOPIC_ARN) \ + --protocol lambda \ + --notification-endpoint $(PUBLISH_MALWARE_LAMBDA_ARN) \ + --region $(REGION) + +add-lambda-permission: + aws lambda add-permission \ + --function-name $(PUBLISH_MALWARE_LAMBDA_NAME) \ + --region $(REGION) \ + --statement-id sns \ + --action lambda:InvokeFunction \ + --principal sns.amazonaws.com \ + --source-arn $(SCAN_RESULT_TOPIC_ARN) + +update-function-code: zip + aws lambda update-function-code \ + --function-name $(FUNCTION_NAME) \ + --zip-file fileb://zip/send-malware-to-sns.zip diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/template.yml b/post-scan-actions/aws-python-publish-malware-to-sns/template.yml new file mode 100644 index 00000000..1eaca73b --- /dev/null +++ b/post-scan-actions/aws-python-publish-malware-to-sns/template.yml @@ -0,0 +1,90 @@ +AWSTemplateFormatVersion: 2010-09-09 +Transform: AWS::Serverless-2016-10-31 + +Metadata: + AWS::ServerlessRepo::Application: + Name: cloudone-filestorage-plugin-publish-malware-to-sns + Description: >- + According to the scan result from the scanner, publish the malware information + to the target SNS topic. + Author: Trend Micro Cloud One File Storage Security + +Parameters: + TargetSnsTopicName: + Type: String + Description: The name for the SNS topic to which malware information publish. + PublishMalwareLambdaName: + Type: String + Description: The name for the lambda function publishes the malware information to SNS topic. + PublishMalwarePolicyName: + Type: String + Description: The name for the policy includes sns and account authority. + PublishMalwareRoleName: + Type: String + Description: The name for the role to execute the lambda function. + ScanResultTopicARN: + Type: String + Description: The ARN of the scan result SNS topic in storage stack. +Resources: + TargetSnsTopic: + Type: AWS::SNS::Topic + Properties: + TopicName: !Ref TargetSnsTopicName + DisplayName: Malware notification + PublishMalwarePolicy: + Type: AWS::IAM::ManagedPolicy + Properties: + ManagedPolicyName: !Ref PublishMalwarePolicyName + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - 'sns:TagResource' + - 'sns:Publish' + - 'account:GetAlternateContact' + Resource: '*' + PublishMalwareRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Ref PublishMalwareRoleName + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - sts:AssumeRole + ManagedPolicyArns: + - !Ref PublishMalwarePolicy + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + PublishMalwareLambda: + Type: AWS::Lambda::Function + Properties: + CodeUri: ./ + Handler: handler.lambda_handler + FunctionName: !Ref PublishMalwareLambdaName + Runtime: python3.8 + Timeout: 500 + Role: !GetAtt + - PublishMalwareRole + - Arn + Environment: + Variables: + TARGET_SNS_ARN: !Ref TargetSnsTopic + MemorySize: 128 + TopicSubscription: + Type: AWS::SNS::Subscription + Properties: + Protocol: lambda + Endpoint: !GetAtt PublishMalwareLambda.Arn + TopicArn: !Ref ScanResultTopicARN + InvokedLambdaPermission: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !GetAtt PublishMalwareLambda.Arn + Action: lambda:InvokeFunction + Principal: events.amazonaws.com + SourceArn: !Ref ScanResultTopicARN From d58a744f0c280a583f922066115d8c00e339a1dd Mon Sep 17 00:00:00 2001 From: Ryan_c_wu Date: Tue, 26 Jul 2022 17:08:10 +0800 Subject: [PATCH 3/6] add makefile --- .../README.md | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 post-scan-actions/aws-python-publish-malware-to-sns/README.md diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/README.md b/post-scan-actions/aws-python-publish-malware-to-sns/README.md new file mode 100644 index 00000000..0c001a17 --- /dev/null +++ b/post-scan-actions/aws-python-publish-malware-to-sns/README.md @@ -0,0 +1,111 @@ +# Cloud One File Storage Security Post Scan Action - Publish Malware to SNS Topic + +After a scan occurs, this example Lambda function publish the malware information to specific SNS topic. + +## Prerequisites + +### Find the 'ScanResultTopicARN' SNS topic ARN + +- In the AWS console, go to **Services > CloudFormation** > your all-in-one stack > **Outputs** or **Services > CloudFormation** > your storage stack > **Outputs**. +- Scroll down to locate the **ScanResultTopicARN** Key. +- Copy the **ScanResultTopic** ARN to a temporary location. Example: `arn:aws:sns:us-east-1:123445678901:FileStorageSecurity-All-In-One-Stack-StorageStack-1IDPU1PZ2W5RN-ScanResultTopic-N8DD2JH1GRKF` + +## Installation + +### From Cloudformation Template + +1. Visit AWS cloudformation console. +2. Click **Create Stack**. +3. Upload `template.yml` in this folder. +4. Fill in the paramters. +5. Click **Next**. +6. Check the require access capabilities checkboxes. +7. Click **Create Stack**. + +### From Makefile + +In a shell program, enter the following GNU Make command, using backslashes (`\`) to separate lines + +1. **Create Malware Target SNS Topic** + + ```bash + TARGET_SNS_TOPIC_NAME= \ + make create-target-sns-topic + ``` + +- where: + - `` is the name for the new SNS topic which cloud be published the walmare information. + +2. **Create Required Policy** + + ```bash + PUBLISH_MALWARE_POLICY_NAME= \ + make create-publish-malware-policy + ``` + +- where + - `` is the name for the new policy. + +3. **Create Required Role** + + ```bash + PUBLISH_MALWARE_POLICY_NAME= \ + make create-publish-malware-role + ``` + +- where + - `` is the name for the new role. + +4. **Attach Policy** + + ```bash + PUBLISH_MALWARE_ROLE_NAME= \ + PUBLISH_MALWARE_POLICY_ARN= \ + make create-publish-malware-role + ``` + +- where + - `` is the policy ARN created from step 2. + - `` is the role name created from step 3. + +5. **Create Lambda Function** + + ```bash + PUBLISH_MALWARE_LAMBDA_NAME= \ + PUBLISH_MALWARE_ROLE_ARN= \ + TARGET_SNS_TOPIC_ARN= \ + make create-function + ``` + +- where + - `` is the SNS topic ARN created from step 1. + - `` is the role ARN created from step 3. + - `` is the name for new lambda function. + +6. **SNS Subscrition** + + ```bash + SCAN_RESULT_TOPIC_ARN= \ + PUBLISH_MALWARE_LAMBDA_ARN= \ + REGION= \ + make subscribe-to-sns-topic + ``` + +- where + - `` is the lambda function ARN created from step 5. + - `` is the SNS topic ARN from the storage stack. + - `` is the building AWS region. + +7. **Add Lambda Permission** + + ```bash + PUBLISH_MALWARE_LAMBDA_NAME= \ + REGION= \ + SCAN_RESULT_TOPIC_ARN= \ + make add-lambda-permission + ``` + +- where + - `` is the lambda function and created from step 5. + - `` is the building AWS region. + - `` is the SNS topic ARN from the storage stack. From 0a5f5296bd49409e93dffe573e5faa664017c379 Mon Sep 17 00:00:00 2001 From: Ryan_c_wu Date: Wed, 27 Jul 2022 13:49:37 +0800 Subject: [PATCH 4/6] refine PR --- .../handler.py | 11 +- .../template.yml | 131 +++++++++++++----- 2 files changed, 104 insertions(+), 38 deletions(-) diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/handler.py b/post-scan-actions/aws-python-publish-malware-to-sns/handler.py index 8edbcb3c..2a1bf024 100644 --- a/post-scan-actions/aws-python-publish-malware-to-sns/handler.py +++ b/post-scan-actions/aws-python-publish-malware-to-sns/handler.py @@ -33,6 +33,7 @@ def lambda_handler(event, context): target_sns_arn = os.environ['TARGET_SNS_ARN'] scan_results = [] + account_name = fetch_account_name() for record in event['Records']: @@ -42,10 +43,6 @@ def lambda_handler(event, context): message = json.loads(record['Sns']['Message']) findings = message['scanning_result'].get('Findings') - # ARN info to get AWS Account ID - # arn = json.dumps(record['EventSubscriptionArn']) - # account_id = arn.split(":")[4].strip() - if not findings: continue @@ -53,9 +50,9 @@ def lambda_handler(event, context): scan_results.append({ 'bucket_name': get_bucket_name(message['file_url']), - 'account_name': fetch_account_name(), - 'malware_type': finding['malware'], - 'type': finding['type'], + 'account_name': account_name, + 'malware': finding['malware'], + 'malware_type': finding['type'], 'time': get_iso_str(message['timestamp']) }) diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/template.yml b/post-scan-actions/aws-python-publish-malware-to-sns/template.yml index 1eaca73b..d22aa547 100644 --- a/post-scan-actions/aws-python-publish-malware-to-sns/template.yml +++ b/post-scan-actions/aws-python-publish-malware-to-sns/template.yml @@ -1,53 +1,46 @@ AWSTemplateFormatVersion: 2010-09-09 -Transform: AWS::Serverless-2016-10-31 - -Metadata: - AWS::ServerlessRepo::Application: - Name: cloudone-filestorage-plugin-publish-malware-to-sns - Description: >- - According to the scan result from the scanner, publish the malware information - to the target SNS topic. - Author: Trend Micro Cloud One File Storage Security +Description: According to the scan result from the scanner, publish the malware information to the target SNS topic. Parameters: - TargetSnsTopicName: - Type: String - Description: The name for the SNS topic to which malware information publish. - PublishMalwareLambdaName: - Type: String - Description: The name for the lambda function publishes the malware information to SNS topic. - PublishMalwarePolicyName: - Type: String - Description: The name for the policy includes sns and account authority. - PublishMalwareRoleName: + Prefix: Type: String - Description: The name for the role to execute the lambda function. + Description: Prefix string for the resources name. ScanResultTopicARN: Type: String Description: The ARN of the scan result SNS topic in storage stack. + TargetSnsTopicArn: + Type: String + Description: The ARN for the SNS topic to which malware information publish. Will create a new SNS Topic if this value is empty. + Default: '' + +Conditions: + NeedCreateNewSnsTopic: !Equals + - !Ref TargetSnsTopicArn + - '' + Resources: TargetSnsTopic: Type: AWS::SNS::Topic + Condition: NeedCreateNewSnsTopic Properties: - TopicName: !Ref TargetSnsTopicName + TopicName: !Join ["-", [!Ref Prefix, !Ref AWS::Region, "malware-plugin"]] DisplayName: Malware notification PublishMalwarePolicy: Type: AWS::IAM::ManagedPolicy Properties: - ManagedPolicyName: !Ref PublishMalwarePolicyName + ManagedPolicyName: !Join ["-", [!Ref Prefix, !Ref AWS::Region, "malware-plugin"]] PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - - 'sns:TagResource' - - 'sns:Publish' - - 'account:GetAlternateContact' + - sns:Publish + - account:GetAlternateContact Resource: '*' PublishMalwareRole: Type: AWS::IAM::Role Properties: - RoleName: !Ref PublishMalwareRoleName + RoleName: !Join ["-", [!Ref Prefix, !Ref AWS::Region, "malware-plugin"]] AssumeRolePolicyDocument: Version: "2012-10-17" Statement: @@ -63,9 +56,8 @@ Resources: PublishMalwareLambda: Type: AWS::Lambda::Function Properties: - CodeUri: ./ - Handler: handler.lambda_handler - FunctionName: !Ref PublishMalwareLambdaName + Handler: index.lambda_handler + FunctionName: !Join ["-", [!Ref Prefix, !Ref AWS::Region, "malware-plugin"]] Runtime: python3.8 Timeout: 500 Role: !GetAtt @@ -73,8 +65,85 @@ Resources: - Arn Environment: Variables: - TARGET_SNS_ARN: !Ref TargetSnsTopic + TARGET_SNS_ARN: !If [NeedCreateNewSnsTopic, !Ref TargetSnsTopic, !Ref TargetSnsTopicArn, ] MemorySize: 128 + Code: + ZipFile: | + import os + import json + from datetime import datetime + from urllib.parse import urlparse + + import boto3 + + + def get_bucket_name(file_url): + + url = urlparse(file_url) + return url.hostname.split('.')[0] + + + def get_iso_str(ts): + + dt = datetime.fromtimestamp(ts) + return dt.isoformat() + + + def fetch_account_name(): + + account_client = boto3.client('account') + response = account_client.get_alternate_contact( + AlternateContactType='SECURITY' + ) + + return response['AlternateContact']['Name'] + + + def lambda_handler(event, context): + + target_sns_arn = os.environ['TARGET_SNS_ARN'] + + scan_results = [] + account_name = fetch_account_name() + + for record in event['Records']: + + print('record', record) + + # Message details from SNS event + message = json.loads(record['Sns']['Message']) + findings = message['scanning_result'].get('Findings') + + if not findings: + continue + + finding = findings[0] + + scan_results.append({ + 'bucket_name': get_bucket_name(message['file_url']), + 'account_name': account_name, + 'malware': finding['malware'], + 'malware_type': finding['type'], + 'time': get_iso_str(message['timestamp']) + }) + + print('scan_results', scan_results) + + sns_client = boto3.client('sns') + request_entries = [ + { + 'Message': json.dumps(scan_result), + 'Id': str(i) + } + for i, scan_result in enumerate(scan_results) + ] + + response = sns_client.publish_batch( + TopicArn=target_sns_arn, + PublishBatchRequestEntries=request_entries, + ) + + print(response) TopicSubscription: Type: AWS::SNS::Subscription Properties: @@ -86,5 +155,5 @@ Resources: Properties: FunctionName: !GetAtt PublishMalwareLambda.Arn Action: lambda:InvokeFunction - Principal: events.amazonaws.com + Principal: sns.amazonaws.com SourceArn: !Ref ScanResultTopicARN From e1eed5f6feb3f05bf0c2de4b057946194d3269d2 Mon Sep 17 00:00:00 2001 From: Hundao Date: Thu, 28 Jul 2022 14:52:51 +0800 Subject: [PATCH 5/6] refine PR --- .../Makefile | 2 +- .../README.md | 29 +++-- .../handler.py | 22 +++- .../template.yml | 101 +++--------------- 4 files changed, 52 insertions(+), 102 deletions(-) diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/Makefile b/post-scan-actions/aws-python-publish-malware-to-sns/Makefile index 5f12b448..9a33956a 100644 --- a/post-scan-actions/aws-python-publish-malware-to-sns/Makefile +++ b/post-scan-actions/aws-python-publish-malware-to-sns/Makefile @@ -13,7 +13,7 @@ create-target-sns-topic: create-publish-malware-policy: aws iam create-policy \ --policy-name $(PUBLISH_MALWARE_POLICY_NAME) \ - --policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"VisualEditor0\",\"Effect\":\"Allow\",\"Action\":[\"sns:TagResource\",\"sns:Publish\",\"account:GetAlternateContact\"],\"Resource\":\"*\"}]}" + --policy-document "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"VisualEditor0\",\"Effect\":\"Allow\",\"Action\":[\"sns:Publish\",\"account:GetAlternateContact\"],\"Resource\":\"*\"}]}" create-publish-malware-role: aws iam create-role \ diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/README.md b/post-scan-actions/aws-python-publish-malware-to-sns/README.md index 0c001a17..2dbd19c2 100644 --- a/post-scan-actions/aws-python-publish-malware-to-sns/README.md +++ b/post-scan-actions/aws-python-publish-malware-to-sns/README.md @@ -12,15 +12,26 @@ After a scan occurs, this example Lambda function publish the malware informatio ## Installation -### From Cloudformation Template - -1. Visit AWS cloudformation console. -2. Click **Create Stack**. -3. Upload `template.yml` in this folder. -4. Fill in the paramters. -5. Click **Next**. -6. Check the require access capabilities checkboxes. -7. Click **Create Stack**. +### From SAM CLI + +```bash +sam deploy \ +--stack-name \ +--capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_NAMED_IAM \ +--region \ +--s3-bucket \ +--template-file template.yml \ +--parameter-overrides \ +ParameterKey=TargetSnsTopicArn,ParameterValue= \ +ParameterKey=ScanResultTopicARN,ParameterValue= +``` + +- where: + - `` is the stack name for this plugin. + - `` is the building AWS region. + - `` is the template put in. + - `` is the malware information published. + - `` is the SNS topic ARN from the storage stack. ### From Makefile diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/handler.py b/post-scan-actions/aws-python-publish-malware-to-sns/handler.py index 2a1bf024..04723db3 100644 --- a/post-scan-actions/aws-python-publish-malware-to-sns/handler.py +++ b/post-scan-actions/aws-python-publish-malware-to-sns/handler.py @@ -28,6 +28,12 @@ def fetch_account_name(): return response['AlternateContact']['Name'] +def divide_to_chunks(iterable_collection, size): + + for i in range(0, len(iterable_collection), size): + yield iterable_collection[i:i + size] + + def lambda_handler(event, context): target_sns_arn = os.environ['TARGET_SNS_ARN'] @@ -59,6 +65,7 @@ def lambda_handler(event, context): print('scan_results', scan_results) sns_client = boto3.client('sns') + fails = [] request_entries = [ { 'Message': json.dumps(scan_result), @@ -67,9 +74,14 @@ def lambda_handler(event, context): for i, scan_result in enumerate(scan_results) ] - response = sns_client.publish_batch( - TopicArn=target_sns_arn, - PublishBatchRequestEntries=request_entries, - ) + for entries_chunk in divide_to_chunks(request_entries, 10): + response = sns_client.publish_batch( + TopicArn=target_sns_arn, + PublishBatchRequestEntries=entries_chunk, + ) + + fails += response['Failed'] - print(response) + if fails: + print(fails) + raise ValueError('fail to publish sns.') diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/template.yml b/post-scan-actions/aws-python-publish-malware-to-sns/template.yml index d22aa547..31ffc64f 100644 --- a/post-scan-actions/aws-python-publish-malware-to-sns/template.yml +++ b/post-scan-actions/aws-python-publish-malware-to-sns/template.yml @@ -1,10 +1,8 @@ AWSTemplateFormatVersion: 2010-09-09 +Transform: AWS::Serverless-2016-10-31 Description: According to the scan result from the scanner, publish the malware information to the target SNS topic. Parameters: - Prefix: - Type: String - Description: Prefix string for the resources name. ScanResultTopicARN: Type: String Description: The ARN of the scan result SNS topic in storage stack. @@ -23,12 +21,10 @@ Resources: Type: AWS::SNS::Topic Condition: NeedCreateNewSnsTopic Properties: - TopicName: !Join ["-", [!Ref Prefix, !Ref AWS::Region, "malware-plugin"]] DisplayName: Malware notification PublishMalwarePolicy: Type: AWS::IAM::ManagedPolicy Properties: - ManagedPolicyName: !Join ["-", [!Ref Prefix, !Ref AWS::Region, "malware-plugin"]] PolicyDocument: Version: "2012-10-17" Statement: @@ -40,7 +36,6 @@ Resources: PublishMalwareRole: Type: AWS::IAM::Role Properties: - RoleName: !Join ["-", [!Ref Prefix, !Ref AWS::Region, "malware-plugin"]] AssumeRolePolicyDocument: Version: "2012-10-17" Statement: @@ -54,12 +49,12 @@ Resources: - !Ref PublishMalwarePolicy - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole PublishMalwareLambda: - Type: AWS::Lambda::Function + Type: AWS::Serverless::Function Properties: - Handler: index.lambda_handler - FunctionName: !Join ["-", [!Ref Prefix, !Ref AWS::Region, "malware-plugin"]] + CodeUri: ./ + Handler: handler.lambda_handler Runtime: python3.8 - Timeout: 500 + Timeout: 30 Role: !GetAtt - PublishMalwareRole - Arn @@ -67,89 +62,21 @@ Resources: Variables: TARGET_SNS_ARN: !If [NeedCreateNewSnsTopic, !Ref TargetSnsTopic, !Ref TargetSnsTopicArn, ] MemorySize: 128 - Code: - ZipFile: | - import os - import json - from datetime import datetime - from urllib.parse import urlparse - - import boto3 - - - def get_bucket_name(file_url): - - url = urlparse(file_url) - return url.hostname.split('.')[0] - - - def get_iso_str(ts): - - dt = datetime.fromtimestamp(ts) - return dt.isoformat() - - - def fetch_account_name(): - - account_client = boto3.client('account') - response = account_client.get_alternate_contact( - AlternateContactType='SECURITY' - ) - - return response['AlternateContact']['Name'] - - - def lambda_handler(event, context): - - target_sns_arn = os.environ['TARGET_SNS_ARN'] - - scan_results = [] - account_name = fetch_account_name() - - for record in event['Records']: - - print('record', record) - - # Message details from SNS event - message = json.loads(record['Sns']['Message']) - findings = message['scanning_result'].get('Findings') - - if not findings: - continue - - finding = findings[0] - - scan_results.append({ - 'bucket_name': get_bucket_name(message['file_url']), - 'account_name': account_name, - 'malware': finding['malware'], - 'malware_type': finding['type'], - 'time': get_iso_str(message['timestamp']) - }) - - print('scan_results', scan_results) - - sns_client = boto3.client('sns') - request_entries = [ - { - 'Message': json.dumps(scan_result), - 'Id': str(i) - } - for i, scan_result in enumerate(scan_results) - ] - - response = sns_client.publish_batch( - TopicArn=target_sns_arn, - PublishBatchRequestEntries=request_entries, - ) - - print(response) TopicSubscription: Type: AWS::SNS::Subscription Properties: Protocol: lambda Endpoint: !GetAtt PublishMalwareLambda.Arn TopicArn: !Ref ScanResultTopicARN + DeliveryPolicy: + healthyRetryPolicy: + numRetries: 6 + minDelayTarget: 5 + maxDelayTarget: 60 + numMinDelayRetries: 2 + numMaxDelayRetries: 2 + numNoDelayRetries: 2 + backoffFunction: exponential InvokedLambdaPermission: Type: AWS::Lambda::Permission Properties: From 22bf28876077e371629b7b6a73c598a15043c0ff Mon Sep 17 00:00:00 2001 From: Hundao Date: Thu, 28 Jul 2022 18:16:48 +0800 Subject: [PATCH 6/6] refine PR --- .../aws-python-publish-malware-to-sns/handler.py | 1 - .../aws-python-publish-malware-to-sns/template.yml | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/handler.py b/post-scan-actions/aws-python-publish-malware-to-sns/handler.py index 04723db3..dab8c965 100644 --- a/post-scan-actions/aws-python-publish-malware-to-sns/handler.py +++ b/post-scan-actions/aws-python-publish-malware-to-sns/handler.py @@ -84,4 +84,3 @@ def lambda_handler(event, context): if fails: print(fails) - raise ValueError('fail to publish sns.') diff --git a/post-scan-actions/aws-python-publish-malware-to-sns/template.yml b/post-scan-actions/aws-python-publish-malware-to-sns/template.yml index 31ffc64f..0af2d112 100644 --- a/post-scan-actions/aws-python-publish-malware-to-sns/template.yml +++ b/post-scan-actions/aws-python-publish-malware-to-sns/template.yml @@ -53,14 +53,14 @@ Resources: Properties: CodeUri: ./ Handler: handler.lambda_handler - Runtime: python3.8 + Runtime: python3.9 Timeout: 30 Role: !GetAtt - PublishMalwareRole - Arn Environment: Variables: - TARGET_SNS_ARN: !If [NeedCreateNewSnsTopic, !Ref TargetSnsTopic, !Ref TargetSnsTopicArn, ] + TARGET_SNS_ARN: !If [ NeedCreateNewSnsTopic, !Ref TargetSnsTopic, !Ref TargetSnsTopicArn ] MemorySize: 128 TopicSubscription: Type: AWS::SNS::Subscription