AWS Public Sector Blog

Automate security orchestration in AWS Security Hub with Trend Micro Cloud One

Security analysts are suffering from alert fatigue as breaches and bad actors become more prevalent. As organizations mature in their cybersecurity capabilities, they are looking to try and leverage automation to reduce the operational burden of alerting, detecting, and responding to threats.

Organizations need a holistic view of their environment, facilitated by using multiple security services. Frequent attacks occur within the public sector targeting critical functions like elections, public services like waste water or recycling services, Criminal Justice Information Services (CJIS), and Health and Human Services (HHS) to name a few. Many security teams within these government organizations are making use of third-party tools such as Amazon Web Services (AWS) Partner Trend Micro’s Cloud One, in addition to native AWS security tools like Amazon GuardDuty and AWS Security Hub, in an effort to detect and respond to these types of attacks.

This blog post walks you through how to combine the findings from these disparate systems into a single operational view, so we can build a security information and event management (SIEM)-like platform with security orchestration automation and response (SOAR) capabilities, with the goal of reducing the security operations (SecOps) burden. This helps analysts identify, respond, and remediate existing threats while maintaining a dynamic response platform that scales with their environment.

Prerequisites

1. You must have an existing AWS account.

2. You must be currently using AWS Security Hub and subscribed to Trend Micro Cloud One (Workload Security). There are other services and AWS Partner offerings that provide workload security monitoring, but for the purposes of this blog, we will demonstrate how to integrate with the offering from Trend Micro Cloud One.

Solution overview

Figure 1. Solution overview.

As seen in the Figure 1:

1. Trend Micro Cloud One sends workload security findings as an email to an Amazon Simple Notification Service (Amazon SNS) topic.

2. The Amazon SNS topic triggers an AWS Lambda function.

3. The Lambda function extracts and converts findings to Amazon Security Finding Format (ASFF) and adds to AWS Security Hub findings.

4. The Security Hub automatically sends all new findings and all updates to existing findings to Amazon EventBridge as EventBridge events.

5. The EventBridge triggers an automated response on Trend Micro Events in the form of a Lambda execution, automated quarantine of compromised Amazon Elastic Compute Cloud (Amazon EC2) instances using Security Groups, AWS Systems Manager automation, Amazon SNS topic, or in the case of this blog post, creating an Amazon Machine Image (AMI) of the compromised instance for future investigation.

Procedure

1. Log into the AWS Management Console and navigate to the Amazon SNS console. Create a Standard Amazon SNS topic. In this blog post, we named the Amazon SNS topic TrendMicroEventForwarding.

 

Figure 2. Create a standard Amazon SNS Topic.

2. From the AWS Identity and Access Management (IAM) Console, create an IAM User with programmatic access and ability to publish to the newly created Amazon SNS topic.

3. Download the CSV containing the access key ID and secret key.

Figure 3. Creating a user with programmatic access.

4. Create an IAM Policy that explicitly allows this IAM user to publish to the previously created Amazon SNS topic.

Figure 4. Creating an IAM policy with ability to publish.

5. Log in to Trend Micro Cloud One and configure event forwarding to Amazon SNS:

a. From Administration select Event Forwarding, then check the box for Amazon SNS and then select Enter IAM Credentials.

b. Select Event types to forward by checking the boxes.

Figure 5. Configuring event forwarding in the Trend Micro Cloud One console.

6. Enter in the Access Key and the Secret Access Key of the newly created IAM User from the previously downloaded CSV into their respective fields.

7. Enter in the Amazon Resource Name (ARN) of the Amazon SNS Topic you created earlier. Note: ARN can be found by going back to the Amazon SNS console and finding your newly created topic.

8. You can test that the credentials work properly by selecting: Test credentials and send notification.

Figure 6. A successful credential test reads “Amazon SNS credentials have been verified. A test notification has been sent with EventType: ‘TestSNS’.

9. Back in your AWS account, create an IAM Role (we suggest the name asff_write_to_security_hub_role) that has the ability to import findings into Security Hub granted by an IAM policy like the following:

