diff --git a/README.md b/README.md index 89b284f..b64d2a5 100644 --- a/README.md +++ b/README.md @@ -28,15 +28,22 @@ The design is: ## Deployment -### Configure Deep Security to Send Events to Amazon SNS - -To configure Deep Security Manager to send all events to Amazon SNS, follow the steps in the [Deep Security Help Center](https://help.deepsecurity.trendmicro.com/sns.html). - -By default, this configuration sends all Deep Security events to the specified Amazon SNS topic. You can [filter what events are sent](https://help.deepsecurity.trendmicro.com/Events-Alerts/sns-json-config.html) using a simple JSON policy language (very similar to AWS IAM). - -This integration only uses a subset of Deep Security events. Essentially only sending critical and high severity events to AWS Security Hub by default. This class of events is more closely related to the core concept of an AWS Security Hub finding. - -**Caution:** If you use the Deep Security event policy language to prevent sending relevant events to an Amazon SNS topic, those events won't show up in the AWS Security Hub. This is unlikely to happen but something to be aware of if you're filtering the event stream outbound from your Deep Security installation. +### Create the code package + +For the lambda to work you must make sure you run python2.7 and boto3 >= 1.9.68! +This can be achieved by performing the following in this directory: +```bash +mkdir package +pip install boto3 --target package/ +cd package +zip -r9 ../lambdacode.zip . +cd ../ +zip -g lambdacode.zip lambda_function.py +``` +Now make the code available in a S3 bucket: +```bash +aws s3api put-object --body lambdacode.zip --key deepsecurity.zip --bucket +``` ### Configure AWS Security Hub @@ -44,20 +51,33 @@ AWS Security Hub is available as an open preview. Simply access the service from ![Enable AWS Security Hub](docs/enable-security-hub.png) -This will walk you through the initial process of setting up the required permissions and structures to support the AWS Security Hub. +This will walk you through the initial process of setting up the required permissions and structures to support the AWS Security Hub. Once that initial step is complete, you need to subscribe to Trend Micro's Deep Security in order to permit the service to receive events from your Deep Security installation. ![Subscribe to Trend Micro:Deep Security](docs/subscribe-to-deep-security.png) -### Configure the AWS Lambda Function +### Stack deployment +A [cloudformation template](cloudformation.yaml) has been provided to deploy most of the needed components. +```bash +aws cloudformation create-stack --stack-name --template-body file://cloudformation.yaml +``` +**parameters** +Default values are provided but should be customized -Using the CloudFormation template in this repository, you can easily deploy the required AWS Lambda function and assign the proper permissions via the AWS IAM execution role. +**sns topic** +The next stage will require you to send all events from Deep Security Manager to SNS. This stack has already created +the sns topic and the arn can be found in it's outputs. The user for the accesskey must still be created. -The code requires these permissions to run: +### Configure Deep Security to Send Events to Amazon SNS + +To configure Deep Security Manager to send all events to Amazon SNS, follow the steps in the [Deep Security Help Center](https://help.deepsecurity.trendmicro.com/sns.html). + +By default, this configuration sends all Deep Security events to the specified Amazon SNS topic. You can [filter what events are sent](https://help.deepsecurity.trendmicro.com/Events-Alerts/sns-json-config.html) using a simple JSON policy language (very similar to AWS IAM). + +This integration only uses a subset of Deep Security events. Essentially only sending critical and high severity events to AWS Security Hub by default. This class of events is more closely related to the core concept of an AWS Security Hub finding. -- read access to the target Amazon SNS topic that Deep Security is sending events to -- write access to the AWS Security Hub API, specifically the ImportFindings function calls +**Caution:** If you use the Deep Security event policy language to prevent sending relevant events to an Amazon SNS topic, those events won't show up in the AWS Security Hub. This is unlikely to happen but something to be aware of if you're filtering the event stream outbound from your Deep Security installation. ### Configuring AWS IAM Permissions @@ -107,15 +127,15 @@ In order to properly select events to send to the AWS Security Hub, this integra ## Support -This is an Open Source community project. Project contributors may be able to help, -depending on their time and availability. Please be specific about what you're +This is an Open Source community project. Project contributors may be able to help, +depending on their time and availability. Please be specific about what you're trying to do, your system, and steps to reproduce the problem. -For bug reports or feature requests, please -[open an issue](https://github.com/deep-security/serverless-kms-grants/issues). +For bug reports or feature requests, please +[open an issue](https://github.com/deep-security/serverless-kms-grants/issues). You are welcome to [contribute](#contribute). -Official support from Trend Micro is not available. Individual contributors may be +Official support from Trend Micro is not available. Individual contributors may be Trend Micro employees, but are not official support. ## Contribute @@ -127,4 +147,4 @@ We accept contributions from the community. To submit changes: 1. Make your changes. 1. Submit a pull request with an explanation of your changes or additions. -We will review and work with you to release the code. \ No newline at end of file +We will review and work with you to release the code. diff --git a/cloudformation.yaml b/cloudformation.yaml new file mode 100644 index 0000000..722e1d4 --- /dev/null +++ b/cloudformation.yaml @@ -0,0 +1,123 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Create components for the TD integration' + +Parameters: + TopicName: + Description: The name for the sns topic that will receive the TD alerts + Type: String + Default: "deepsecurity-alerts" + IAMRoleName: + Description: Name for the role of the lambda + Type: String + Default: role-deepsecurity-securityhub-lambda + IAMPolName: + Description: Name for the policy attached to the role of the lambda + Type: String + Default: policy-deepsecurity-securityhub-lambda + BucketName: + Description: Name of the bucket in which the lambda code (zip) is stored + Type: String + Default: deepsecurity-bucket + LambdaName: + Type: String + Default: lambda-deepsecurity-securityhub + Description: Name of the lambda function + Owner: + Type: String + Default: john.doe@example.com + Description: Name of the owner of the application (You) + + +Resources: + # Role for the lambda function to use + IAMRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Principal: + Service: + - "lambda.amazonaws.com" + Action: + - "sts:AssumeRole" + RoleName: !Ref IAMRoleName + + # Policy for the lambda iam role + IAMPolicy: + Type: AWS::IAM::Policy + Properties: + Roles: + - !Ref IAMRole + PolicyDocument: + Version: "2012-10-17" + Statement: + # Statement to be able to log + - Effect: Allow + Action: + - "logs:*" + Resource: + - "*" + # Allow securityhub batch-import + - Effect: "Allow" + Action: + - "securityhub:BatchImportFindings" + Resource: + - "*" + # Allow sns + - Effect: "Allow" + Action: + - "sns:*" + Resource: + - !Ref SNSTopic + PolicyName: !Ref IAMPolName + + # Lambda function that will run the code to send the appropriate events to + # Security Hub + LambdaFunction: + Type: AWS::Lambda::Function + Properties: + Code: + S3Bucket: !Ref BucketName + S3Key: 'deepsecurity.zip' + Description: Filters events from deepsecurity and passes relevant ones to Security Hub + FunctionName: !Ref LambdaName + Handler: "lambda_handler" + MemorySize: 128 + Role: !GetAtt IAMRole.Arn + Runtime: "python2.7" + Timeout: 60 # Two minutes + Tags: + - Key: Name + Value: !Ref LambdaName + - Key: Owner + Value: !Ref Owner + - Key: Application + Value: "Deepsecurity" + + # SNS Topic to which Deep Security should send the alerts + SNSTopic: + Type: AWS::SNS::Topic + Properties: + DisplayName: !Ref TopicName + TopicName: !Ref TopicName + + TopicSubscription: + Type: "AWS::SNS::Subscription" + Properties: + Endpoint: !GetAtt LambdaFunction.Arn + Protocol: lambda + TopicArn: !Ref SNSTopic + +Outputs: + TopicArn: + Description: ARN of the sns topic created + Value: !Ref SNSTopic + Export: + Name: !Sub "${AWS::StackName}-TopicArn" + RoleArn: + Description: ARN of the iam role created + Value: !GetAtt IAMRole.Arn + Export: + Name: !Sub "${AWS::StackName}-RoleArn" diff --git a/send_deep_security_events_to_aws_security_hub.py b/send_deep_security_events_to_aws_security_hub.py index 0a7ccaf..9ca56c7 100644 --- a/send_deep_security_events_to_aws_security_hub.py +++ b/send_deep_security_events_to_aws_security_hub.py @@ -3,10 +3,13 @@ """ Select and convert important Deep Security events to Amazon Finding Format * Function runs as an AWS Lambda function triggers by an Amazon SNS topic -* Topic receives messages from Deep Security's Event Forwarding to Amazon SNS (ref: https://help.deepsecurity.trendmicro.com/sns.html?Highlight=sns) -* Each message should have one Deep Security event to evaluate but the code is robust enough to handle multiple events per message +* Topic receives messages from Deep Security's Event Forwarding to Amazon SNS +* (ref: https://help.deepsecurity.trendmicro.com/sns.html?Highlight=sns) +* Each message should have one Deep Security event to evaluate but the code is +* robust enough to handle multiple events per message * All logs are sent to Amazon CloudWatch Logs -* Details on the security logic behind event selection are available on the GitHub repo at https://github.com/deep-security/aws-security-hub +* Details on the security logic behind event selection are available on the +* GitHub repo at https://github.com/deep-security/aws-security-hub """ # Standard library import datetime @@ -15,6 +18,10 @@ # 3rd party libraries import boto3 +print("Boto Version = %s" % boto3.__version__) +# Import botocore exception +from botocore.exceptions import UnknownServiceError + def evaluate_deep_security_event(deep_security_event): """ @@ -28,10 +35,10 @@ def evaluate_deep_security_event(deep_security_event): # Each Deep Security event type has different criteria for forwarding, verify those properties if 'EventType' in deep_security_event: - if deep_security_event['EventType'] == "SystemEvent": + if deep_security_event['EventType'] == "SystemEvent": # Ignore, generated by Deep Security as a platform. Includes events like agent updates, communication issues, etc. print("Ignoring system event from Deep Security") - elif deep_security_event['EventType'] == "PacketLog": + elif deep_security_event['EventType'] == "PacketLog": # Firewall events if 'RepeatCount' in deep_security_event: print("Firewall event detected, checking repetition levels") @@ -49,25 +56,25 @@ def evaluate_deep_security_event(deep_security_event): if 'InfectedFilePath' in deep_security_event: if len(deep_security_event['InfectedFilePath']) > 0: result = True - elif deep_security_event['EventType'] == "WebReputationEvent": + elif deep_security_event['EventType'] == "WebReputationEvent": # Web reputation events print("Web reputation event detected, checking the associated risk") if 'Risk' in deep_security_event: if int(deep_security_event['Risk']) >= 3: result = True - elif deep_security_event['EventType'] == "IntegrityEvent": + elif deep_security_event['EventType'] == "IntegrityEvent": # Integrity monitoring events if 'Severity' in deep_security_event: print("Integrity monitoring event detected, checking severity") if int(deep_security_event['Severity']) >= 3: result = True - elif deep_security_event['EventType'] == "LogInspectionEvent": + elif deep_security_event['EventType'] == "LogInspectionEvent": # Log inspection events if 'OSSEC_Level' in deep_security_event: print("Log inspection event detected, checking risk level") if int(deep_security_event['OSSEC_Level']) >= 8: result = True - elif deep_security_event['EventType'] == "AppControlEvent": + elif deep_security_event['EventType'] == "AppControlEvent": # Application control events pass # TODO: Add risk evaluation for this type of event @@ -82,7 +89,7 @@ def generate_finding_title(title): def verify_required_properties(deep_security_event): """ - Verify if the specified Deep Security event contains the required properties to + Verify if the specified Deep Security event contains the required properties to be convert to an Amazon Finding Format finding """ result = False @@ -111,7 +118,7 @@ def verify_required_properties(deep_security_event): def convert_deep_security_event_to_aff(deep_security_event): """ - Convert a Deep Security to the Amazon Finding Format with all required and + Convert a Deep Security to the Amazon Finding Format with all required and any applicable option properties """ event_types = { @@ -172,8 +179,8 @@ def convert_deep_security_event_to_aff(deep_security_event): 'trend-micro:HostInstanceID': str(deep_security_event['HostInstanceID']), 'trend-micro:Hostname': deep_security_event['Hostname'], 'trend-micro:HostSecurityPolicyID': str(deep_security_event['HostSecurityPolicyID']), - 'trend-micro:HostSecurityPolicyName': deep_security_event['HostSecurityPolicyName'], - }, # optional, added to + 'trend-micro:HostSecurityPolicyName': deep_security_event['HostSecurityPolicyName'], + }, # optional, added to #"Malware": {}, # added when a malware event is detected "Network": {}, # optional "RecordState": "ACTIVE", @@ -192,10 +199,10 @@ def convert_deep_security_event_to_aff(deep_security_event): aff_format['ProductFields']['trend-micro:Origin'] = deep_security_event['OriginString'] # Apply custom properties based on Deep Security event type - if deep_security_event['EventType'] == "SystemEvent": + if deep_security_event['EventType'] == "SystemEvent": # Ignore, generated by Deep Security as a platform. Includes events like agent updates, communication issues, etc. pass - elif deep_security_event['EventType'] == "PacketLog": + elif deep_security_event['EventType'] == "PacketLog": # Firewall events aff_format['Severity']['Product'] = 0 aff_format['Severity']['Normalized'] = int(20) # An "could result in future compromises" finding in the AFF format @@ -220,21 +227,21 @@ def convert_deep_security_event_to_aff(deep_security_event): ] aff_format['Types'].append("TPPs/Execution") aff_format['Title'] = generate_finding_title("Malware [{}] detected".format(deep_security_event['MalwareName'])) - elif deep_security_event['EventType'] == "WebReputationEvent": + elif deep_security_event['EventType'] == "WebReputationEvent": # Web reputation events if 'Risk' in deep_security_event: aff_format['Severity']['Product'] = int(deep_security_event['Risk']) aff_format['Severity']['Normalized'] = int(int(deep_security_event['Risk']) * 17.5) # to match the 31-70 range in the AFF format aff_format['Types'].append("TPPs/Execution") aff_format['Title'] = generate_finding_title("High risk web request to IP [{}]".format(deep_security_event['TargetIP'])) - elif deep_security_event['EventType'] == "IntegrityEvent": + elif deep_security_event['EventType'] == "IntegrityEvent": # Integrity monitoring events if 'Severity' in deep_security_event: aff_format['Severity']['Product'] = int(deep_security_event['Severity']) aff_format['Severity']['Normalized'] = int(int(deep_security_event['Severity']) * 17.5) # to match the 31-70 range in the AFF format aff_format['Types'].append("Unusual Behaviors/VM") aff_format['Title'] = generate_finding_title("Unexpected change to object [{}]".format(deep_security_event['Key'])) - elif deep_security_event['EventType'] == "LogInspectionEvent": + elif deep_security_event['EventType'] == "LogInspectionEvent": # Log inspection events if 'OSSEC_Level' in deep_security_event: aff_format['Severity']['Product'] = int(deep_security_event['OSSEC_Level']) @@ -244,8 +251,8 @@ def convert_deep_security_event_to_aff(deep_security_event): aff_format['Severity']['Normalized'] = int(int(deep_security_event['OSSEC_Level']) * 5) # to match the 31-70 range in the AFF format aff_format['Types'].append("Unusual Behaviors/VM") aff_format['Types'].append("Unusual Behaviors/Application") - aff_format['Title'] = generate_finding_title(deep_security_event['OSSEC_Description']) - elif deep_security_event['EventType'] == "AppControlEvent": + aff_format['Title'] = generate_finding_title(deep_security_event['OSSEC_Description']) + elif deep_security_event['EventType'] == "AppControlEvent": # Application control events aff_format['Types'].append("Unusual Behaviors/Application") pass # TODO: Add severity normalization for this type of event @@ -260,10 +267,10 @@ def get_role_arn_for_acct(acct_number): """ # All roles are created via the provided CloudFormation template # this lets us use a simple pattern to get the role ARN. - # + # # Each AWS account sending findings to AWS Security Hub must have # cross-account role created that allows this function to call - # BatchImportFindings on that account's behalf, otherwise findings + # BatchImportFindings on that account's behalf, otherwise findings # from that account are rejected as lacking the proper permissions return "arn:aws:iam::{}:role/trend-micro-aff-forward-to-aws-security-hub".format(acct_number) @@ -306,7 +313,10 @@ def send_events_to_hub(aff_events, acct_number=None): """ result = False - securityhub = get_security_hub_client(acct_number) + try: + securityhub = get_security_hub_client(acct_number) + except UnknownServiceError: + print("Failed to create security hub client because the service is not known.") result = None try: @@ -327,7 +337,7 @@ def send_events_to_hub(aff_events, acct_number=None): print("AWS Security Hub successfully received [{}] findings".format(result['SuccessCount'])) if not result['FailedCount'] == 0: print("AWS Security Hub failed to process [{}] findings".format(result['FailedCount'])) - + return result def lambda_handler(event, context): @@ -381,10 +391,13 @@ def lambda_handler(event, context): # For each account, send the events for acct_number, e in aff_events_to_send.items(): - print("Sending [{}] events to AWS SecuritY Hub for account [{}]".format(len(e), acct_number)) - send_events_to_hub(aff_events, acct_number=acct_number) - - return { - 'total_events': total_events, - 'events_forwarded': forwarded_events, - } \ No newline at end of file + print("Sending [{}] events to AWS SecuritY Hub for account [{}]".format(len(e), acct_number)) + try: + send_events_to_hub(aff_events, acct_number=acct_number) + except Exception as err: + print("Could not extract the Deep Security event(s) from the SNS message. Threw exception:{}".format(err)) + + return { + 'total_events': total_events, + 'events_forwarded': forwarded_events, + }