This repository contains source code for the aws-lambda-guardduty
function.
This AWS Lambda function translates feeds from AWS GuardDuty findings into a list of malicious IP addresses that are then stored in an S3 bucket. A FortiGate can then consume this list as an external threat feed.
AWS GuardDuty is a managed threat detection service that monitors malicious or unauthorized behaviors/activities related to AWS resources. AWS GuardDuty provides visibility of logs called findings, and Fortinet provides a Lambda function that is invoked based on events happening in the findings and will create a list of malicious IP addresses which are then stored in an S3 Bucket. FortiGate can then be configured to point to this S3 bucket as the external feed of threat vectors.
AWS GuardDuty findings give visibility on the following:
- Severity: High/medium/low (associated with scores)
- Where the behavior/activity occurred: Region, resource ID, account ID
- When: Last seen date/time
- Count
- Detailed information:
- Affected resource: type/instance ID/image ID/port/resource type/image description/launch time/tags/network interfaces (public IP, private IP, subnet ID, VPCID, security groups)
- Action: type/connection direction
- Actor
- Additional
For more information on Amazon GuardDuty, refer to the Amazon GuardDuty official website.
This function requires:
- FortiOS 6.0.0 or higher
- An AWS account
- A subscription to GuardDuty. For more information on GuardDuty, refer to the article Getting Started with Amazon GuardDuty.
- Node.js (8.10.0+). Choose the version available for your OS (e.g. Windows, Linux, macOS).
- npm. A Node version manager should be used to install Node.js and npm. For more information, refer to the article Downloading and installing Node.js and npm. Choose the version available for your OS (e.g. Windows, Linux, macOS).
- Git (latest version). Choose the version available for your OS (e.g. Windows, Linux, macOS).
If you are on the Windows platform, you will also need:
- Git Bash (latest version).This is a Windows platform solution for performing the installation steps. For more information on setting up Git Bash on Windows, refer to the article Use git, ssh and npm on windows with Git Bash.
Installing and configuring the FortiGate aws-lambda-guardduty
function requires knowledge of the following:
- CLI (Command Line Interface)
- AWS Lambda function, DynamoDB, S3 bucket, and IAM
- Node.js
Step 4. Create an IAM role with the required permissions describes how to create a dedicated AWS IAM role to run this Lambda function. This role will have limited permissions in order to restrict operations to a dedicated S3 bucket resource and to this function only.
It is never recommended to attach a full control policy such as AmazonS3FullAccess
, which has full permissions to all resources under your Amazon AWS account, to the role which runs the Lambda function. Allowing full-access permissions to all resources may put your resources at risk.
Note: The commands in each step are intended for use in Terminal (Linux or MacOS) or Git Bash (Windows) only.
Create the deployment package from the local git project repository. In Step 5. Create the Lambda function, this package will be uploaded during Lambda function creation.
-
Clone this project into the guardduty folder of your current local directory, and enter the project directory.
$ git clone https://github.com/fortinet/aws-lambda-guardduty.git guardduty $ cd guardduty
-
Install project dependencies.
$ npm install
-
Build this project locally.
$ npm run build
The deployment package aws_lambda_guardduty.zip will be available in the dist directory.
One S3 bucket is needed for the Lambda function to store the IP block list.
Create the S3 bucket and make note of the name as it will be used later. In these instructions, the S3 bucket name will be my-aws-lambda-guardduty.
Notes:
- The Amazon S3 Rules for Bucket Naming require bucket names to be "unique across all existing bucket names in Amazon S3".
- This S3 bucket is required to run this project.
- Although S3 bucket creation is region-specific, once created, the S3 bucket can be accessed from any region.
- Do not grant the S3 bucket public access permissions.
- The Lambda function points to this S3 bucket through its S3_BUCKET environment variable.
One DynamoDB table with the stream feature enabled is required to store records of malicious IP addresses from GuardDuty Findings.
Notes:
- DynamoDB tables and Lambda functions are region-specific so you must create the table and the Lambda function in the same AWS region.
- A DynamoDB trigger on this table will be created to cause the Lambda function to execute. Since the Lambda function hasn't been created yet, instructions to create the trigger will be provided later in Step 6. Create a DynamoDB stream trigger.
In these instructions, the DynamoDB table name will be my-aws-lambda-guardduty-db.
- In the AWS console, select Services > Database > DynamoDB.
- Click Create table.
- Enter a Table name.
- For the Primary key Partition key:
- Enter the value finding_id. This value is case-sensitive.
- From the dropdown list, select String.
- Check the Add a sort key checkbox:
- Enter the value ip. This value is case-sensitive.
- From the dropdown list, select String.
- Under Table settings, check Use default settings.
- Click Create to create the table.
- Select the table to display table information.
- On the Overview tab, under Stream details, click on Manage Stream.
- Select the Keys only option, then click on Enable.
- Also listed under Stream details is the Latest stream ARN. Make note of this as you will need it in the IAM policy creation step.
To run the Lambda function across AWS services, an IAM role with the following permissions is required:
AWS Service | Permission |
---|---|
S3 | ListBucket, HeadBucket, GetObject, PutObject, PutObjectAcl |
DynamoDB | DescribeStream, ListStreams, Scan, GetShardIterator, GetRecords, UpdateItem |
The Lambda function also needs permission to write logs to CloudWatch. This permission is available in the AWS-managed policy AWSLambdaBasicExecutionRole.
Two user-managed policies will be created:
- A policy which grants an IAM role permissions to operate on the S3 bucket my-aws-lambda-guardduty.
- A policy which grants an IAM role permissions to operate on the DynamoDB table my-aws-lambda-guardduty-db.
To create a user-managed policy:
- In the AWS console, select Services > Security, Identity & Compliance > IAM.
- In the left navigation column, click Policies.
- Click Create policy.
For the policy which grants permissions to operate on the S3 bucket:
- For Service, select S3.
- For Actions, select the following Access level items:
- List > ListBucket
- List > HeadBucket
- Read > GetObject
- Write > PutObject
- Permissions management > PutObjectAcl
- For Resources, ensure that Specific is selected and then Add ARNs for each resource type to restrict access to any file in the specified bucket only.
- For the bucket resource type:
- Click Add ARN.
- In the popup, enter the Bucket name (my-aws-lambda-guardduty) and the ARN is created automatically (arn:aws:s3:::my-aws-lambda-guardduty).
- Click Add.
- For the object resource type:
- Click Add ARN.
- In the popup, create the ARN by entering the Bucket name (my-aws-lambda-guardduty) and a wildcard for the Object name (or check the Any box). The ARN is created automatically (arn:aws:s3:::my-aws-lambda-guardduty/*).
- Click Add.
- For the bucket resource type:
- Click on Review Policy.
- Enter a Name for the policy.
- (Optional) Enter a Description for the policy.
- Click Create policy.
This policy in JSON form looks like the code snippet below:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket",
"s3:PutObjectAcl"
],
"Resource": [
"arn:aws:s3:::my-aws-lambda-guardduty",
"arn:aws:s3:::my-aws-lambda-guardduty/*"
]
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": "s3:HeadBucket",
"Resource": "*"
}
]
}
For the policy which grants permissions to operate on the DynamoDB table:
- For Service, select DynamoDB.
- For Actions, select the following Access level items:
- Read > DescribeStream
- Read > GetRecords
- Read > GetShardIterator
- Read > ListStreams
- Read > Scan
- Write > UpdateItem
- For Resources, ensure that Specific is selected and then Add ARNs for each resource type to restrict access to restrict access to any stream resource in the specified table only.
- For the stream resource type:
- Click Add ARN.
- In the popup, create the ARN by entering the information for your environment:
- Region: your-region
- Account: your-account-id
- Table name: my-aws-lambda-guardduty-db
- Stream label: * (or check the Any box)
- Click Add.
- The ARN is created automatically (arn:aws:dynamodb:your-region:your-account-id:table/my-aws-lambda-guardduty-db/stream/*).
- Alternatively, you can paste in the Latest stream ARN and replace the Stream label with the * wildcard. The Latest stream ARN is found on the Overview tab when selecting the DynamoDB table (Services > Database > DynamoDB > Tables > my-aws-lambda-guardduty-db).
- For the table resource type:
- Click Add ARN.
- In the popup, create the ARN by entering the information for your environment:
- Region: your-region
- Account: your-account-id
- Table name: my-aws-lambda-guardduty-db
- Click Add.
- The ARN is created automatically (arn:aws:dynamodb:your-region:your-account-id:table/my-aws-lambda-guardduty-db).
- For the stream resource type:
- Click on Review Policy.
- Enter a Name for the policy.
- (Optional) Enter a Description for the policy.
- Click Create policy.
This policy in JSON form looks like the code snippet below:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"dynamodb:GetShardIterator",
"dynamodb:Scan",
"dynamodb:UpdateItem",
"dynamodb:DescribeStream",
"dynamodb:GetRecords"
],
"Resource": [
"arn:aws:dynamodb:your-region:your-account-id:table/my-aws-lambda-guardduty-db/stream/*",
"arn:aws:dynamodb:your-region:your-account-id:table/my-aws-lambda-guardduty-db"
]
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": "dynamodb:ListStreams",
"Resource": "*"
}
]
}
Next, create an IAM role to run the Lambda function:
- In the AWS console, select Services > Security, Identity & Compliance > IAM.
- In the left navigation column, click Roles.
- Click Create role.
- For Choose the service that will use this role, select Lambda.
- Click Next: Permissions.
- Attach permissions policies by searching for and selecting:
- the two user-managed policies created above
- the AWS-managed policy AWSLambdaBasicExecutionRole
- Click Next: Tags.
- Click Next: Review.
- Enter a Role name.
- (Optional) Enter a Role description.
- Click Create role.
The Lambda function is created with the deployment package generated in Step 1. Prepare the deployment package. It has five configurable environment variables:
Variable Name | Type | Description |
---|---|---|
MIN_SEVERITY | Integer | The minimum severity required to block an IP address. Values can range from 0.1 to 8.9. The default value is 3. For information on GuardDuty severity levels, refer to the article Severity Levels for GuardDuty Findings. |
S3_BUCKET | Text | The S3 bucket name to store the IP block list file. This must be specified as there is no default value. |
S3_BLOCKLIST_KEY | Text | The relative file path to the IP block list file within the S3 bucket. This must be specified as there is no default value. |
REGION | Text | The AWS Region in which to run these services: Lambda, DynamoDB. This must be specified as there is no default value. For information on determining the Region based on the Region Name, refer to the AWS article AWS Regions and Endpoints. |
DDB_TABLE_NAME | Text | The DynamoDB table name which stores malicious IP addresses obtained from the findings. This must be specified as there is no default value. |
To create the Lambda function:
- In the AWS Console, select Services > Compute > Lambda.
- Click Create (a) function.
- Select Author from scratch and enter Basic information as follows:
- Function name: Enter a unique name of your choosing.
- Runtime: Select Node.js 8.10.
- Permissions: Select Use an existing role and then select the role created in Step 4. Set up an IAM role and attach policies.
- Click Create function.
- Locate the Function code area.
- Under Code entry type, select Upload a .zip file.
- Under Function package, click Upload.
- Navigate to the .dist directory and select the deployment package aws_lambda_guardduty.zip generated in Step 1. Prepare the deployment package.
- For Handler, enter index.handler.
- Under Environment variables, add the following key-value pairs:
Key Value MIN_SEVERITY 3 S3_BUCKET The name of the S3 bucket created in Step 2. Create an S3 bucket (my-aws-lambda-guardduty) S3_BLOCKLIST_KEY ip_blocklist (or something else as the name of a file to store the malicious IP addresses.) REGION The AWS Region where your Lambda function and DynamoDB table are located. DDB_TABLE_NAME The name of the DynamoDB table created in Step 3. Create a DynamoDB table. (my-aws-lambda-guardduty-db) - Under Basic settings, change the Timeout from 3 sec to 15 sec.
- Click Save.
A DynamoDB stream trigger is what causes the Lambda function to create the ip blocklist file and store it in the S3 bucket.
- In the AWS console, select Services > Database > DynamoDB.
- In the left nagivation columm, click Tables.
- Click the Name of the DynamoDB table created in Step 3. Create a DynamoDB table (my-aws-lambda-guardduty-db).
- Click the Triggers tab.
- Click Create Trigger and then from the dropdown, select Existing Lambda function.
- For Function, select the Lambda function created in Step 5. Create the Lambda function.
- For Batch size, leave the default value of 100.
- Ensure Enable trigger is selected.
- Click Create.
To work with the Lambda function AWS CloudWatch and GuardDuty services need some additional configuration.
A CloudWatch event rule is used to invoke the Lambda function to collect the malicious IP addresses and save them in the DynamoDB table. The event rule is triggered based on events happening in GuardDuty findings.
To create an event rule:
- In the AWS console, select Services > Management & Governance > CloudWatch.
- In the left nagivation columm, click Rules.
- Click Create Rule.
- Under Event Source:
- Select Event Pattern.
- From the dropdown list, ensure Events by Service is selected.
- For Service Name, select GuardDuty.
- For Event Type, select GuardDuty Finding.
- Confirm that the Event Pattern Preview looks like the code snippet below.
{ "source": [ "aws.guardduty" ], "detail-type": [ "GuardDuty Finding" ] }
- Under Targets:
- Click Add Target*.
- From the dropdown list, ensure Lambda function is selected.
- For Function, select the Lambda function you created in Step 5. Create the Lambda function.
- Click Configure details.
- Enter a Name (E.g. aws-lambda-guardduty-finding-event-rule).
- For State, check the Enabled checkbox.
- Click Create Rule.
When all services have been created, verify the the installation by creating and running a test event from the Lambda function.
To create a test event:
- In the AWS Console, select Services > Compute > Lambda.
- In the left nagivation columm, click Functions.
- Locate the Lambda function created in Step 5. Create the Lambda function and click on the Function name.
- From the Select a test event dropdown, select Configure test events.
- Select Create new test event.
- Paste the following code into the text box.
{ "id": "fa9fa4a5-0232-188d-da1c-af410bcfc344", "detail": { "service": { "serviceName": "guardduty", "action": { "networkConnectionAction": { "connectionDirection": "INBOUND", "remoteIpDetails": { "ipAddressV4": "192.168.123.123" } } }, "additionalInfo": { "threatListName": "GeneratedFindingThreatListName" }, "eventLastSeen": "2018-07-18T22:12:01.720Z" }, "severity": 3 } }
- Click Create.
To execute the Lambda function with the test event:
- From the Select a test event dropdown, select the event you just created.
- Click the Test button.
Ensure Execution result: succeeded is at the top of the page and then review the results of the test. Look for the following:
- A record with a finding_id of fa9fa4a5-0232-188d-da1c-af410bcfc344 and an ip of 192.168.123.123 is in the DynamoDB table my-aws-lambda-guardduty-db.
- The file ip_blocklist resides in the S3 bucket my-aws-lambda-guardduty.
- The file ip_blocklist has the Read object permission for Everyone under the Public access section.
- The file ip_blocklist is accessible in a browser using its link (e.g. https://s3-***your-region***.amazonaws.com/***my-aws-lambda-guardduty***/ip_blocklist).
- Check that the file ip_blocklist contains the line 192.168.123.123.
Amazon GuardDuty monitors your AWS infrastructure on a continuous basis to detect malicious or unauthorized behavior and creates records based on such findings.
If you are subscribing to GuardDuty for the first time, the Findings list will be empty. To generate some samples, go to Settings and click Generate sample findings. Several dummy findings marked as “[SAMPLE]” will be created.
As long as you have set up the Lambda function and CloudWatch correctly, some of those sample findings will trigger the CloudWatch event rule to run the Lambda function. A few new IP addresses will eventually appear in the ip_blocklist.
Instructions can be found in FortiGate documentation in the GuardDuty integration section.
Since test events and sample findings can update the ip_blocklist with sample IP addresses, it is highly recommended that you clean up the ip_blocklist prior to production use.
Clean up is done by removing the ip_blocklist from the S3 bucket and clearing the DynamoDB table:
- Delete all records from the DynamoDB table created in Step 3. Create a DynamoDB table. (my-aws-lambda-guardduty-db).
- Delete the ip_blocklist file from the S3 bucket created in Step 2. Create an S3 bucket (my-aws-lambda-guardduty).
Fortinet-provided scripts in this and other GitHub projects do not fall under the regular Fortinet technical support scope and are not supported by FortiCare Support Services. For direct issues, please refer to the Issues tab of this GitHub project. For other questions related to this project, contact github@fortinet.com.
License © Fortinet Technologies. All rights reserved.