Figure 7. IAM role assigned to Lambda function.

10. Create a Lambda function named asff_write_to_security_hub using the following code example, which is designed to convert Trend Micro Cloud One findings to Amazon Security Finding Format (ASFF) and write them directly to Security Hub:

import datetime
import json
import os
import boto3
from botocore.retries.standard import RetryPolicy

def generate_finding_title(title):
    return "Trend Micro: {}".format(title)

def verify_required_properties(ws_event):
    print("Entering verify_required_properties")
    result = True
    required_properties = [
        'HostOwnerID', 
        'HostInstanceID', 
        'TenantID', 
        'EventID', 
        "EventType", 
        'LogDate', 
        'HostAssetValue', 
        'HostGroupID', 
        'HostGroupName', 
        'HostID',
        'Hostname', 
        'HostSecurityPolicyID', 
        'HostSecurityPolicyName'
        ]
    for prop in required_properties:
        if not prop in ws_event:
            result = False
            print("Exiting verify_required_properties")
            return result
        

def select_asff_eventType(EventType, types):
    print("Entering select_asff_eventType")
    if(EventType == 'PacketLog'):
        types.append("Unusual Behaviors/Network Flow")
    elif(EventType == 'IntegrityEvent'):
        types.append("Unusual Behaviors/VM")
    elif(EventType == 'LogInspectionEvent' or EventType == 'PayloadLog'):
        types.append("Unusual Behaviors/VM")
        types.append("Unusual Behaviors/Application")
    elif(EventType == 'WebReputationEvent' or EventType == 'AntiMalwareEvent'):
        types.append("TPPs/Execution")
    print("Exiting select_asff_eventType")
    return types

def antimalwareStatusAction(action):
    print("Entering antimalwareStatusAction")
    state = ""
    if action == "Cleaned" or action == "Deleted":
        state = "REMOVED"
    elif action == "Quarantined" or action == "Access Denied":
        state = "OBSERVED"
    else:
        state = "REMOVAL_FAILED"
    print("Exiting antimalwareStatusAction")
    return state
        
def addAdditionalInformation(Event, finding):
    print("Entering addAdditionalInformation")
    if 'SystemEvent' in Event["EventType"]:
        pass
    if "PacketLog" in Event["EventType"]:
        finding['Severity']['Product'] = 0
        finding['Severity']['Normalized'] = int(20)
        select_asff_eventType(Event["EventType"], finding["Types"])
        finding['Title'] = "Trend Micro: Repeated attempted network connection on instance {}".format(Event['HostInstanceID'])
    if "PayloadLog" in Event["EventType"]:
        if 'Severity' in Event:
            finding['Severity']['Product'] = int(Event['Severity'])
            finding['Severity']['Normalized'] = int(int(Event['Severity']) * 17.5)
        select_asff_eventType(Event["EventType"], finding["Types"])
        finding['Title'] = "Trend Micro: Rule [{}] triggered".format(Event['Reason'])
    if "AntiMalwareEvent" in Event["EventType"]:
        finding['Malware'] = [
            {
                "Name": Event['MalwareName'],
                "Path": Event['InfectedFilePath'],
                "State": antimalwareStatusAction(Event['ScanResultString']),
                }
            ]
        if Event['ScanResultString'] == "Cleaned" or Event['ScanResultString'] == "Deleted":
            finding['Severity']['Label'] = "INFORMATIONAL"
        elif Event['ScanResultString'] == "Quarantined":
            finding['Severity']['Label'] = "LOW"
        else: 
            finding['Severity']['Label'] = "MEDIUM"
        select_asff_eventType(Event["EventType"], finding["Types"])
        finding['Title'] = "Malware [{}] detected".format(Event['MalwareName'])
    if "WebReputationEvent" in Event["EventType"]:
        if 'Risk' in Event:
            finding['Severity']['Product'] = int(Event['Risk'])
            finding['Severity']['Normalized'] = int(int(Event['Risk']) * 17.5)
        select_asff_eventType(Event["EventType"], finding["Types"])
        finding['Title'] = "High risk web request to IP [{}]".format(Event['TargetIP'])
    if "IntegrityEvent" in Event["EventType"]:
        if 'Severity' in Event:
            finding['Severity']['Product'] = int(Event['Severity'])
            finding['Severity']['Normalized'] = int(int(Event['Severity']) * 17.5)
        select_asff_eventType(Event["EventType"], finding["Types"])
        finding['Title'] = "Unexpected change to object [{}]".format(Event['Key'])
    if "LogInspectionEvent" in Event["EventType"]:
        if 'OSSEC_Level' in Event:
            finding['Severity']['Product'] = int(Event['OSSEC_Level'])
            if int(Event['OSSEC_Level']) >= 13:
                finding['Severity']['Normalized'] = int(int(Event['OSSEC_Level']) * 6.5)
            else:
                finding['Severity']['Normalized'] = int(int(Event['OSSEC_Level']) * 5)
        select_asff_eventType(Event["EventType"], finding["Types"])
        finding['Title'] = Event['OSSEC_Description']
    if "AppControlEvent" in Event["EventType"]:
        finding['Types'].append("Unusual Behaviors/Application")
    if 'Tags' in Event:
        finding['ProductFields']['trend-micro:Tags'] = Event['Tags']
    if 'OriginString' in Event:
        finding['ProductFields']['trend-micro:Origin'] = Event['OriginString']
    print("Exiting addAdditionalInformation")
    return finding

