Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions post-scan-actions/aws-python-publish-malware-to-sns/Makefile
Original file line number Diff line number Diff line change
@@ -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: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 \
Comment on lines +36 to +37

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are not matched with ones in the template. Why?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will align them in the next commit.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The runtime is not aligned still.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the lost, fixed already.

--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
122 changes: 122 additions & 0 deletions post-scan-actions/aws-python-publish-malware-to-sns/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# 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 SAM CLI

```bash
sam deploy \
--stack-name <YOUR_STACK_NAME> \
--capabilities CAPABILITY_AUTO_EXPAND CAPABILITY_NAMED_IAM \
--region <YOUR_REGION> \
--s3-bucket <YOUR_S3_BUCKET> \
--template-file template.yml \
--parameter-overrides \
ParameterKey=TargetSnsTopicArn,ParameterValue=<YOUR_TARGET_TOPIC_ARN> \
ParameterKey=ScanResultTopicARN,ParameterValue=<SCAN_RESULT_TOPIC_ARN>
```

- where:
- `<YOUR_STACK_NAME>` is the stack name for this plugin.
- `<YOUR_REGION>` is the building AWS region.
- `<YOUR_S3_BUCKET>` is the template put in.
- `<YOUR_TARGET_TOPIC_ARN>` is the malware information published.
- `<SCAN_RESULT_TOPIC_ARN>` is the SNS topic ARN from the storage 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=<YOUR_TARGET_SNS_TOPIC_NAME> \
make create-target-sns-topic
```

- where:
- `<YOUR_TARGET_SNS_TOPIC_NAME>` is the name for the new SNS topic which cloud be published the walmare information.

2. **Create Required Policy**

```bash
PUBLISH_MALWARE_POLICY_NAME=<YOUR_PUBLISH_MALWARE_POLICY_NAME> \
make create-publish-malware-policy
```

- where
- `<YOUR_PUBLISH_MALWARE_POLICY_NAME>` is the name for the new policy.

3. **Create Required Role**

```bash
PUBLISH_MALWARE_POLICY_NAME=<YOUR_PUBLISH_MALWARE_ROLE_NAME> \
make create-publish-malware-role
```

- where
- `<YOUR_PUBLISH_MALWARE_ROLE_NAME>` is the name for the new role.

4. **Attach Policy**

```bash
PUBLISH_MALWARE_ROLE_NAME=<YOUR_PUBLISH_MALWARE_ROLE_NAME> \
PUBLISH_MALWARE_POLICY_ARN=<YOUR_PUBLISH_MALWARE_POLICY_ARN> \
make create-publish-malware-role
```

- where
- `<YOUR_PUBLISH_MALWARE_POLICY_ARN>` is the policy ARN created from step 2.
- `<YOUR_PUBLISH_MALWARE_ROLE_NAME>` is the role name created from step 3.

5. **Create Lambda Function**

```bash
PUBLISH_MALWARE_LAMBDA_NAME=<YOUR_PUBLISH_MALWARE_LAMBDA_NAME> \
PUBLISH_MALWARE_ROLE_ARN=<YOUR_PUBLISH_MALWARE_ROLE_ARN> \
TARGET_SNS_TOPIC_ARN=<YOUR_TARGET_SNS_TOPIC_ARN> \
make create-function
```

- where
- `<YOUR_TARGET_SNS_TOPIC_ARN>` is the SNS topic ARN created from step 1.
- `<YOUR_PUBLISH_MALWARE_ROLE_ARN>` is the role ARN created from step 3.
- `<YOUR_PUBLISH_MALWARE_LAMBDA_NAME>` is the name for new lambda function.

6. **SNS Subscrition**

```bash
SCAN_RESULT_TOPIC_ARN=<YOUR_SCAN_RESULT_TOPIC_ARN> \
PUBLISH_MALWARE_LAMBDA_ARN=<YOUR_PUBLISH_MALWARE_LAMBDA_ARN> \
REGION=<YOUR_REGION> \
make subscribe-to-sns-topic
```

- where
- `<YOUR_PUBLISH_MALWARE_LAMBDA_ARN>` is the lambda function ARN created from step 5.
- `<YOUR_SCAN_RESULT_TOPIC_ARN>` is the SNS topic ARN from the storage stack.
- `<YOUR_REGION>` is the building AWS region.

7. **Add Lambda Permission**

```bash
PUBLISH_MALWARE_LAMBDA_NAME=<YOUR_PUBLISH_MALWARE_LAMBDA_NAME> \
REGION=<YOUR_REGION> \
SCAN_RESULT_TOPIC_ARN=<YOUR_SCAN_RESULT_TOPIC_ARN> \
make add-lambda-permission
```

- where
- `<YOUR_PUBLISH_MALWARE_LAMBDA_NAME>` is the lambda function and created from step 5.
- `<YOUR_REGION>` is the building AWS region.
- `<SCAN_RESULT_TOPIC_ARN>` is the SNS topic ARN from the storage stack.
86 changes: 86 additions & 0 deletions post-scan-actions/aws-python-publish-malware-to-sns/handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
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 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']

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')
fails = []
request_entries = [
{
'Message': json.dumps(scan_result),
'Id': str(i)
}
for i, scan_result in enumerate(scan_results)
]

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']

if fails:
print(fails)
86 changes: 86 additions & 0 deletions post-scan-actions/aws-python-publish-malware-to-sns/template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
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:
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:
DisplayName: Malware notification
PublishMalwarePolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- sns:Publish
- account:GetAlternateContact
Resource: '*'
PublishMalwareRole:
Type: AWS::IAM::Role
Properties:
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::Serverless::Function
Properties:
CodeUri: ./
Handler: handler.lambda_handler
Runtime: python3.9
Timeout: 30
Role: !GetAtt
- PublishMalwareRole
- Arn
Environment:
Variables:
TARGET_SNS_ARN: !If [ NeedCreateNewSnsTopic, !Ref TargetSnsTopic, !Ref TargetSnsTopicArn ]
MemorySize: 128
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:
FunctionName: !GetAtt PublishMalwareLambda.Arn
Action: lambda:InvokeFunction
Principal: sns.amazonaws.com
SourceArn: !Ref ScanResultTopicARN