def workload_security_event_to_asff(ws_event, region, awsaccountid):
    print("Entering workload_security_event_to_asff")
    event_types = {
        'SystemEvent': 'system',
        'PacketLog': 'firewall',
        'PayloadLog': 'intrusionprevention',
        'AntiMalwareEvent': 'antimalware',
        'WebReputationEvent': 'webreputation',
        'IntegrityEvent': 'integrity',
        'LogInspectionEvent': 'log',
        'AppControlEvent': 'applicationcontrol'
        }

    finding = {
        "SchemaVersion": "2018-10-08",
        "Id": ws_event["UniqueID"],
        #"Id": "2021-07-13-15-57-19-000-us-east-1-123-3",
        #"Id": "us-east-1/664859491917/98aebb2207407c87f51e89943f12b1ef2",
        #"Id": "us-east-1/664859491917/2c945051a0219e847a8d8a73c2ca6c62",
        "ProductArn": f"arn:aws:securityhub:{region}:{awsaccountid}:product/{awsaccountid}/default",
        "GeneratorId": "trend-micro-workload-security-{}".format(event_types[ws_event["EventType"]]),
        "AwsAccountId": awsaccountid,
        "Types": [
            ],
        "CreatedAt": ws_event['LogDate'],
        "UpdatedAt": datetime.datetime.utcnow().isoformat("T") + "Z",
        "Severity": {
            "Product": 0,
            "Normalized": 0
            },
        "ProductFields": {
            'ProviderName': "Trend Micro Cloud One",
            "ProviderVersion": "20",
            'trend-micro:TenantName': ws_event['TenantName'] if 'TenantName' in ws_event else '',
            'trend-micro:TenantID': str(ws_event['TenantID']) if 'TenantID' in ws_event else '',
            'trend-micro:EventID': str(ws_event['EventID']) if 'EventID' in ws_event else '',
            'trend-micro:HostAssetValue': str(ws_event['HostAssetValue']) if 'HostAssetValue' in ws_event else '',
            'trend-micro:HostGroupID': str(ws_event['HostGroupID']) if 'HostGroupID' in ws_event else '',
            'trend-micro:HostGroupName': ws_event['HostGroupName'] if 'HostGroupName' in ws_event else '',
            'trend-micro:HostID': str(ws_event['HostID']) if 'HostID' in ws_event else '',
            'trend-micro:HostInstanceID': str(ws_event['HostInstanceID']) if 'HostInstanceID' in ws_event else '',
            'trend-micro:Hostname': ws_event['Hostname'] if 'Hostname' in ws_event else '',
            'trend-micro:HostSecurityPolicyID': str(ws_event['HostSecurityPolicyID']) if 'HostSecurityPolicyID' in ws_event else '',
            'trend-micro:HostSecurityPolicyName': ws_event['HostSecurityPolicyName'] if 'HostSecurityPolicyName' in ws_event else '',
            'trend-micro:Origin' : ws_event['OriginString'] if 'OriginString' in ws_event else ''
            },
        "Description": "Workload Security Event, type: {}".format(event_types[ws_event["EventType"]]),
        "Resources": [
            {
                "Type": "AwsEc2Instance",
                "Id":  ws_event['HostInstanceID'] if 'HostInstanceID' in ws_event else ''
                }
            ],
        "Title": "Cloud One Workload Security push the following event type: {} for HostName: {}".format(event_types[ws_event["EventType"]], ws_event['Hostname'] if 'Hostname' in ws_event else ''),
        }
    converted_event = addAdditionalInformation(ws_event, finding)
    print("Exiting workload_security_event_to_asff")
    return converted_event

def lambda_handler(event, context):
    total_events = 0
    saved_events = 0
    securityhub = boto3.client("securityhub")
    region = boto3.session.Session().region_name
    awsaccountid = boto3.client("sts").get_caller_identity()["Account"]
    print(json.dumps(event))
    if 'Records' in event:
        for e in event['Records']:
            if 'EventSource' in e and e['EventSource'] == 'aws:sns':
                print("Amazon SNS message received")
                if 'Sns' in e:
                    ws_events = None
                    try:
                        ws_events = json.loads(e['Sns']['Message'])
                    except Exception as err:
                        print("Could not extract the Workload Security event(s) from the SNS message. Threw exception:\n{}".format(err))
                    aff_events = []
                    if ws_events:
                        print("Found {} Workload Security events...processing".format(len(ws_events)))
                        for ws_event in ws_events:
                            """if('HostInstanceID' in ws_event):"""
                            total_events += 1
                            if not ws_event["EventType"] == 'SystemEvent' or verify_required_properties(ws_event):
                                aff_event = workload_security_event_to_asff(ws_event=ws_event, region=region, awsaccountid=awsaccountid)
                                aff_events.append(aff_event)
                                print(aff_event)
                            else: print("Specified event does not have the required properties to properly process it")
                    if len(aff_events) > 0:
                        print("About to call security hub batch import")
                        response = securityhub.batch_import_findings(Findings=aff_events)
                        print("Security hub batch import completed")
                        print(json.dumps(response))
        return {
            'total_events': total_events,
            'saved_events': saved_events,
            'issues': (total_events - saved_events)
            }

Figure 8. Writing the Lambda function code to Security Hub.

11. Attach the asff_write_to_security_hub_role to the newly created Lambda function.

12. Set the Lambda function to initiate on the SNS topic you created earlier (ours is named TrendMicroEventForwarding). You can do this by selecting your Lambda function, selecting the Add Trigger box as shown in Figure 9, and selecting the Amazon SNS Topic.

Figure 9. Adding a trigger to the Lambda function.

Verify and complete service integration to Amazon EventBridge

1. View Trend Micro findings in Security Hub.

a. Using the Trend Micro Workload Security Demo instance, we generated a Cross Site Scripting test event and successfully forwarded it to Security Hub.

Figure 10. Trend Micro event as seen in Security Hub.

2. To forward the received event details to EventBridge, create a custom action in Security Hub.

3. To create a custom action, in the Security Hub console, select Setting, then select Customs actions tab, then the Create custom action button as shown in Figure 11.

Figure 11. Creating a custom action in the Security Hub console.

4. After selecting the Create custom action button, you are presented with the screen shown in Figure 12. Give your custom action a name, an optional description, and a custom action ID of your choosing, then select Create custom action.

Figure 12. Creating a custom action.

5. After the custom action is created you see it listed in the Custom actions pane. Take note of the Custom action ARN of the newly created action.

6. From the AWS Management Console, move over to EventBridge.

7. Select Rules, then Create rule.

Figure 13. The EventBridge console interface.

8. In the Create rule window (Figure 14), add the following:

a. Give the rule a name and description (optional).
b. In the Event matching pattern section, select Pre-defined pattern by service.
c. In the Service provider dropdown, select AWS.
d. In the Service Name dropdown, select Security Hub.
e. Select the radio button for Specific custom action ARN(s).
f. Paste in the ARN from the custom action you created earlier.

Figure 14. Creating an EventBridge rule.

g. In the Select targets section (Figure 15), select SSM Automation.
h. From the Document section, select AWS-CreateImage.
i. Select the radio button for Input Transformer. In the top box enter: {“InstanceId”:“$.detail.findings[0].Resources[0].Id’} and in the bottom box enter: {“InstanceId”:[<InstanceId>],“NoReboot”:[“true”]}
j. Leave all other options with their default values and click Create.
k. Add a comment.
l. Select Create.

Figure 15. Selecting targets for the EventBridge rule.

End to end event testing

To test that everything is now working, go back to the Security Hub console, and:

1. Select a Trend Micro finding;

2. Select the Actions button; and

3. Select your custom action from the list.

Figure 16. Custom action shown in action dropdown box.

If everything has been properly configured, you should see an AMI being created in the Amazon EC2 Console.

Figure 17. AMI being created.

Conclusion

In this blog post, you walked through how to combine the findings from disparate security systems into one automated, operational view, to reduce the burden of security teams. This is just one of many custom actions that can be taken. Using the same method, it’s also possible to:

  • Isolate instances, create a snapshot of Amazon Elastic Block Store (Amazon EBS) volumes, integrate with a third party, and more.
  • Use workflow driven automated remediation (i.e. Lambda, EventBridge, AWS Step Functions), like:
    • Security Operations Center (SOC)/Intrusion Prevention Engineering (IPE) and others who may need to be alerted and/or provide approvals in the workflow process before an action, like quarantining via restrictive security group, can be taken; or
    • Intrusion Detection System (IDS) / Intrusion Prevention System (IPS) on-premises toolset integrations.

Read more technical walkthroughs on the public sector blog. For help with this procedure, reach out to your account manager, or contact us directly.


Subscribe to the AWS Public Sector Blog newsletter to get the latest in AWS tools, solutions, and innovations from the public sector delivered to your inbox, or contact us.

The AWS Public Sector Blog needs your help. Please take a few minutes to share insights regarding your experience with the AWS Public Sector Blog in this survey, and we’ll use feedback from the survey to create more content aligned with the preferences of our readers.

Grant Joslyn

Grant Joslyn

Grant Joslyn is a solutions architect for the US state and local government public sector team at Amazon Web Services (AWS). He specializes in end user compute and cloud automation. He provides technical and architectural guidance to customers building secure solutions on AWS. He is a subject matter expert and thought leader for strategic initiatives that help customers embrace DevOps practices.

Joseph Sadler

Joseph Sadler

Joseph is a senior solutions architect on the Worldwide Public Sector team at Amazon Web Services (AWS), specializing in cybersecurity and machine learning (ML). With public and private sector experience, he has expertise in cloud security, artificial intelligence (AI), threat detection, and incident response. His diverse background helps him architect robust, secure solutions that leverage cutting-edge technologies to safeguard mission-critical systems.

Robert Hall

Robert Hall

Robert Hall is a solutions architect for the US state and local government public sector team within Amazon Web Services (AWS) and has been working for AWS since 2016. Prior to AWS, he worked as an IT security specialist within the global risk management function of a large aerospace company where he performed network and application penetration testing; cloud, mobile, and M&A security risk assessments; and critical infrastructure risk management projects.