From 3722139b29e83e64752dfbaafd601cdb737c3cba Mon Sep 17 00:00:00 2001 From: Daniel Pinheiro Date: Tue, 21 Sep 2021 14:57:27 -0400 Subject: [PATCH] Update to version v3.2.0 --- .gitignore | 9 +- CHANGELOG.md | 35 +- NOTICE.txt | 2 +- README.md | 170 ++++-- ...urity-automations-firehose-athena.template | 6 +- ...s-waf-security-automations-webacl.template | 15 +- .../aws-waf-security-automations.template | 534 +++++++++++++++++- deployment/build-s3-dist.sh | 55 +- deployment/run-unit-tests.sh | 48 +- source/access_handler/access-handler.py | 8 +- source/custom_resource/custom-resource.py | 64 ++- source/helper/helper.py | 11 +- source/image/architecture_diagram.png | Bin 0 -> 169536 bytes .../__init__.py | 0 .../ip_retention_handler/remove_expired_ip.py | 259 +++++++++ source/ip_retention_handler/requirements.txt | 2 + .../ip_retention_handler/set_ip_retention.py | 152 +++++ source/ip_retention_handler/test/__init__.py | 0 .../test/test_remove_expired_ip.py | 109 ++++ .../test/test_set_ip_retention.py | 92 +++ .../testing_requirements.txt | 4 +- source/lib/boto3_util.py | 63 +++ source/lib/dynamodb_util.py | 36 ++ source/lib/sns_util.py | 36 ++ source/lib/solution_metrics.py | 8 +- source/lib/waflibv2.py | 103 +++- source/log_parser/add_athena_partitions.py | 5 +- source/log_parser/log-parser.py | 33 +- source/log_parser/partition_s3_logs.py | 5 +- source/log_parser/test/__init__.py | 0 .../test}/test_build_athena_queries.py | 10 +- .../test/test_data}/alb_logs_query.txt | 0 .../test_data}/athena_partitions_query.txt | 0 .../test/test_data}/cloudfront_logs_query.txt | 0 .../test/test_data}/waf_logs_query.txt | 0 .../test}/test_solution_metrics.py | 0 source/log_parser/testing_requirements.txt | 12 + .../reputation-lists.py | 10 +- 38 files changed, 1726 insertions(+), 170 deletions(-) create mode 100644 source/image/architecture_diagram.png rename source/{tests => ip_retention_handler}/__init__.py (100%) create mode 100644 source/ip_retention_handler/remove_expired_ip.py create mode 100644 source/ip_retention_handler/requirements.txt create mode 100644 source/ip_retention_handler/set_ip_retention.py create mode 100644 source/ip_retention_handler/test/__init__.py create mode 100644 source/ip_retention_handler/test/test_remove_expired_ip.py create mode 100644 source/ip_retention_handler/test/test_set_ip_retention.py rename source/{tests => ip_retention_handler}/testing_requirements.txt (77%) create mode 100644 source/lib/boto3_util.py create mode 100644 source/lib/dynamodb_util.py create mode 100644 source/lib/sns_util.py create mode 100644 source/log_parser/test/__init__.py rename source/{tests => log_parser/test}/test_build_athena_queries.py (89%) rename source/{tests => log_parser/test/test_data}/alb_logs_query.txt (100%) rename source/{tests => log_parser/test/test_data}/athena_partitions_query.txt (100%) rename source/{tests => log_parser/test/test_data}/cloudfront_logs_query.txt (100%) rename source/{tests => log_parser/test/test_data}/waf_logs_query.txt (100%) rename source/{tests => log_parser/test}/test_solution_metrics.py (100%) create mode 100644 source/log_parser/testing_requirements.txt diff --git a/.gitignore b/.gitignore index b375019a..8a22cf58 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,11 @@ **/.pyc /deployment/open-source/ source/tests/__pycache__/ -source/log_parser/__pycache__/ \ No newline at end of file +source/log_parser/__pycache__/ +deployment/global-s3-assets/ +deployment/regional-s3-assets/ + +# coverage +**/coverage +**/package +*coverage* \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2149a552..251c078c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,30 +3,35 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [2.3.1] - 2019-10-30 +## [3.2] - 2021-09-22 ### Added +- Added IP retention support on Allowed and Denied IP Sets ### Changed -- Fixed error handling of intermittent issue: (WAFStaleDataException) when calling the UpdateWebACL -- Upgrade from Node 8 to Node 10 for Lambda function -## [2.3.2] - 2020-02-05 +- Bug fixes +## [3.1] - 2020-10-22 +### Changed +- Replaced s3 path-style with virtual-hosted style +- Added partition variable to all ARNs +- Updated bug report +## [3.0] - 2020-07-08 ### Added +- Added an option to deploy AWS Managed Rules for WebACL on installation ### Changed -- Fixed README file to accurately reflect script params -- Upgraded from Python 3.7 to 3.8 -- Changed RequestThreshold min limit from 2000 to 100 +- Upgraded from WAF classic to WAFV2 API +- Eliminated dependency on NodeJS and use Python as the standardized programming language ## [2.3.3] - 2020-06-15 ### Added - Implemented Athena optimization: added partitioning for CloudFront, ALB and WAF logs and Athena queries ### Changed - Fixed potential DoS vector within Bad Bots X-Forward-For header -## [3.0] - 2020-07-08 +## [2.3.2] - 2020-02-05 ### Added -- Added an option to deploy AWS Managed Rules for WebACL on installation ### Changed -- Upgraded from WAF classic to WAFV2 API -- Eliminated dependency on NodeJS and use Python as the standardized programming language -## [3.1] - 2020-10-22 +- Fixed README file to accurately reflect script params +- Upgraded from Python 3.7 to 3.8 +- Changed RequestThreshold min limit from 2000 to 100 +## [2.3.1] - 2019-10-30 +### Added ### Changed -- Replaced s3 path-style with virtual-hosted style -- Added partition variable to all ARNs -- Updated bug report +- Fixed error handling of intermittent issue: (WAFStaleDataException) when calling the UpdateWebACL +- Upgrade from Node 8 to Node 10 for Lambda function diff --git a/NOTICE.txt b/NOTICE.txt index 998ce3bc..a6ce2b71 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,6 +1,6 @@ AWS WAF Security Automations -Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. +Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. Licensed under the Apache License Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at http://www.apache.org/licenses/ or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, diff --git a/README.md b/README.md index 14f020e6..1e5a1c4c 100644 --- a/README.md +++ b/README.md @@ -1,87 +1,153 @@ -# AWS WAF Security Automations -A solution that contains all AWS WAF samples developed so far - waf-reactive-blacklist, waf-bad-bot-blocking, waf-block-bad-behaving and waf-reputation-lists. +**[🚀 Solution Landing Page](https://aws.amazon.com/solutions/implementations/aws-waf-security-automations/>)** | **[🚧 Feature request](https://github.com/awslabs/aws-waf-security-automations/issues/new?assignees=&labels=feature-request%2C+enhancement&template=feature_request.md&title=)** | **[🐛 Bug Report](https://github.com/awslabs/aws-waf-security-automations/issues/new?assignees=&labels=bug%2C+triage&template=bug_report.md&title=)** -For the full solution overview visit [AWS WAF Security Automations](https://aws.amazon.com/answers/security/aws-waf-security-automations/). +Note: If you want to use the solution without building from source, navigate to Solution Landing Page -## File Structure -This project consists of microservices that facilitate the functional areas of the solution. These microservices are deployed to a serverless environment in AWS Lambda. +## Table of contents -``` -|-deployment/ [folder containing templates and build scripts] -|-source/ - |-access_handler/ [microservice for processing bad bots honeypot endpoint access. This AWS Lambda function intercepts the suspicious request and adds the source IP address to the AWS WAF block list] - |-custom_resource/ [custom helper for CloudFormation deployment template] - |-helper/ [custom helper for CloudFormation deployment dependency check and auxiliary functions] - |-lib/ [library files including waf api calls and other common functions used in the solution] - |-log_parser/ [microservice for processing access logs searching for suspicious behavior and add the corresponding source IP addresses to an AWS WAF block list] - |-reputation_lists_parser/ [microservice for processing third-party IP reputation lists and add malicious IP addresses to an AWS WAF block list] - |-tests/ [unit tests] - |-timer/ [creates a sleep function for cloudformation to pace the creation of ip_sets] -``` +- [Solution Overview](#solution-overview) +- [Architecture Diagram](#architecture-diagram) +- [Customizing the Solution](#customizing-the-solution) + - [Prerequisites for Customization](#prerequisites-for-customization) + - [Build](#build) + - [Upload Deployment Assets](#upload-deployment-assets) + - [Deploy](#deploy) +- [File Structure](#file-structure) +- [License](#license) + + +# Solution Overview + +The AWS DevOps Monitoring Dashboard solution is a reference implementation that automatically deploys a set of AWS WAF (web application firewall) rules that filter common web-based attacks. Users can select from preconfigured protective features that define the rules included in an AWS WAF web access control list (web ACL). Once deployed, AWS WAF protects your Amazon CloudFront distributions or Application Load Balancers by inspecting web requests. + +You can use AWS WAF to create custom, application-specific rules that block attack patterns to ensure application availability, secure resources, and prevent excessive resource consumption. + +This solution can be easily installed in your AWS accounts via launching the provided AWS CloudFormation template. + +For a detailed solution implementation guide, refer to Solution Landing Page [AWS WAF Security Automations](https://aws.amazon.com/solutions/implementations/aws-waf-security-automations) + + +# Architecture Diagram + +

+ +
+

+ +AWS WAF Security Automations architecture + +AWS Managed Rules (A): This set of AWS managed core rules provides protection against exploitation of a wide range of common application vulnerabilities or other unwanted traffic. + +Manual IP lists (B and C): This component creates two specific AWS WAF rules that allow you to manually insert IP addresses that you want to block or allow. + +SQL Injection (D) and XSS (E): The solution configures two native AWS WAF rules that are designed to protect against common SQL injection or cross-site scripting (XSS) patterns in the URI, query string, or body of a request. + +HTTP flood (F): This component helps protect against attacks that consist of a large number of requests from a particular IP address, such as a web-layer DDoS attacks or a brute-force login attempt. This feature supports thresholds of less than 100 requests within a 5 minute period. + +Scanners and Probes (G): This component parses application access logs searching for suspicious behavior, such as an abnormal amount of errors generated by an origin. It then blocks those suspicious source IP addresses for a customer-defined period of time. + +IP Reputation Lists (H): This component is the IP Lists Parser AWS Lambda function which checks third-party IP reputation lists hourly for new ranges to block. + +Bad Bots (I): This component automatically sets up a honeypot, which is a security mechanism intended to lure and deflect an attempted attack. -## Getting Started + +# Customizing the Solution -#### 01. Prerequisites -The following procedures assumes that all of the OS-level configuration has been completed. They are: + +## Prerequisites for Customization * [AWS Command Line Interface](https://aws.amazon.com/cli/) * Python 3.8 -The AWS WAF Security Automations solution is developed with Python for the microservices that run in AWS Lambda. The latest version has been tested with Python v3.8. + +## Build -#### 02. Clone AWS WAF Security Automations repository -Clone the aws-waf-security-automations GitHub repository: +Building from GitHub source will allow you to modify the solution, such as adding custom actions or upgrading to a new release. The process consists of downloading the source from GitHub, creating Amazon S3 buckets to store artifacts for deployment, building the solution, and uploading the artifacts to S3 in your account. + +#### 1. Clone the repository + +Clone or download the repository to a local directory on your linux client. Note: if you intend to modify the source code you may wish to create your own fork of the GitHub repo and work from that. This allows you to check in any changes you make to your private copy of the solution. + +**Git Clone example:** ``` git clone https://github.com/awslabs/aws-waf-security-automations.git ``` -#### 03. Run unit tests -Next, run unit tests to make sure added customization passes the tests +**Download Zip example:** +``` +wget https://github.com/awslabs/aws-waf-security-automations/archive/master.zip +``` + +#### 2. Unit test +Next, run unit tests to make sure your customized code passes the tests -``` -cd ./deployment +``` +cd /deployment chmod +x ./run-unit-tests.sh ./run-unit-tests.sh -``` +``` + +#### 3. Create S3 buckets for storing deployment assets + +AWS Solutions use two buckets: -#### 04. Declare enviroment variables: +* One global bucket that is access via the http end point. AWS CloudFormation templates are stored here. Ex. "mybucket" +* One regional bucket for each region where you plan to deploy the solution. Use the name of the global bucket as the prefix of the bucket name, and suffixed with the region name. Regional assets such as Lambda code are stored here. Ex. "mybucket-us-east-1" +* The assets in buckets must be accessible by your account + +#### 4. Declare enviroment variables ``` -export TEMPLATE_OUTPUT_BUCKET= # Name for the S3 bucket where the template will be located -export DIST_OUTPUT_BUCKET= # Name for the S3 bucket where customized code will reside -export SOLUTION_NAME="aws-waf-security-automations" # name of the solution +export TEMPLATE_OUTPUT_BUCKET= # Name of the global bucket where CloudFormation templates are stored +export DIST_OUTPUT_BUCKET= # Name for the regional bucket where regional assets are stored +export SOLUTION_NAME= # name of the solution. export VERSION= # version number for the customized code -export AWS_REGION= # region where the distributable is deployed +export AWS_REGION= # region where the solution is deployed ``` -#### _Note:_ You must manually create two buckets in S3 called $TEMPLATE_OUTPUT_BUCKET and $DIST_OUTPUT_BUCKET-$AWS_REGION to copy the distribution. The assets in bucket should be publicly accessible. The build-s3-dist.sh script DOES NOT do this and the CloudFormation template expects/references the REGION specific bucket. - -#### 05. Build the AWS WAF Security Automations solution for deployment: +#### 5. Build the solution ``` +cd /deployment chmod +x ./build-s3-dist.sh && ./build-s3-dist.sh $TEMPLATE_OUTPUT_BUCKET $DIST_OUTPUT_BUCKET $SOLUTION_NAME $VERSION ``` -#### 06. Upload deployment assets to your Amazon S3 buckets: + + +## Upload deployment assets ``` -aws s3 cp ./deployment/global-s3-assets s3://$TEMPLATE_OUTPUT_BUCKET/aws-waf-security-automations/$VERSION --recursive --acl bucket-owner-full-control -aws s3 cp ./deployment/regional-s3-assets s3://$DIST_OUTPUT_BUCKET-$AWS_REGION/aws-waf-security-automations/$VERSION --recursive --acl bucket-owner-full-control +aws s3 cp ./deployment/global-s3-assets s3://$TEMPLATE_OUTPUT_BUCKET/$SOLUTION_NAME/$VERSION --recursive --acl bucket-owner-full-control +aws s3 cp ./deployment/regional-s3-assets s3://$DIST_OUTPUT_BUCKET-$AWS_REGION/$SOLUTION_NAME/$VERSION --recursive --acl bucket-owner-full-control ``` -#### _Note:_ You must use proper acl and profile for the copy operation as applicable. +#### _Note:_ You must use proper acl and profile for the copy operation as applicable. Using randomized bucket names is recommended. + + +## Deploy -#### 07. Deploy the AWS WAF Security Automations solution: * From your designated Amazon S3 bucket where you uploaded the deployment assets, copy the link location for the aws-waf-security-automations.template. * Using AWS CloudFormation, launch the AWS WAF Security Automations solution stack using the copied Amazon S3 link for the aws-waf-security-automations.template. -*** + +# File structure + +This project consists of microservices that facilitate the functional areas of the solution. These microservices are deployed to a serverless environment in AWS Lambda. + +
+|-deployment/ [folder containing templates and build scripts]
+|-source/
+  |-access_handler/         [microservice for processing bad bots honeypot endpoint access. This AWS Lambda function intercepts the suspicious request and adds the source IP address to the AWS WAF block list]
+  |-custom_resource/        [custom helper for CloudFormation deployment template]
+  |-helper/                 [custom helper for CloudFormation deployment dependency check and auxiliary functions]
+  |-image/                  [folder containing images of the solution such as architecture diagram]
+  |-lib/                    [library files including waf api calls and other common functions used in the solution]
+  |-ip_retention_handler/   [lambda code for setting ip retention and removing expired ips]
+  |-log_parser/             [microservice for processing access logs searching for suspicious behavior and add the corresponding source IP addresses to an AWS WAF block list]
+  |-reputation_lists_parser/ [microservice for processing third-party IP reputation lists and add malicious IP addresses to an AWS WAF block list]
+  |-timer/                   [creates a sleep function for cloudformation to pace the creation of ip_sets]
+
-Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +# Collection of operational metrics -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +This solution collects anonymous operational metrics to help AWS improve the quality and features of the solution. For more information, including how to disable this capability, please see the [implementation guide](https://docs.aws.amazon.com/solutions/latest/aws-waf-security-automations/appendix-g.html). - http://www.apache.org/licenses/LICENSE-2.0 + +# License -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. +See license [here](https://github.com/awslabs/aws-waf-security-automations/blob/master/LICENSE.txt) \ No newline at end of file diff --git a/deployment/aws-waf-security-automations-firehose-athena.template b/deployment/aws-waf-security-automations-firehose-athena.template index eb9a8cac..55f2c7cd 100644 --- a/deployment/aws-waf-security-automations-firehose-athena.template +++ b/deployment/aws-waf-security-automations-firehose-athena.template @@ -46,6 +46,8 @@ Parameters: Type: String DeliveryStreamName: Type: String + UUID: + Type: String Conditions: AlbEndpoint: !Equals @@ -144,6 +146,8 @@ Resources: Properties: DeliveryStreamName: !Ref DeliveryStreamName DeliveryStreamType: DirectPut + DeliveryStreamEncryptionConfigurationInput: + KeyType: AWS_OWNED_CMK ExtendedS3DestinationConfiguration: BucketARN: !Ref WafLogBucketArn BufferingHints: @@ -404,7 +408,7 @@ Resources: Type: AWS::Athena::WorkGroup Condition: AthenaLogParser Properties: - Name: WAFAddPartitionAthenaQueryWorkGroup + Name: !Join ['-', ['WAFAddPartitionAthenaQueryWorkGroup', !Ref UUID]] Description: Athena WorkGroup for adding Athena partition queries used by AWS WAF Security Automations Solution State: ENABLED RecursiveDeleteOption: true diff --git a/deployment/aws-waf-security-automations-webacl.template b/deployment/aws-waf-security-automations-webacl.template index d61cf8a6..45a988c6 100644 --- a/deployment/aws-waf-security-automations-webacl.template +++ b/deployment/aws-waf-security-automations-webacl.template @@ -191,7 +191,7 @@ Resources: Scope: !Sub '${RegionScope}' IPAddressVersion: 'IPV4' Name: !Sub '${ParentStackName}WhitelistSetIPV4' - Description: 'Allow whitelist for IPV4 addresses' + Description: 'Allow List for IPV4 addresses' Addresses: [] WAFBlacklistSetV4: @@ -201,7 +201,7 @@ Resources: Scope: !Sub '${RegionScope}' IPAddressVersion: 'IPV4' Name: !Sub '${ParentStackName}BlacklistSetIPV4' - Description: 'Block blacklist for IPV4 addresses' + Description: 'Block Denied List for IPV4 addresses' Addresses: [] WAFHttpFloodSetV4: @@ -259,7 +259,7 @@ Resources: Scope: !Sub '${RegionScope}' IPAddressVersion: IPV6 Name: !Sub '${ParentStackName}WhitelistSetIPV6' - Description: 'Allow whitelist for IPV6 addresses' + Description: 'Allow list for IPV6 addresses' Addresses: [] WAFBlacklistSetV6: @@ -269,7 +269,7 @@ Resources: Scope: !Sub '${RegionScope}' IPAddressVersion: IPV6 Name: !Sub '${ParentStackName}BlacklistSetIPV6' - Description: 'Block blacklist for IPV6 addresses' + Description: 'Block Denied List for IPV6 addresses' Addresses: [] WAFHttpFloodSetV6: @@ -356,6 +356,13 @@ Resources: Variables: SECONDS: '2' LOG_LEVEL: !Ref LogLevel + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: There is no need to run this lambda in a VPC + - id: W92 + reason: There is no need for Reserved Concurrency # Adding a (priority 0) rule for AWS Managed RuleSet, optionally triggered by params diff --git a/deployment/aws-waf-security-automations.template b/deployment/aws-waf-security-automations.template index 5200e668..4f4962e9 100644 --- a/deployment/aws-waf-security-automations.template +++ b/deployment/aws-waf-security-automations.template @@ -36,19 +36,22 @@ Metadata: - ActivateBadBotProtectionParam - Label: - default: Settings + default: Log Monitoring Settings Parameters: - EndpointType - AppAccessLogBucket - - - Label: - default: Advanced Settings - Parameters: - ErrorThreshold - RequestThreshold - WAFBlockPeriod - KeepDataInOriginalS3Location + - Label: + default: IP Retention Settings + Parameters: + - IPRetentionPeriodAllowedParam + - IPRetentionPeriodDeniedParam + - SNSEmailParam + ParameterLabels: ActivateAWSManagedRulesParam: default: Activate AWS Managed Rules Protection @@ -87,7 +90,16 @@ Metadata: default: WAF Block Period KeepDataInOriginalS3Location: - default: Keep Data in Original s3 location + default: Keep Data in Original S3 Location + + IPRetentionPeriodAllowedParam: + default: Retention Period (Minutes) for Allowed IP Set + + IPRetentionPeriodDeniedParam: + default: Retention Period (Minutes) for Denied IP Set + + SNSEmailParam: + default: Email for receiving notifcation upon Allowed or Denied IP Sets expiration Parameters: ActivateAWSManagedRulesParam: @@ -211,6 +223,33 @@ Parameters: to keep a copy of the logs in their original location. Selecting "Yes" will duplicate your log storage. If you did not choose to activate Athena log parsing, ignore this parameter. + IPRetentionPeriodAllowedParam: + Type: Number + Default: -1 + MinValue: -1 + Description: >- + If you want to activate IP retention for the Allowed IP set, enter a number (15 or above) as the retention period (minutes). + IP addresses reaching the retention period will expire and be removed from the IP set. A minimum 15-minute retention + period is supported. If you enter a number between 0 and 15, it will be treated as 15. Leave it to default value -1 + to disable IP retention. + + IPRetentionPeriodDeniedParam: + Type: Number + Default: -1 + MinValue: -1 + Description: >- + If you want to activate IP retention for the Denied IP set, enter a number (15 or above) as the retention period (minutes). + IP addresses reaching the retention period will expire and be removed from the IP set. A minimum 15-minute retention + period is supported. If you enter a number between 0 and 15, it will be treated as 15. Leave it to default value -1 + to disable IP retention. + + SNSEmailParam: + Type: String + Default: '' + Description: >- + If you activated IP retention period above and want to receive an email notification when IP addresses expire, enter a valid email address. + If you did not activate IP retention or want to disable email notification, leave it blank (default). + Conditions: HttpFloodProtectionRateBasedRuleActivated: !Equals - !Ref ActivateHttpFloodProtectionParam @@ -268,6 +307,20 @@ Conditions: - Condition: ReputationListsProtectionActivated - Condition: AthenaLogParser + IPRetentionAllwedPeriod: !Not [!Equals [!Ref IPRetentionPeriodAllowedParam, -1]] + + IPRetentionDeniedPeriod: !Not [!Equals [!Ref IPRetentionPeriodDeniedParam, -1]] + + IPRetentionPeriod: !Or + - Condition: IPRetentionAllwedPeriod + - Condition: IPRetentionDeniedPeriod + + SNSEmailProvided: !Not [!Equals [!Ref SNSEmailParam, '']] + + SNSEmail: !And + - Condition: IPRetentionPeriod + - Condition: SNSEmailProvided + Mappings: SourceCode: General: @@ -292,6 +345,8 @@ Mappings: WAFBadBotRule: 'BLOCK' Athena: QueryScheduledRunTime: 5 # by default athena query runs every 5 minutes, update it if needed + UserAgent: + UserAgentExtra: 'AwsSolution/SO0006/%VERSION%' Resources: CheckRequirements: @@ -330,6 +385,8 @@ Resources: WAFBlockPeriod: !Ref WAFBlockPeriod GlueDatabaseName: !If [AthenaLogParser, !GetAtt CreateGlueDatabaseName.DatabaseName, ''] DeliveryStreamName: !If [HttpFloodProtectionLogParserActivated, !GetAtt CreateDeliveryStreamName.DeliveryStreamName, ''] + UUID: !GetAtt CreateUniqueID.UUID + WebACLStack: Type: 'AWS::CloudFormation::Stack' @@ -763,7 +820,8 @@ Resources: - Effect: Allow Action: 'lambda:InvokeFunction' Resource: - - !Sub 'arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${AWS::StackName}*' + - !Sub 'arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:*AddAthenaPartitions*' + - !Sub 'arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:*ReputationListsParser*' - !Ref 'AWS::NoValue' - PolicyName: WAFAccess PolicyDocument: @@ -820,6 +878,18 @@ Resources: - 'logs:PutLogEvents' Resource: - !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*CustomResource*' + - !If + - ScannersProbesProtectionActivated + - PolicyName: S3BucketLoggingAccess + PolicyDocument: + Statement: + - Effect: Allow + Action: + - 's3:GetBucketLogging' + - 's3:PutBucketLogging' + Resource: + - !Sub 'arn:${AWS::Partition}:s3:::${AppAccessLogBucket}' + - !Ref 'AWS::NoValue' Metadata: cfn_nag: rules_to_suppress: @@ -990,7 +1060,7 @@ Resources: - 'logs:PutLogEvents' Resource: - !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*AddAthenaPartitions*' - + Helper: Type: 'AWS::Lambda::Function' Properties: @@ -1005,9 +1075,142 @@ Resources: Variables: LOG_LEVEL: !FindInMap ["Solution", "Data", "LogLevel"] SCOPE: !If [AlbEndpoint, 'REGIONAL', 'CLOUDFRONT'] + USER_AGENT_EXTRA: !FindInMap [Solution, UserAgent, UserAgentExtra] Runtime: python3.8 MemorySize: 128 Timeout: 300 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: There is no need to run this lambda in a VPC + - id: W92 + reason: There is no need for Reserved Concurrency + + LambdaRoleSetIPRetention: + Type: 'AWS::IAM::Role' + Condition: IPRetentionPeriod + Properties: + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - 'sts:AssumeRole' + Path: / + Policies: + - PolicyName: LogsAccess + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'logs:CreateLogGroup' + - 'logs:CreateLogStream' + - 'logs:PutLogEvents' + Resource: + - !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*SetIPRetention*' + - PolicyName: DDBAccess + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'dynamodb:PutItem' + Resource: + - !GetAtt IPRetentionDDBTable.Arn + Metadata: + cfn_nag: + rules_to_suppress: + - + id: W11 + reason: "LogsAccess permission restricted to account, region and log group name substring (SetIPRetention)." + + LambdaRoleRemoveExpiredIP: + Type: 'AWS::IAM::Role' + Condition: IPRetentionPeriod + Properties: + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - 'sts:AssumeRole' + Path: / + Policies: + - PolicyName: LogsAccess + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'logs:CreateLogGroup' + - 'logs:CreateLogStream' + - 'logs:PutLogEvents' + Resource: + - !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*RemoveExpiredIP*' + - PolicyName: WAFAccess + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'wafv2:GetIPSet' + - 'wafv2:UpdateIPSet' + Resource: + - !GetAtt WebACLStack.Outputs.WAFWhitelistSetV4Arn + - !GetAtt WebACLStack.Outputs.WAFBlacklistSetV4Arn + - !GetAtt WebACLStack.Outputs.WAFWhitelistSetV6Arn + - !GetAtt WebACLStack.Outputs.WAFBlacklistSetV6Arn + - PolicyName: DDBStreamAccess + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - "dynamodb:GetShardIterator" + - "dynamodb:DescribeStream" + - "dynamodb:GetRecords" + - "dynamodb:ListStreams" + Resource: + - !GetAtt IPRetentionDDBTable.StreamArn + - PolicyName: InvokeLambda + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - "lambda:InvokeFunction" + Resource: + - !GetAtt IPRetentionDDBTable.StreamArn + Metadata: + cfn_nag: + rules_to_suppress: + - + id: W11 + reason: "LogsAccess permission restricted to account, region and log group name substring (RemoveExpiredIP)." + + SNSPublishPolicy: + Type: "AWS::IAM::Policy" + Condition: SNSEmail + Properties: + PolicyName: "SNSPublishPolicy" + Roles: + - Ref: LambdaRoleRemoveExpiredIP + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - "SNS:Publish" + Resource: + - !Ref IPExpirationSNSTopic CreateUniqueID: Type: 'Custom::CreateUUID' @@ -1048,16 +1251,58 @@ Resources: BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true + LoggingConfiguration: + DestinationBucketName: !Ref AccessLoggingBucket + LogFilePrefix: WAF_Logs/ Metadata: cfn_nag: rules_to_suppress: - - - id: W35 - reason: "WafLogBucket does not require access logging to be configured by default." - id: W51 reason: "WafLogBucket does not require a bucket policy." + AccessLoggingBucket: + Type: AWS::S3::Bucket + Condition: LogParser + DependsOn: CheckRequirements + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + AccessControl: LogDeliveryWrite + BucketEncryption: + ServerSideEncryptionConfiguration: + - ServerSideEncryptionByDefault: + SSEAlgorithm: AES256 + PublicAccessBlockConfiguration: + BlockPublicAcls: True + BlockPublicPolicy: True + IgnorePublicAcls: True + RestrictPublicBuckets: True + Metadata: + cfn_nag: + rules_to_suppress: + - id: W35 + reason: "This bucket is an access logging bucket for another bucket and does not require access logging to be configured for it." + + AccessLoggingBucketPolicy: + Type: AWS::S3::BucketPolicy + Condition: LogParser + Properties: + Bucket: + Ref: AccessLoggingBucket + PolicyDocument: + Statement: + - Action: "s3:*" + Condition: + Bool: + aws:SecureTransport: 'false' + Effect: Deny + Principal: "*" + Resource: + - !GetAtt AccessLoggingBucket.Arn + - !Join ["/", [!GetAtt AccessLoggingBucket.Arn, "*"]] + Sid: HttpsOnly + Version: '2012-10-17' LogParser: Type: 'AWS::Lambda::Function' @@ -1104,9 +1349,17 @@ Resources: REQUEST_THRESHOLD: !Ref RequestThreshold SOLUTION_ID: !FindInMap [Solution, Data, SolutionID] METRICS_URL: !FindInMap [Solution, Data, MetricsURL] + USER_AGENT_EXTRA: !FindInMap [Solution, UserAgent, UserAgentExtra] Runtime: python3.8 MemorySize: 512 Timeout: 300 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: There is no need to run this lambda in a VPC + - id: W92 + reason: There is no need for Reserved Concurrency MoveS3LogsForPartition: Type: 'AWS::Lambda::Function' @@ -1132,9 +1385,17 @@ Resources: LOG_LEVEL: !FindInMap ["Solution", "Data", "LogLevel"] KEEP_ORIGINAL_DATA: !Ref KeepDataInOriginalS3Location ENDPOINT: !Ref EndpointType + USER_AGENT_EXTRA: !FindInMap [Solution, UserAgent, UserAgentExtra] Runtime: python3.8 MemorySize: 512 Timeout: 300 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: There is no need to run this lambda in a VPC + - id: W92 + reason: There is no need for Reserved Concurrency AddAthenaPartitions: Type: 'AWS::Lambda::Function' @@ -1157,9 +1418,80 @@ Resources: Environment: Variables: LOG_LEVEL: !FindInMap ["Solution", "Data", "LogLevel"] + USER_AGENT_EXTRA: !FindInMap [Solution, UserAgent, UserAgentExtra] + Runtime: python3.8 + MemorySize: 512 + Timeout: 300 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: There is no need to run this lambda in a VPC + - id: W92 + reason: There is no need for Reserved Concurrency + + SetIPRetention: + Type: 'AWS::Lambda::Function' + Condition: IPRetentionPeriod + Properties: + Description: >- + This lambda function processes CW events for WAF UpdateIPSet API calls. It writes relevant ip retention data into a DynamoDB table. + Handler: 'set_ip_retention.lambda_handler' + Role: !GetAtt LambdaRoleSetIPRetention.Arn + Code: + S3Bucket: !Join ['-', [!FindInMap ["SourceCode", "General", "SourceBucket"], !Ref 'AWS::Region']] + S3Key: !Join ['/', [!FindInMap ["SourceCode", "General", "KeyPrefix"], 'ip_retention_handler.zip']] + Environment: + Variables: + LOG_LEVEL: !FindInMap ["Solution", "Data", "LogLevel"] + TABLE_NAME: !Ref IPRetentionDDBTable + STACK_NAME: !Ref 'AWS::StackName' + IP_RETENTION_PEROID_ALLOWED_MINUTE: !Ref IPRetentionPeriodAllowedParam + IP_RETENTION_PEROID_DENIED_MINUTE: !Ref IPRetentionPeriodDeniedParam + REMOVE_EXPIRED_IP_LAMBDA_ROLE_NAME: !Ref LambdaRoleRemoveExpiredIP + USER_AGENT_EXTRA: !FindInMap [Solution, UserAgent, UserAgentExtra] + Runtime: python3.8 + MemorySize: 128 + Timeout: 300 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: There is no need to run this lambda in a VPC + - id: W92 + reason: There is no need for Reserved Concurrency + + RemoveExpiredIP: + Type: 'AWS::Lambda::Function' + Condition: IPRetentionPeriod + Properties: + Description: >- + This lambda function processes the DDB streams records (IP) expired by TTL. It removes expired IPs from WAF allowed or denied IP sets. + Handler: 'remove_expired_ip.lambda_handler' + Role: !GetAtt LambdaRoleRemoveExpiredIP.Arn + Code: + S3Bucket: !Join ['-', [!FindInMap ["SourceCode", "General", "SourceBucket"], !Ref 'AWS::Region']] + S3Key: !Join ['/', [!FindInMap ["SourceCode", "General", "KeyPrefix"], 'ip_retention_handler.zip']] + Environment: + Variables: + LOG_LEVEL: !FindInMap ["Solution", "Data", "LogLevel"] + SNS_EMAIL: !If [SNSEmail, 'yes', 'no'] + SNS_TOPIC_ARN : !If [SNSEmail, !Ref IPExpirationSNSTopic, ''] + SEND_ANONYMOUS_USAGE_DATA: !FindInMap ["Solution", "Data", "SendAnonymousUsageData"] + UUID: !GetAtt CreateUniqueID.UUID + SOLUTION_ID: !FindInMap [Solution, Data, SolutionID] + METRICS_URL: !FindInMap [Solution, Data, MetricsURL] + USER_AGENT_EXTRA: !FindInMap [Solution, UserAgent, UserAgentExtra] Runtime: python3.8 MemorySize: 512 Timeout: 300 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: There is no need to run this lambda in a VPC + - id: W92 + reason: There is no need for Reserved Concurrency LambdaInvokePermissionAppLogParserS3: Type: 'AWS::Lambda::Permission' @@ -1188,6 +1520,15 @@ Resources: Principal: "events.amazonaws.com" SourceArn: !GetAtt LambdaAddAthenaPartitionsEventsRule.Arn + LambdaInvokePermissionSetIPRetention: + Type: 'AWS::Lambda::Permission' + Condition: IPRetentionPeriod + Properties: + FunctionName: !Ref SetIPRetention + Action: 'lambda:InvokeFunction' + Principal: events.amazonaws.com + SourceArn: !GetAtt SetIPRetentionEventsRule.Arn + LambdaAthenaWAFLogParser: Type: 'AWS::Events::Rule' Condition: HttpFloodAthenaLogParser @@ -1238,7 +1579,7 @@ Resources: Condition: AthenaLogParser Properties: Description: Security Automations - Add partitions to Athena table - ScheduleExpression: rate(1 hour) + ScheduleExpression: cron(* ? * * * *) State: ENABLED Targets: - Arn: !GetAtt AddAthenaPartitions.Arn @@ -1262,6 +1603,35 @@ Resources: WafLogBucket: !If [HttpFloodAthenaLogParser, !Ref WafLogBucket, ''] AthenaWorkGroup: !GetAtt FirehoseAthenaStack.Outputs.WAFAddPartitionAthenaQueryWorkGroup + SetIPRetentionEventsRule: + Type: AWS::Events::Rule + Condition: IPRetentionPeriod + Properties: + Description: AWS WAF Security Automations - Events rule for setting IP retention + EventPattern: + source: + - aws.wafv2 + detail-type: + - AWS API Call via CloudTrail + detail: + eventSource: + - wafv2.amazonaws.com + eventName: + - UpdateIPSet + requestParameters: + name: + - !GetAtt WebACLStack.Outputs.NameWAFWhitelistSetV4 + - !GetAtt WebACLStack.Outputs.NameWAFBlacklistSetV4 + - !GetAtt WebACLStack.Outputs.NameWAFWhitelistSetV6 + - !GetAtt WebACLStack.Outputs.NameWAFBlacklistSetV6 + State: ENABLED + Targets: + - Arn: + Fn::GetAtt: + - SetIPRetention + - Arn + Id: SetIPRetentionLambda + LambdaInvokePermissionAppLogParserCloudWatch: Type: 'AWS::Lambda::Permission' Condition: ScannersProbesAthenaLogParser @@ -1308,6 +1678,14 @@ Resources: LOG_TYPE: !If [AlbEndpoint, 'alb', 'cloudfront'] SEND_ANONYMOUS_USAGE_DATA: !FindInMap ["Solution", "Data", "SendAnonymousUsageData"] IPREPUTATIONLIST_METRICNAME: !GetAtt WebACLStack.Outputs.IPReputationListsMetricName + USER_AGENT_EXTRA: !FindInMap [Solution, UserAgent, UserAgentExtra] + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: There is no need to run this lambda in a VPC + - id: W92 + reason: There is no need for Reserved Concurrency ReputationListsParserEventsRule: @@ -1391,10 +1769,17 @@ Resources: SOLUTION_ID: !FindInMap [Solution, Data, SolutionID] METRICS_URL: !FindInMap [Solution, Data, MetricsURL] STACK_NAME: !Ref 'AWS::StackName' - + USER_AGENT_EXTRA: !FindInMap [Solution, UserAgent, UserAgentExtra] Runtime: python3.8 MemorySize: 128 Timeout: 300 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: There is no need to run this lambda in a VPC + - id: W92 + reason: There is no need for Reserved Concurrency LambdaInvokePermissionBadBot: Type: 'AWS::Lambda::Permission' @@ -1509,6 +1894,15 @@ Resources: ApiGatewayBadBotStageAccessLogGroup: Type: AWS::Logs::LogGroup Condition: BadBotProtectionActivated + Metadata: + cfn_nag: + rules_to_suppress: + - + id: W84 + reason: "Encryption not required: no sensitive data logged to CloudWatch." + - + id: W86 + reason: "Leave the configuration of the expiration of the log data in CloudWatch log group to user due to potential compliance regulations." ApiGatewayBadBotCloudWatchRole: Type: AWS::IAM::Role @@ -1569,9 +1963,17 @@ Resources: SCOPE: !If [AlbEndpoint, 'REGIONAL', 'CLOUDFRONT'] SOLUTION_ID: !FindInMap [Solution, Data, SolutionID] METRICS_URL: !FindInMap [Solution, Data, MetricsURL] + USER_AGENT_EXTRA: !FindInMap [Solution, UserAgent, UserAgentExtra] Runtime: python3.8 MemorySize: 128 Timeout: 300 + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: There is no need to run this lambda in a VPC + - id: W92 + reason: There is no need for Reserved Concurrency ConfigureAWSWAFLogs: Type: 'Custom::ConfigureAWSWAFLogs' @@ -1592,6 +1994,7 @@ Resources: ScannersProbesLambdaLogParser: !If [ScannersProbesLambdaLogParser, 'yes', 'no'] ScannersProbesAthenaLogParser: !If [ScannersProbesAthenaLogParser, 'yes', 'no'] MoveS3LogsForPartition: !If [ScannersProbesAthenaLogParser, !GetAtt MoveS3LogsForPartition.Arn, !Ref 'AWS::NoValue'] + AccessLoggingBucket: !If [ScannersProbesProtectionActivated, !Ref AccessLoggingBucket, !Ref 'AWS::NoValue'] ConfigureWafLogBucket: Type: 'Custom::ConfigureWafLogBucket' @@ -1637,6 +2040,9 @@ Resources: ActivateBadBotProtectionParam: !Ref ActivateBadBotProtectionParam ActivateAWSManagedRulesParam: !Ref ActivateAWSManagedRulesParam KeepDataInOriginalS3Location: !Ref KeepDataInOriginalS3Location + IPRetentionPeriodAllowedParam: !Ref IPRetentionPeriodAllowedParam + IPRetentionPeriodDeniedParam: !Ref IPRetentionPeriodDeniedParam + SNSEmailParam: !If [SNSEmail, 'yes', 'no'] # AWS WAF Web ACL WAFWebACL: !GetAtt WebACLStack.Outputs.WAFWebACL # AWS WAF IP Sets - ID @@ -1719,6 +2125,108 @@ Resources: WAFWebACLMetricName: !GetAtt WebACLStack.Outputs.WAFWebACLMetricName RegionMetric: !If [AlbEndpoint, !Sub ', "Region", "${AWS::Region}"', ''] RegionProperties: !If [AlbEndpoint, !Sub '${AWS::Region}', 'us-east-1'] + + IPRetentionDDBTable: + Type: 'AWS::DynamoDB::Table' + Condition: IPRetentionPeriod + Properties: + AttributeDefinitions: + - AttributeName: IPSetId + AttributeType: S + - AttributeName: ExpirationTime + AttributeType: N + BillingMode: PAY_PER_REQUEST + KeySchema: + - AttributeName: IPSetId + KeyType: HASH + - AttributeName: ExpirationTime + KeyType: RANGE + SSESpecification: + SSEEnabled: True + SSEType: KMS + StreamSpecification: + StreamViewType: OLD_IMAGE + TimeToLiveSpecification: + AttributeName: ExpirationTime + Enabled: true + Metadata: + cfn_nag: + rules_to_suppress: + - + id: W78 + reason: "This DynamoDB table constains transactional ip retention data that will be expired by DynamoDB TTL. The data doesn't need to be retained after its lifecycle ends." + + IPExpirationSNSTopic: + Type: AWS::SNS::Topic + Condition: SNSEmail + Properties: + DisplayName: 'AWS WAF Security Automations IP Expiration Notification' + TopicName: !Join ['-', ['AWS-WAF-Security-Automations-IP-Expiration-Notification', !GetAtt CreateUniqueID.UUID]] + KmsMasterKeyId: alias/aws/sns + + IPExpirationEmailNotification: + Type: AWS::SNS::Subscription + Condition: SNSEmail + Properties: + Endpoint: !Ref SNSEmailParam + Protocol: email + TopicArn: !Ref IPExpirationSNSTopic + + SNSNotificationPolicy: + Type: AWS::SNS::TopicPolicy + Condition: SNSEmail + Metadata: + cfn_nag: + rules_to_suppress: + - id: F18 + reason: "Condition restricts permissions to current account." + Properties: + Topics: + - !Ref IPExpirationSNSTopic + PolicyDocument: + Statement: + - Sid: __default_statement_ID + Effect: Allow + Principal: + AWS: "*" + Action: + - SNS:GetTopicAttributes + - SNS:SetTopicAttributes + - SNS:AddPermission + - SNS:RemovePermission + - SNS:DeleteTopic + - SNS:Subscribe + - SNS:ListSubscriptionsByTopic + - SNS:Publish + - SNS:Receive + Resource: !Ref IPExpirationSNSTopic + Condition: + StringEquals: + AWS:SourceOwner: !Sub ${AWS::AccountId} + - Sid: TrustLambdaToPublishEventsToMyTopic + Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: SNS:Publish + Resource: !Ref IPExpirationSNSTopic + - Sid: AllowPublishThroughSSLOnly + Action: SNS:Publish + Effect: Deny + Resource: + - !Ref IPExpirationSNSTopic + Condition: + Bool: + aws:SecureTransport: 'false' + Principal: "*" + + DDBStreamToLambdaESMapping: + Type: AWS::Lambda::EventSourceMapping + Condition: IPRetentionPeriod + Properties: + Enabled: true + EventSourceArn: !GetAtt IPRetentionDDBTable.StreamArn + FunctionName: !GetAtt RemoveExpiredIP.Arn + StartingPosition: LATEST Outputs: BadBotHoneypotEndpoint: diff --git a/deployment/build-s3-dist.sh b/deployment/build-s3-dist.sh index 444fb2b6..70eb049b 100755 --- a/deployment/build-s3-dist.sh +++ b/deployment/build-s3-dist.sh @@ -57,6 +57,10 @@ echo "find ../ -type f -name '.DS_Store' -delete" find "$source_dir" -type f -name '.DS_Store' -delete echo "find $source_dir -iname \"package\" -type d -exec rm -r \"{}\" \; 2> /dev/null" find "$source_dir" -iname "package" -type d -exec rm -r "{}" \; 2> /dev/null +echo "find $source_dir/**/* -iname \"lib\" -type d -exec rm -rf \"{}\" \; 2> /dev/null" +find "$source_dir/**/*" -iname "lib" -type d -exec rm -rf "{}" \; 2> /dev/null +echo "find $source_dir -iname \"__pycache__\" -type d -exec rm -r \"{}\" \; 2> /dev/null" +find "$source_dir" -iname "__pycache__" -type d -exec rm -r "{}" \; 2> /dev/null echo "------------------------------------------------------------------------------" echo "[Packing] Templates" @@ -79,23 +83,27 @@ echo "-------------------------------------------------------------------------- echo "[Packing] Log Parser" echo "------------------------------------------------------------------------------" cd "$source_dir"/log_parser || exit 1 -pip install -r requirements.txt --target ./package +pip3 install -r requirements.txt --target ./package cd "$source_dir"/log_parser/package || exit 1 zip -q -r9 "$build_dist_dir"/log_parser.zip . cd "$source_dir"/log_parser || exit 1 -cp -r "$source_dir"/lib . -zip -g -r "$build_dist_dir"/log_parser.zip log-parser.py partition_s3_logs.py add_athena_partitions.py build_athena_queries.py lib +mkdir -p lib +echo "cp $source_dir/lib/waflibv2.py $source_dir/lib/solution_metrics.py $source_dir/lib/boto3_util.py lib" +cp -rf "$source_dir"/lib/waflibv2.py "$source_dir"/lib/solution_metrics.py "$source_dir"/lib/boto3_util.py lib +zip -g -r "$build_dist_dir"/log_parser.zip log-parser.py partition_s3_logs.py add_athena_partitions.py build_athena_queries.py lib test echo "------------------------------------------------------------------------------" echo "[Packing] Access Handler" echo "------------------------------------------------------------------------------" cd "$source_dir"/access_handler || exit 1 -pip install -r requirements.txt --target ./package +pip3 install -r requirements.txt --target ./package cd "$source_dir"/access_handler/package || exit 1 zip -q -r9 "$build_dist_dir"/access_handler.zip . cd "$source_dir"/access_handler || exit 1 -cp -r "$source_dir"/lib . +mkdir -p lib +echo "cp $source_dir/lib/waflibv2.py $source_dir/lib/solution_metrics.py $source_dir/lib/boto3_util.py lib" +cp -rf "$source_dir"/lib/waflibv2.py "$source_dir"/lib/solution_metrics.py "$source_dir"/lib/boto3_util.py lib zip -g -r "$build_dist_dir"/access_handler.zip access-handler.py lib @@ -103,11 +111,13 @@ echo "-------------------------------------------------------------------------- echo "[Packing] IP Lists Parser" echo "------------------------------------------------------------------------------" cd "$source_dir"/reputation_lists_parser || exit 1 -pip install -r requirements.txt --target ./package +pip3 install -r requirements.txt --target ./package cd "$source_dir"/reputation_lists_parser/package || exit 1 zip -q -r9 "$build_dist_dir"/reputation_lists_parser.zip . cd "$source_dir"/reputation_lists_parser || exit 1 -cp -r "$source_dir"/lib . +mkdir -p lib +echo "cp $source_dir/lib/waflibv2.py $source_dir/lib/solution_metrics.py $source_dir/lib/boto3_util.py lib" +cp -rf "$source_dir"/lib/waflibv2.py "$source_dir"/lib/solution_metrics.py "$source_dir"/lib/boto3_util.py lib zip -g -r "$build_dist_dir"/reputation_lists_parser.zip reputation-lists.py lib @@ -115,11 +125,13 @@ echo "-------------------------------------------------------------------------- echo "[Packing] Custom Resource" echo "------------------------------------------------------------------------------" cd "$source_dir"/custom_resource || exit 1 -pip install -r requirements.txt --target ./package +pip3 install -r requirements.txt --target ./package cd "$source_dir"/custom_resource/package || exit 1 zip -q -r9 "$build_dist_dir"/custom_resource.zip . cd "$source_dir"/custom_resource || exit 1 -cp -r "$source_dir"/lib . +mkdir -p lib +echo "cp $source_dir/lib/waflibv2.py $source_dir/lib/solution_metrics.py $source_dir/lib/boto3_util.py lib" +cp -rf "$source_dir"/lib/waflibv2.py "$source_dir"/lib/solution_metrics.py "$source_dir"/lib/boto3_util.py lib zip -g -r "$build_dist_dir"/custom_resource.zip custom-resource.py lib @@ -127,11 +139,13 @@ echo "-------------------------------------------------------------------------- echo "[Packing] Helper" echo "------------------------------------------------------------------------------" cd "$source_dir"/helper || exit 1 -pip install -r requirements.txt --target ./package +pip3 install -r requirements.txt --target ./package cd "$source_dir"/helper/package || exit 1 zip -q -r9 "$build_dist_dir"/helper.zip ./* cd "$source_dir"/helper || exit 1 -cp -r "$source_dir"/lib . +mkdir -p lib +echo "cp $source_dir/lib/waflibv2.py $source_dir/lib/boto3_util.py lib" +cp -rf "$source_dir"/lib/waflibv2.py "$source_dir"/lib/boto3_util.py lib zip -g -r "$build_dist_dir"/helper.zip helper.py lib @@ -139,9 +153,22 @@ echo "-------------------------------------------------------------------------- echo "[Packing] Timer" echo "------------------------------------------------------------------------------" cd "$source_dir"/timer || exit 1 -pip install -r requirements.txt --target ./package +pip3 install -r requirements.txt --target ./package cd "$source_dir"/timer/package || exit 1 zip -q -r9 "$build_dist_dir"/timer.zip ./* cd "$source_dir"/timer || exit 1 -cp -r "$source_dir"/lib . -zip -g -r "$build_dist_dir"/timer.zip timer.py lib +zip -g -r "$build_dist_dir"/timer.zip timer.py + + +echo "------------------------------------------------------------------------------" +echo "[Packing] IP Retention Handler" +echo "------------------------------------------------------------------------------" +cd "$source_dir"/ip_retention_handler || exit 1 +pip3 install -r requirements.txt --target ./package +cd "$source_dir"/ip_retention_handler/package || exit 1 +zip -q -r9 "$build_dist_dir"/ip_retention_handler.zip ./* +cd "$source_dir"/ip_retention_handler || exit 1 +mkdir -p lib +echo "cp $source_dir/lib/waflibv2.py $source_dir/lib/solution_metrics.py $source_dir/lib/sns_util.py $source_dir/lib/dynamodb_util.py $source_dir/lib/boto3_util.py lib" +cp -rf "$source_dir"/lib/waflibv2.py "$source_dir"/lib/solution_metrics.py "$source_dir"/lib/sns_util.py "$source_dir"/lib/dynamodb_util.py $source_dir/lib/boto3_util.py lib +zip -g -r "$build_dist_dir"/ip_retention_handler.zip set_ip_retention.py remove_expired_ip.py lib test \ No newline at end of file diff --git a/deployment/run-unit-tests.sh b/deployment/run-unit-tests.sh index 13e5189c..c4cedc40 100755 --- a/deployment/run-unit-tests.sh +++ b/deployment/run-unit-tests.sh @@ -8,12 +8,42 @@ # template_dir="$PWD" -source_dir="$template_dir/../source" - -echo "------------------------------------------------------------------------------" -echo "[Test] Build Athena Queries" -echo "------------------------------------------------------------------------------" -echo 'pip3 install -r ../tests/testing_requirements.txt' -pip3 install -r ../source/tests/testing_requirements.txt -echo 'pytest -s ../tests' -pytest -s ../source/tests +source_dir="$(cd $template_dir/../source; pwd -P)" + +echo "Current directory: $template_dir" +echo "Source directory: $source_dir" + +run_python_lambda_test() { + lambda_name=$1 + lambda_description=$2 + echo "------------------------------------------------------------------------------" + echo "[Test] Python Unit Test: $lambda_description" + echo "------------------------------------------------------------------------------" + + cd $source_dir/$lambda_name + echo "run_python_lambda_test: Current directory: $source_dir/$lambda_name" + + # Install dependencies + echo 'Install Python Testing Dependencies: pip3 install -r ./testing_requirements.txt' + pip3 install -r ./testing_requirements.txt + + # Set coverage report path + mkdir -p $source_dir/test/coverage-reports + coverage_report_path=$source_dir/test/coverage-reports/$lambda_name.coverage.xml + echo "coverage report path set to $coverage_report_path" + + # Run unit tests with coverage + python3 -m pytest --cov --cov-report=term-missing --cov-report "xml:$coverage_report_path" + # The pytest --cov with its parameters and .coveragerc generates a xml cov-report with `coverage/sources` list + # with absolute path for the source directories. To avoid dependencies of tools (such as SonarQube) on different + # absolute paths for source directories, this substitution is used to convert each absolute source directory + # path to the corresponding project relative path. The $source_dir holds the absolute path for source directory. + sed -i -e "s,$source_dir,source,g" $coverage_report_path +} + +# Run Python unit tests +run_python_lambda_test ip_retention_handler "Set IP Retention Lambda" +run_python_lambda_test log_parser "Log Parser" + +# Return to the directory where we started +cd $template_dir \ No newline at end of file diff --git a/source/access_handler/access-handler.py b/source/access_handler/access-handler.py index fab38abb..4ebaa234 100644 --- a/source/access_handler/access-handler.py +++ b/source/access_handler/access-handler.py @@ -28,6 +28,7 @@ from lib.waflibv2 import WAFLIBv2 from lib.solution_metrics import send_metrics +from lib.boto3_util import create_client waflib = WAFLIBv2() @@ -40,7 +41,7 @@ def send_anonymous_usage_data(log, scope, ipset_name_v4, ipset_arn_v4, ipset_nam log.info("[send_anonymous_usage_data] Start") metric_prefix = os.getenv('METRIC_NAME_PREFIX') - cw = boto3.client('cloudwatch') + cw = create_client('cloudwatch') usage_data = { "data_type": "bad_bot", "bad_bot_ip_set_size": 0, @@ -202,7 +203,10 @@ def lambda_handler(event, context): # Fixed as old line had security exposure based on user supplied IP address log.info("Event->%s<-", str(event)) - source_ip = str(event['requestContext']['identity']['sourceIp']) + if event['requestContext']['identity']['userAgent'] == 'Amazon CloudFront': + source_ip = str(event['headers']['X-Forwarded-For'].split(',')[0].strip()) + else: + source_ip = str(event['requestContext']['identity']['sourceIp']) log.info("scope = %s", scope) log.info("ipset_name_v4 = %s", ipset_name_v4) diff --git a/source/custom_resource/custom-resource.py b/source/custom_resource/custom-resource.py index 05de4f24..09881d32 100644 --- a/source/custom_resource/custom-resource.py +++ b/source/custom_resource/custom-resource.py @@ -19,8 +19,11 @@ import requests import os import time +from os import environ +from botocore.config import Config from lib.waflibv2 import WAFLIBv2 from lib.solution_metrics import send_metrics +from lib.boto3_util import create_client, create_resource waflib = WAFLIBv2() @@ -42,7 +45,7 @@ # # All those requirements are pre-verified by helper function. # ---------------------------------------------------------------------------------------------------------------------- -def configure_s3_bucket(log, region, bucket_name): +def configure_s3_bucket(log, region, bucket_name, access_logging_bucket_name): log.info("[configure_s3_bucket] Start") if bucket_name.strip() == "": @@ -51,11 +54,14 @@ def configure_s3_bucket(log, region, bucket_name): # ------------------------------------------------------------------------------------------------------------------ # Create the S3 bucket (if not exist) # ------------------------------------------------------------------------------------------------------------------ - s3_client = boto3.client('s3') + s3_client = create_client('s3') try: response = s3_client.head_bucket(Bucket=bucket_name) log.info("[configure_s3_bucket]response head_bucket: \n%s" % response) + + # Enable access logging if needed + put_s3_bucket_access_logging(log, s3_client, bucket_name, access_logging_bucket_name) except botocore.exceptions.ClientError as e: # If a client error is thrown, then check that it was a 404 error. # If it was a 404 error, then the bucket does not exist. @@ -98,8 +104,33 @@ def configure_s3_bucket(log, region, bucket_name): } ) log.info("[configure_s3_bucket]response put_public_access_block: \n%s" % response) + + # Enable access logging + put_s3_bucket_access_logging(log, s3_client, bucket_name, access_logging_bucket_name) + log.info("[configure_s3_bucket] End") +# ---------------------------------------------------------------------------------------------------------------------- +# Enable access logging on the App access log bucket +# ---------------------------------------------------------------------------------------------------------------------- +def put_s3_bucket_access_logging(log, s3_client, bucket_name, access_logging_bucket_name): + log.info("[put_s3_bucket_access_logging] Start") + + response = s3_client.get_bucket_logging(Bucket = bucket_name) + + # Enable access logging if not already exists + if response.get('LoggingEnabled') is None: + response = s3_client.put_bucket_logging( + Bucket=bucket_name, + BucketLoggingStatus={ + 'LoggingEnabled': { + 'TargetBucket': access_logging_bucket_name, + 'TargetPrefix': 'AppAccess_Logs' + } + } + ) + log.info("[put_s3_bucket_access_logging]put_bucket_logging response: \n%s" % response) + log.info("[put_s3_bucket_access_logging] End") # ---------------------------------------------------------------------------------------------------------------------- # Configure bucket event to call Log Parser whenever a new gz log or athena result file is added to the bucket; @@ -110,7 +141,7 @@ def add_s3_bucket_lambda_event(log, bucket_name, lambda_function_arn, lambda_log log.info("[add_s3_bucket_lambda_event] Start") try: - s3_client = boto3.client('s3') + s3_client = create_client('s3') if lambda_function_arn is not None and (lambda_parser or athena_parser): notification_conf = s3_client.get_bucket_notification_configuration(Bucket=bucket_name) @@ -169,7 +200,7 @@ def remove_s3_bucket_lambda_event(log, bucket_name, lambda_function_arn, lambda_ if lambda_function_arn != None: log.info("[remove_s3_bucket_lambda_event] Start") - s3_client = boto3.client('s3') + s3_client = create_client('s3') try: new_conf = {} notification_conf = s3_client.get_bucket_notification_configuration(Bucket=bucket_name) @@ -267,8 +298,8 @@ def generate_app_log_parser_conf_file(log, stack_name, error_threshold, block_pe if not overwrite: try: - s3 = boto3.resource('s3') - file_obj = s3.Object(app_access_log_bucket, remote_file) + s3_resource = create_resource('s3') + file_obj = s3_resource.Object(app_access_log_bucket, remote_file) file_content = file_obj.get()['Body'].read() remote_conf = json.loads(file_content) @@ -285,7 +316,7 @@ def generate_app_log_parser_conf_file(log, stack_name, error_threshold, block_pe with open(local_file, 'w') as outfile: json.dump(default_conf, outfile) - s3_client = boto3.client('s3') + s3_client = create_client('s3') s3_client.upload_file(local_file, app_access_log_bucket, remote_file, ExtraArgs={'ContentType': "application/json"}) log.debug("[generate_app_log_parser_conf_file] End") @@ -309,8 +340,8 @@ def generate_waf_log_parser_conf_file(log, stack_name, request_threshold, block_ if not overwrite: try: - s3 = boto3.resource('s3') - file_obj = s3.Object(waf_access_log_bucket, remote_file) + s3_resource = create_resource('s3') + file_obj = s3_resource.Object(waf_access_log_bucket, remote_file) file_content = file_obj.get()['Body'].read() remote_conf = json.loads(file_content) @@ -327,7 +358,7 @@ def generate_waf_log_parser_conf_file(log, stack_name, request_threshold, block_ with open(local_file, 'w') as outfile: json.dump(default_conf, outfile) - s3_client = boto3.client('s3') + s3_client = create_client('s3') s3_client.upload_file(local_file, waf_access_log_bucket, remote_file, ExtraArgs={'ContentType': "application/json"}) log.debug("[generate_waf_log_parser_conf_file] End") @@ -341,7 +372,7 @@ def add_athena_partitions(log, add_athena_partition_lambda_function, resource_ty glue_waf_log_table, waf_log_bucket, athena_work_group): log.info("[add_athena_partitions] Start") - lambda_client = boto3.client('lambda') + lambda_client = create_client('lambda') response = lambda_client.invoke( FunctionName=add_athena_partition_lambda_function.rsplit(":", 1)[-1], Payload="""{ @@ -424,7 +455,10 @@ def send_anonymous_usage_data(log, action_type, resource_properties): "error_threshold": resource_properties['ErrorThreshold'], "waf_block_period": resource_properties['WAFBlockPeriod'], "aws_managed_rules": resource_properties['ActivateAWSManagedRulesParam'], - "keep_original_s3_data": resource_properties['KeepDataInOriginalS3Location'] + "keep_original_s3_data": resource_properties['KeepDataInOriginalS3Location'], + "allowed_ip_retention_period_minute": resource_properties['IPRetentionPeriodAllowedParam'], + "denied_ip_retention_period_minute": resource_properties['IPRetentionPeriodDeniedParam'], + "sns_email_notification": resource_properties['SNSEmailParam'] } # -------------------------------------------------------------------------------------------------------------- @@ -483,7 +517,8 @@ def lambda_handler(event, context): if 'CREATE' in request_type: configure_s3_bucket(log, event['ResourceProperties']['Region'], - event['ResourceProperties']['AppAccessLogBucket']) + event['ResourceProperties']['AppAccessLogBucket'], + event['ResourceProperties']['AccessLoggingBucket']) add_s3_bucket_lambda_event(log, event['ResourceProperties']['AppAccessLogBucket'], lambda_log_parser_function, lambda_partition_s3_logs_function, @@ -491,6 +526,9 @@ def lambda_handler(event, context): athena_parser) elif 'UPDATE' in request_type: + configure_s3_bucket(log, event['ResourceProperties']['Region'], + event['ResourceProperties']['AppAccessLogBucket'], + event['ResourceProperties']['AccessLoggingBucket']) old_lambda_app_log_parser_function = event['OldResourceProperties']['LogParser'] if 'LogParser' in \ event[ 'OldResourceProperties'] else None diff --git a/source/helper/helper.py b/source/helper/helper.py index b908a6c8..7ab6c87b 100644 --- a/source/helper/helper.py +++ b/source/helper/helper.py @@ -21,7 +21,10 @@ import random import requests import os +from os import environ +from botocore.config import Config from lib.waflibv2 import WAFLIBv2 +from lib.boto3_util import create_client logging.getLogger().debug('Loading function') @@ -47,7 +50,7 @@ def check_app_log_bucket(log, region, bucket_name): # Check if bucket exists (and inside the specified region) # ------------------------------------------------------------------------------------------------------------------ exists = True - s3_client = boto3.client('s3') + s3_client = create_client('s3') try: response = s3_client.head_bucket(Bucket=bucket_name) log.info("[check_app_log_bucket]response: \n%s" % response) @@ -107,7 +110,7 @@ def check_service_dependencies(log, resource_properties): # ------------------------------------------------------------------------------------------------------------------ if resource_properties['AthenaLogParser'] == "yes": try: - athena_client = boto3.client('athena') + athena_client = create_client('athena') athena_client.list_named_queries() except botocore.exceptions.EndpointConnectionError: unavailable_services.append('Amazon Athena') @@ -119,7 +122,7 @@ def check_service_dependencies(log, resource_properties): # ------------------------------------------------------------------------------------------------------------------ if resource_properties['AthenaLogParser'] == "yes": try: - glue_client = boto3.client('glue') + glue_client = create_client('glue') glue_client.get_databases() except botocore.exceptions.EndpointConnectionError: unavailable_services.append('AWS Glue') @@ -131,7 +134,7 @@ def check_service_dependencies(log, resource_properties): # ------------------------------------------------------------------------------------------------------------------ if resource_properties['HttpFloodProtectionLogParserActivated'] == "yes": try: - firehose_client = boto3.client('firehose') + firehose_client = create_client('firehose') firehose_client.list_delivery_streams() except botocore.exceptions.EndpointConnectionError: unavailable_services.append('Amazon Kinesis Data Firehose') diff --git a/source/image/architecture_diagram.png b/source/image/architecture_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..6955a9e7db14e938f7f0136ffbecbd35cae09947 GIT binary patch literal 169536 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 oFW>}$``=2.22.0 +backoff>=1.8.0 \ No newline at end of file diff --git a/source/ip_retention_handler/set_ip_retention.py b/source/ip_retention_handler/set_ip_retention.py new file mode 100644 index 00000000..18ad4444 --- /dev/null +++ b/source/ip_retention_handler/set_ip_retention.py @@ -0,0 +1,152 @@ +###################################################################################################################### +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance # +# with the License. A copy of the License is located at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES # +# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions # +# and limitations under the License. # +###################################################################################################################### + +import logging +from os import environ +from calendar import timegm +from datetime import datetime, timedelta +from lib.dynamodb_util import DDB + +class SetIPRetention(object): + """ + This class contains functions to put ip retention info into ddb table + """ + + def __init__(self, event, log): + """ + Class init function + """ + + self.event = event + self.log = log + self.log.debug(self.__class__.__name__ + " Class Event:\n{}".format(event)) + + def is_none(self, value): + """ + Return None (string type) if the value is NoneType + """ + + if value is None: + return 'None' + else: + return value + + def get_expiration_time(self, time, ip_retention_period_minute): + """ + Get ip expiration time which is the TTL used by ddb table to delete ip upon expiration + """ + + utc_start_time = datetime.strptime(time, "%Y-%m-%dT%H:%M:%SZ") + utc_end_time = utc_start_time + timedelta(seconds=60*ip_retention_period_minute) + epoch_time = timegm(utc_end_time.utctimetuple()) + return epoch_time + + def make_item(self, event): + """ + Extract ip retention info from event to make ddb item + """ + + item = {} + request_parameters = self.is_none(event.get('requestParameters', {})) + + ip_retention_period = int(environ.get('IP_RETENTION_PEROID_ALLOWED_MINUTE')) \ + if self.is_none(str(request_parameters.get('name')).find('Whitelist')) != -1 \ + else int(environ.get('IP_RETENTION_PEROID_DENIED_MINUTE')) + + # If retention period is not set, stop and return + if ip_retention_period == -1: + self.log.info("[set_ip_retention: make_item] IP retention is not set on {}. Stop processing." \ + .format(self.is_none(str(request_parameters.get('name'))))) + return item + + # Set a minimum 15-minute retention period + ip_retention_period = 15 if ip_retention_period in range(0, 15) else ip_retention_period + + item = { + "IPSetId": self.is_none(str(request_parameters.get('id'))), + "IPSetName": self.is_none(str(request_parameters.get('name'))), + "Scope": self.is_none(str(request_parameters.get('scope'))), + "IPAdressList": self.is_none(request_parameters.get('addresses',[])), + "LockToken": self.is_none(str(request_parameters.get('lockToken'))), + "IPRetentionPeriodMinute": ip_retention_period, + "CreationTime": timegm(datetime.utcnow().utctimetuple()), + "ExpirationTime": self.get_expiration_time(event.get('eventTime'), ip_retention_period), + "CreatedByUser": environ.get('STACK_NAME') + } + return item + + def put_item(self, table_name): + """ + Write item into ddb table + """ + try: + self.log.info("[set_ip_retention: put_item] Start") + + ddb = DDB(self.log, table_name) + + item = self.make_item(self.event) + + response = {} + + # put item if it is not empty + if bool(item): + response = ddb.put_item(item) + + self.log.info("[set_ip_retention: put_item] item: \n{}".format(item)) + self.log.info("[set_ip_retention: put_item] put_item response: \n{}:".format(response)) + + except Exception as error: + self.log.error(str(error)) + raise + + self.log.info("[set_ip_retention:put_item] End") + + return response + + +def lambda_handler(event, context): + """ + Invoke functions to put ip retentation info into ddb table. + It is triggered by a CloudWatch events rule. + """ + + log = logging.getLogger() + + try: + # Set Log Level + log_level = str(environ['LOG_LEVEL'].upper()) + if log_level not in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']: + log_level = 'ERROR' + log.setLevel(log_level) + + log.info('[set_ip_retention: lambda_handler] Start') + log.info("Lambda Handler Event: \n{}".format(event)) + + event_detail = event.get('detail',{}) + event_user_arn = event_detail.get('userIdentity',{}).get('arn') + response = {} + + # If event for UpdateIPSet api call is not created by the RemoveExpiredIP lambda, continue to put item into DDB + if event_user_arn.find(environ.get('REMOVE_EXPIRED_IP_LAMBDA_ROLE_NAME')) == -1: + sipr = SetIPRetention(event_detail, log) + response = sipr.put_item(environ.get('TABLE_NAME')) + else: + message = "The event for UpdateIPSet API call was made by RemoveExpiredIP lambda instead of user. Skip." + log.info(message) + response = {"Message": message} + except Exception as error: + log.error(str(error)) + raise + + log.info('[set_ip_retention: lambda_handler] End') + return response diff --git a/source/ip_retention_handler/test/__init__.py b/source/ip_retention_handler/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/source/ip_retention_handler/test/test_remove_expired_ip.py b/source/ip_retention_handler/test/test_remove_expired_ip.py new file mode 100644 index 00000000..fa97caf5 --- /dev/null +++ b/source/ip_retention_handler/test/test_remove_expired_ip.py @@ -0,0 +1,109 @@ +############################################################################## +# Copyright Amazon.com, Inc. and its affiliates. All Rights Reserved. +# # +# Licensed under the Amazon Software License (the "License"). You may not # +# use this file except in compliance with the License. A copy of the # +# License is located at # +# # +# http://aws.amazon.com/asl/ # +# # +# or in the "license" file accompanying this file. This file is distributed # +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, # +# express or implied. See the License for the specific language governing # +# permissions and limitations under the License. # +############################################################################## + +import logging +from decimal import Decimal +from remove_expired_ip import RemoveExpiredIP + +event = { + "Records": [{ + "eventID": "some-event-id", + "eventName": "REMOVE", + "eventVersion": "1.1", + "eventSource": "aws:dynamodb", + "awsRegion": "us-east-1", + "dynamodb": { + "ApproximateCreationDateTime": 1628203857.0, + "Keys": { + "ExpirationTime": { + "N": "1628203246" + }, + "IPSetId": { + "S": "some-ips-set-id" + } + }, + "OldImage": { + "IPSetName": { + "S": "some-ip-set-name" + }, + "CreatedByUser": { + "S": "some-user" + }, + "Scope": { + "S": "CLOUDFRONT" + }, + "CreationTime": { + "N": "1628203216" + }, + "LockToken": { + "S": "some-lock_token" + }, + "IPAdressList": { + "L": [{ + "S": "x.x.x.x/32" + }, { + "S": "y.y.y.y/32" + }] + }, + "ExpirationTime": { + "N": "1628203246" + }, + "IPSetId": { + "S": "some-ips-set-id" + } + }, + "SequenceNumber": "some-sequence-number", + "SizeBytes": 339, + "StreamViewType": "OLD_IMAGE" + }, + "userIdentity": { + "principalId": "dynamodb.amazonaws.com", + "type": "Service" + }, + "eventSourceARN": "arn:aws:dynamodb:us-east-1:some-account:table/some-ddb-table/stream/2021-07-26T22:26:39.107" + }] + } + +user_identity = { + "principalId": "dynamodb.amazonaws.com", + "type": "Service" +} + +log = logging.getLogger() +log.setLevel('INFO') +reip = RemoveExpiredIP(event, log) + +def test_is_none(): + is_not_none = reip.is_none('some_value') + is_none = reip.is_none(None) + assert is_not_none == 'some_value' and is_none == 'None' + +def test_is_ddb_stream_event(): + is_ddb_stream_event = reip.is_ddb_stream_event(user_identity) + assert is_ddb_stream_event == True + +def test_deserialize_ddb_data(): + record = event['Records'][0] + ddb_ip_set = reip.is_none(record.get('dynamodb', {}).get('OldImage', {})) + desiralized_ddb_ip_set = reip.deserialize_ddb_data(ddb_ip_set) + expected_desiralized_ddb_ip_set = {'IPSetName': 'some-ip-set-name', 'CreatedByUser': 'some-user', 'Scope': 'CLOUDFRONT', 'CreationTime': Decimal('1628203216'), 'LockToken': 'some-lock_token', 'IPAdressList': ['x.x.x.x/32', 'y.y.y.y/32'], 'ExpirationTime': Decimal('1628203246'), 'IPSetId': 'some-ips-set-id'} + assert desiralized_ddb_ip_set == expected_desiralized_ddb_ip_set + +def test_make_ip_list(): + waf_ip_list = ['x.x.x.x/32', 'y.y.y.y/32'] + ddb_ip_list = ['x.x.x.x/32', 'y.y.y.y/32', 'z.z.z.z/32', 'x.y.y.y/32', 'x.x.y.y/32'] + keep_ip_list, remove_ip_list = reip.make_ip_list(log, waf_ip_list, ddb_ip_list) + assert keep_ip_list == [] + assert len(remove_ip_list) > 0 \ No newline at end of file diff --git a/source/ip_retention_handler/test/test_set_ip_retention.py b/source/ip_retention_handler/test/test_set_ip_retention.py new file mode 100644 index 00000000..175c74d1 --- /dev/null +++ b/source/ip_retention_handler/test/test_set_ip_retention.py @@ -0,0 +1,92 @@ +############################################################################## +# Copyright Amazon.com, Inc. and its affiliates. All Rights Reserved. +# # +# Licensed under the Amazon Software License (the "License"). You may not # +# use this file except in compliance with the License. A copy of the # +# License is located at # +# # +# http://aws.amazon.com/asl/ # +# # +# or in the "license" file accompanying this file. This file is distributed # +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, # +# express or implied. See the License for the specific language governing # +# permissions and limitations under the License. # +############################################################################## + +import logging +import os +from set_ip_retention import SetIPRetention + +event ={ + "eventVersion": "1.08", + "userIdentity": { + "type": "AssumedRole", + "principalId": "some-id", + "arn": "some-arn", + "accountId": "some-account", + "accessKeyId": "some-key-id", + "sessionContext": { + "sessionIssuer": { + "type": "Role", + "principalId": "some-id", + "arn": "some-arn", + "accountId": "some-account", + "userName": "some-username" + }, + "webIdFederationData": {}, + "attributes": { + "creationDate": "2021-07-26T17:42:52Z", + "mfaAuthenticated": "false" + } + } + }, + "eventTime": "2021-07-26T22:33:04Z", + "eventSource": "wafv2.amazonaws.com", + "eventName": "UpdateIPSet", + "awsRegion": "us-east-1", + "sourceIPAddress": "some-ip", + "userAgent": "aws-internal/3 aws-sdk-java/1.11.1004 Linux/5.4.116-64.217.amzn2int.x86_64 OpenJDK_64-Bit_Server_VM/25.292-b10 java/1.8.0_292 vendor/Oracle_Corporation cfg/retry-mode/legacy", + "requestParameters": { + "name": "some-Whitelist-ip-set-name", + "scope": "CLOUDFRONT", + "id": "some-ip-set-id", + "description": "Allow List for IPV4 addresses", + "addresses": [ + "x.x.x.x/32", + "y.y.y.y/32", + "z.z.z.z/32" + ], + "lockToken": "some-lock-token" + }, + "responseElements": { + "nextLockToken": "some-next-lock-token" + }, + "requestID": "some-request-id", + "eventID": "some-event-id", + "readOnly": 'false', + "eventType": "AwsApiCall", + "apiVersion": "2019-04-23", + "managementEvent": 'true', + "recipientAccountId": "some-account", + "eventCategory": "Management" + } + +log = logging.getLogger() +log.setLevel('INFO') +sipr = SetIPRetention(event, log) + +os.environ["TABLE_NAME"] = 'test_table' +os.environ['IP_RETENTION_PEROID_ALLOWED_MINUTE'] = '5' +os.environ['STACK_NAME'] = 'waf-solution' + +def test_get_expiration_time(): + epoch_time = sipr.get_expiration_time("2021-07-26T22:33:04Z", 5) + assert epoch_time == 1627339084 + +def test_make_item(): + item = sipr.make_item(event) + + # Remove CreationTime as it is current timestamp that constantly changes + del item['CreationTime'] + + assert item == {'IPSetId': 'some-ip-set-id', 'IPSetName': 'some-Whitelist-ip-set-name', 'Scope': 'CLOUDFRONT', 'IPAdressList': ['x.x.x.x/32', 'y.y.y.y/32', 'z.z.z.z/32'], 'LockToken': 'some-lock-token', 'IPRetentionPeriodMinute': 15, 'ExpirationTime': 1627339684, 'CreatedByUser': 'waf-solution'} \ No newline at end of file diff --git a/source/tests/testing_requirements.txt b/source/ip_retention_handler/testing_requirements.txt similarity index 77% rename from source/tests/testing_requirements.txt rename to source/ip_retention_handler/testing_requirements.txt index cc39f42e..2ea602b5 100644 --- a/source/tests/testing_requirements.txt +++ b/source/ip_retention_handler/testing_requirements.txt @@ -7,4 +7,6 @@ pytest-mock>=1.10.4 pytest-runner>=2.11.1 uuid>=1.30 backoff>=1.8.0 -freezegun>=0.3.15 \ No newline at end of file +freezegun>=0.3.15 +pytest-cov +pytest-env \ No newline at end of file diff --git a/source/lib/boto3_util.py b/source/lib/boto3_util.py new file mode 100644 index 00000000..b0684ba3 --- /dev/null +++ b/source/lib/boto3_util.py @@ -0,0 +1,63 @@ +###################################################################################################################### +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance # +# with the License. A copy of the License is located at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES # +# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions # +# and limitations under the License. # +###################################################################################################################### +#!/bin/python + +import boto3 +import logging +from os import environ +from botocore.config import Config + +log = logging.getLogger() + +def create_client(service_name, max_attempt=5, mode='standard', user_agent_extra=environ.get('USER_AGENT_EXTRA'), my_config = {}): + """ + This function creates a boto3 client given a service and its configurations + """ + try: + config = Config( + user_agent_extra=user_agent_extra, + retries={'max_attempts': max_attempt, 'mode': mode} + ) + if my_config != {}: + config = my_config + + return boto3.client( + service_name, + config = config + ) + except Exception as e: + log.error("[boto3_util: create_client] failed to create client") + log.error(e) + raise e + + +def create_resource(service_name, max_attempt=5, mode='standard', user_agent_extra=environ.get('USER_AGENT_EXTRA'), my_config = {}): + """ + This function creates a boto3 resource given a service and its configurations + """ + try: + config = Config( + user_agent_extra=user_agent_extra, + retries={'max_attempts': max_attempt, 'mode': mode} + ) + if my_config != {}: + config = my_config + + return boto3.resource( + service_name, + config = config + ) + except Exception as e: + log.error("[boto3_util: create_resource] failed to create resource") + log.error(e) + raise e \ No newline at end of file diff --git a/source/lib/dynamodb_util.py b/source/lib/dynamodb_util.py new file mode 100644 index 00000000..c5d18f10 --- /dev/null +++ b/source/lib/dynamodb_util.py @@ -0,0 +1,36 @@ +###################################################################################################################### +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance # +# with the License. A copy of the License is located at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES # +# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions # +# and limitations under the License. # +###################################################################################################################### + +# !/bin/python + +from lib.boto3_util import create_resource + +dynamodb_resource = create_resource('dynamodb') + +class DDB(object): + def __init__(self, log, table_name): + self.log = log + self.table_name = table_name + self.table = dynamodb_resource.Table(self.table_name) + + # DDB API call to put an item + def put_item(self, item): + try: + response = self.table.put_item( + Item=item + ) + return response + except Exception as e: + self.log.error(e) + self.log.error("dynamodblib: failed to put item: \n{}".format(item)) + return None diff --git a/source/lib/sns_util.py b/source/lib/sns_util.py new file mode 100644 index 00000000..47617704 --- /dev/null +++ b/source/lib/sns_util.py @@ -0,0 +1,36 @@ +###################################################################################################################### +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance # +# with the License. A copy of the License is located at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES # +# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions # +# and limitations under the License. # +###################################################################################################################### +#!/bin/python + +import boto3 +from os import environ +from botocore.config import Config +from lib.boto3_util import create_client + +class SNS(object): + def __init__(self, log): + self.log = log + self.sns_client = create_client('sns') + + def publish(self, topic_arn, message, subject): + try: + response = self.sns_client.publish( + TopicArn=topic_arn, + Message=message, + Subject=subject + ) + return response + except Exception as e: + self.log.error("[sns_util: publish] failed to send email notificaion: \nTopic Arn: %s\nMessage: %s", topic_arn, message) + self.log.error(e) + return None diff --git a/source/lib/solution_metrics.py b/source/lib/solution_metrics.py index b4f6594b..c2fab3f8 100644 --- a/source/lib/solution_metrics.py +++ b/source/lib/solution_metrics.py @@ -17,7 +17,10 @@ import requests from json import dumps from datetime import datetime +import logging +log = logging.getLogger(__name__) +log.setLevel('INFO') def send_metrics(data, uuid=os.getenv('UUID'), @@ -45,5 +48,6 @@ def send_metrics(data, headers = {'content-type': 'application/json'} response = requests.post(url, data=json_data, headers=headers) return response - except: - pass + except Exception as e: + log.error("[solution_metrics:send_metrics] Failed to send solution metrics.") + log.error(str(e)) \ No newline at end of file diff --git a/source/lib/waflibv2.py b/source/lib/waflibv2.py index 4b974a0e..5d443395 100644 --- a/source/lib/waflibv2.py +++ b/source/lib/waflibv2.py @@ -10,17 +10,17 @@ # OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions # # and limitations under the License. # ###################################################################################################################### -import os -import boto3 -import logging -from botocore.config import Config +# import boto3 +# from botocore.config import Config +from botocore.exceptions import ClientError from ipaddress import ip_address -import sys -from backoff import on_exception, expo +from backoff import on_exception, expo, full_jitter +from lib.boto3_util import create_client API_CALL_NUM_RETRIES = 5 -MAX_TIME = 10 -client = boto3.client('wafv2', config=Config(retries={'max_attempts': API_CALL_NUM_RETRIES})) +MAX_TIME = 20 + +client = create_client('wafv2') class WAFLIBv2(object): @@ -62,7 +62,24 @@ def set_ip_cidr(self, log, source_ip): ip_class = "32" if ip_type == "IPV4" else "128" return str(source_ip)+"/"+str(ip_class) - # Retrieve IPSet based on ip_set_id + # Retrieve IPSet given an ip_set_id + def get_ip_set_by_id(self, log, scope, name, ip_set_id): + try: + log.debug("[waflib:get_ip_set_by_id] Start") + response = client.get_ip_set( + Scope=scope, + Name=name, + Id=ip_set_id + ) + log.debug("[waflib:get_ip_set_by_id] got ip set: \n{}.".format(response)) + log.debug("[waflib:get_ip_set_by_id] End") + return response + except Exception as e: + log.error("[waflib:get_ip_set_by_id] Failed to get IPSet %s", str(ip_set_id)) + log.error(str(e)) + return None + + # Retrieve IPSet given an ip set arn @on_exception(expo, client.exceptions.WAFInternalErrorException, max_time=MAX_TIME) def get_ip_set(self, log, scope, name, arn): try: @@ -92,12 +109,56 @@ def get_addresses(self, log, scope, name, arn): log.error(str(e)) return None - # Update addresses in an IPSet - @on_exception(expo, - (client.exceptions.WAFInternalErrorException, - client.exceptions.WAFOptimisticLockException, - client.exceptions.WAFLimitsExceededException), - max_time=MAX_TIME) + # Update addresses in an IPSet using ip set id + @on_exception(expo, client.exceptions.WAFOptimisticLockException, + max_time=MAX_TIME, + jitter=full_jitter, + max_tries=API_CALL_NUM_RETRIES) + def update_ip_set_by_id(self, log, scope, name, ip_set_id, addresses, lock_token, description): + log.debug("[waflib:update_ip_set_by_id] Start") + + try: + response = client.update_ip_set( + Scope=scope, + Name=name, + Id=ip_set_id, + Addresses=addresses, + LockToken=lock_token, + Description=description + ) + + log.debug("[waflib:update_ip_set_by_id] update ip set response: \n{}.".format(response)) + log.debug("[waflib:update_ip_set_by_id] End") + return response + # Get the latest ip set and retry updating api call when OptimisticLockException occurs + except ClientError as ex: + exception_type = ex.response['Error']['Code'] + if exception_type in ['OptimisticLockException']: + log.info("[waflib:update_ip_set_by_id] OptimisticLockException detected. Get the latest ip set and retry updating ip set.") + ip_set = self.get_ip_set_by_id(log, scope, name, ip_set_id) + lock_token = ip_set['LockToken'] + + response = client.update_ip_set( + Scope=scope, + Name=name, + Id=ip_set_id, + Addresses=addresses, + LockToken=lock_token, + Description=description + ) + log.debug("[waflib:update_ip_set_id] End") + return response + except Exception as e: + log.error(e) + log.error("[waflib:update_ip_set_by_id] Failed to update IPSet: %s", str(ip_set_id)) + return None + + + # Update addresses in an IPSet using ip set arn + @on_exception(expo, client.exceptions.WAFOptimisticLockException, + max_time=MAX_TIME, + jitter=full_jitter, + max_tries=API_CALL_NUM_RETRIES) def update_ip_set(self, log, scope, name, ip_set_arn, addresses): log.info("[waflib:update_ip_set] Start") if (ip_set_arn is None or name is None): @@ -112,7 +173,7 @@ def update_ip_set(self, log, scope, name, ip_set_arn, addresses): ip_set = self.get_ip_set(log, scope, name, ip_set_arn) lock_token = ip_set['LockToken'] description = ip_set['IPSet']['Description'] - log.info("Updating IPSet with description: %s", str(description)) + log.info("Updating IPSet with description: %s, lock token: %s", str(description), str(lock_token)) response = client.update_ip_set( Scope=scope, @@ -124,6 +185,8 @@ def update_ip_set(self, log, scope, name, ip_set_arn, addresses): ) new_ip_set = self.get_ip_set(log, scope, name, ip_set_id) + + log.debug("[waflib:update_ip_set] update ip set response:\n{}".format(response)) log.info("[waflib:update_ip_set] End") return new_ip_set except Exception as e: @@ -174,7 +237,11 @@ def list_web_acls(self, log, scope): log.error(str(e)) return None - + # log when retry is stopped + # def give_up_retry(self, log, e): + # log.error("Giving up retry after %s times.",str(API_CALL_NUM_RETRIES)) + # log.error(e) + ################################################################# # Following functions only used for testing, not in WAF Solution ################################################################# @@ -240,4 +307,4 @@ def list_ip_sets(self, log, scope, marker=None): except Exception as e: log.error("Failed to list IPSets in scope: %s", str(scope)) log.error(str(e)) - return None + return None \ No newline at end of file diff --git a/source/log_parser/add_athena_partitions.py b/source/log_parser/add_athena_partitions.py index 51212500..ac65c55a 100644 --- a/source/log_parser/add_athena_partitions.py +++ b/source/log_parser/add_athena_partitions.py @@ -18,7 +18,8 @@ import re import logging from os import environ - +from botocore.config import Config +from lib.boto3_util import create_client def lambda_handler(event, context): """ @@ -41,7 +42,7 @@ def lambda_handler(event, context): # ---------------------------------------------------------- log.info(event) - athena_client = boto3.client('athena') + athena_client = create_client('athena') database_name = event['glueAccessLogsDatabase'] access_log_bucket = event['accessLogBucket'] waf_log_bucket = event['wafLogBucket'] diff --git a/source/log_parser/log-parser.py b/source/log_parser/log-parser.py index 0d0393d7..3da7f14e 100644 --- a/source/log_parser/log-parser.py +++ b/source/log_parser/log-parser.py @@ -19,6 +19,8 @@ import datetime import os from os import environ, remove +from botocore.config import Config +from time import sleep from urllib.parse import unquote_plus from urllib.parse import urlparse import requests @@ -27,12 +29,13 @@ from lib.solution_metrics import send_metrics from build_athena_queries import build_athena_query_for_app_access_logs, \ build_athena_query_for_waf_logs +from lib.boto3_util import create_client, create_resource logging.getLogger().debug('Loading function') api_call_num_retries = 5 max_descriptors_per_ip_set_update = 500 -delay_between_updates = 2 +delay_between_updates = 5 scope = os.getenv('SCOPE') scanners = 1 flood = 2 @@ -140,6 +143,10 @@ def update_ip_set(log, ip_set_type, outstanding_requesters): log.info("[update_ip_set] \tCommit changes in WAF IP set") # -------------------------------------------------------------------------------------------------------------- response = waflib.update_ip_set(log, scope, ipset_name_v4, ipset_arn_v4, addresses_v4) + + # Sleep for a few seconds to mitigate AWS WAF Update API call throttling issue + sleep(delay_between_updates) + response = waflib.update_ip_set(log, scope, ipset_name_v6, ipset_arn_v6, addresses_v6) except Exception as error: @@ -157,7 +164,7 @@ def send_anonymous_usage_data(log): log.info("[send_anonymous_usage_data] Start") - cw = boto3.client('cloudwatch') + cw = create_client('cloudwatch') usage_data = { "data_type": "log_parser", "scanners_probes_set_size": 0, @@ -456,7 +463,7 @@ def process_athena_scheduler_event(log, event): def execute_athena_query(log, log_type, event): log.debug('[execute_athena_query] Start') - athena_client = boto3.client('athena') + athena_client = create_client('athena') s3_output = "s3://%s/athena_results/" % event['accessLogBucket'] database_name = event['glueAccessLogsDatabase'] @@ -506,7 +513,7 @@ def process_athena_result(log, bucket_name, key_name, ip_set_type): log.info("[process_athena_result] \tDownload file from S3") # -------------------------------------------------------------------------------------------------------------- local_file_path = '/tmp/' + key_name.split('/')[-1] - s3 = boto3.client('s3') + s3 = create_client('s3') s3.download_file(bucket_name, key_name, local_file_path) # -------------------------------------------------------------------------------------------------------------- @@ -546,8 +553,8 @@ def load_configurations(log, bucket_name, key_name): log.debug('[load_configurations] Start') try: - s3 = boto3.resource('s3') - file_obj = s3.Object(bucket_name, key_name) + s3_resource = create_resource('s3') + file_obj = s3_resource.Object(bucket_name, key_name) file_content = file_obj.get()['Body'].read() global config @@ -577,12 +584,13 @@ def get_outstanding_requesters(log, bucket_name, key_name, log_type): log.info("[get_outstanding_requesters] \tDownload file from S3") # -------------------------------------------------------------------------------------------------------------- local_file_path = '/tmp/' + key_name.split('/')[-1] - s3 = boto3.client('s3') + s3 = create_client('s3') s3.download_file(bucket_name, key_name, local_file_path) # -------------------------------------------------------------------------------------------------------------- log.info("[get_outstanding_requesters] \tRead file content") # -------------------------------------------------------------------------------------------------------------- + error_count = 0 with gzip.open(local_file_path, 'r') as content: for line in content: try: @@ -620,7 +628,7 @@ def get_outstanding_requesters(log, bucket_name, key_name, log_type): request_key += ' ' + line_data[LINE_FORMAT_CLOUD_FRONT['time']][:-3] request_key += ' ' + line_data[LINE_FORMAT_CLOUD_FRONT['source_ip']] return_code_index = LINE_FORMAT_CLOUD_FRONT['code'] - uri = urlparse(line_data[LINE_FORMAT_ALB['uri']]).path + uri = urlparse(line_data[LINE_FORMAT_CLOUD_FRONT['uri']]).path else: return outstanding_requesters @@ -647,7 +655,11 @@ def get_outstanding_requesters(log, bucket_name, key_name, log_type): counter['uriList'][uri][request_key] = 1 except Exception as e: + error_count += 1 log.error("[get_outstanding_requesters] \t\tError to process line: %s" % line) + log.error(str(e)) + if error_count == 5: #Allow 5 errors before stopping the function execution + raise remove(local_file_path) # -------------------------------------------------------------------------------------------------------------- @@ -700,7 +712,7 @@ def merge_outstanding_requesters(log, bucket_name, key_name, log_type, output_ke force_update = False need_update = False - s3 = boto3.client('s3') + s3 = create_client('s3') # -------------------------------------------------------------------------------------------------------------- log.info("[merge_outstanding_requesters] \tCalculate Last Update Age") @@ -848,7 +860,7 @@ def write_output(log, bucket_name, key_name, output_key_name, outstanding_reques with open(current_data, 'w') as outfile: json.dump(outstanding_requesters, outfile) - s3 = boto3.client('s3') + s3 = create_client('s3') s3.upload_file(current_data, bucket_name, output_key_name, ExtraArgs={'ContentType': "application/json"}) remove(current_data) @@ -961,6 +973,7 @@ def lambda_handler(event, context): except Exception as error: log.error(str(error)) + raise log.info('[lambda_handler] End') return result diff --git a/source/log_parser/partition_s3_logs.py b/source/log_parser/partition_s3_logs.py index 0a303afb..1d02ac69 100644 --- a/source/log_parser/partition_s3_logs.py +++ b/source/log_parser/partition_s3_logs.py @@ -18,7 +18,8 @@ import re import logging from os import environ - +from botocore.config import Config +from lib.boto3_util import create_client def lambda_handler(event, context): """ @@ -53,7 +54,7 @@ def lambda_handler(event, context): logging.getLogger().info("\n[partition_s3_logs lambda_handler] KEEP ORIGINAL DATA: %s; End POINT: %s." %(keep_original_data, endpoint)) - s3 = boto3.client('s3') + s3 = create_client('s3') count = 0 diff --git a/source/log_parser/test/__init__.py b/source/log_parser/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/source/tests/test_build_athena_queries.py b/source/log_parser/test/test_build_athena_queries.py similarity index 89% rename from source/tests/test_build_athena_queries.py rename to source/log_parser/test/test_build_athena_queries.py index ec378019..23904271 100644 --- a/source/tests/test_build_athena_queries.py +++ b/source/log_parser/test/test_build_athena_queries.py @@ -16,7 +16,7 @@ import sys import datetime import logging -from log_parser import build_athena_queries, add_athena_partitions +import build_athena_queries, add_athena_partitions from datetime import datetime from freezegun import freeze_time @@ -40,7 +40,7 @@ def test_build_athena_queries_for_cloudfront_logs(): log, cloudfront_log_type, database_name, table_name, end_timestamp, waf_block_period, error_threshold) - with open('../source/tests/cloudfront_logs_query.txt', 'r') as file: + with open('./test/test_data/cloudfront_logs_query.txt', 'r') as file: cloudfront_logs_query = file.read() assert type(query_string) is str assert query_string == cloudfront_logs_query @@ -51,7 +51,7 @@ def test_build_athena_queries_for_alb_logs(): log, alb_log_type, database_name, table_name, end_timestamp, waf_block_period, error_threshold) - with open('../source/tests/alb_logs_query.txt', 'r') as file: + with open('./test/test_data/alb_logs_query.txt', 'r') as file: alb_logs_query = file.read() assert type(query_string) is str assert query_string == alb_logs_query @@ -62,7 +62,7 @@ def test_build_athena_queries_for_waf_logs(): log, database_name, table_name, end_timestamp, waf_block_period, request_threshold) - with open('../source/tests/waf_logs_query.txt', 'r') as file: + with open('./test/test_data/waf_logs_query.txt', 'r') as file: waf_logs_query = file.read() assert type(query_string) is str assert query_string == waf_logs_query @@ -73,7 +73,7 @@ def test_add_athena_partitions_build_query_string(): query_string = add_athena_partitions.build_athena_query( log, database_name, table_name) - with open('../source/tests/athena_partitions_query.txt', 'r') as file: + with open('./test/test_data/athena_partitions_query.txt', 'r') as file: athena_partitions_query = file.read() assert type(query_string) is str assert query_string == athena_partitions_query diff --git a/source/tests/alb_logs_query.txt b/source/log_parser/test/test_data/alb_logs_query.txt similarity index 100% rename from source/tests/alb_logs_query.txt rename to source/log_parser/test/test_data/alb_logs_query.txt diff --git a/source/tests/athena_partitions_query.txt b/source/log_parser/test/test_data/athena_partitions_query.txt similarity index 100% rename from source/tests/athena_partitions_query.txt rename to source/log_parser/test/test_data/athena_partitions_query.txt diff --git a/source/tests/cloudfront_logs_query.txt b/source/log_parser/test/test_data/cloudfront_logs_query.txt similarity index 100% rename from source/tests/cloudfront_logs_query.txt rename to source/log_parser/test/test_data/cloudfront_logs_query.txt diff --git a/source/tests/waf_logs_query.txt b/source/log_parser/test/test_data/waf_logs_query.txt similarity index 100% rename from source/tests/waf_logs_query.txt rename to source/log_parser/test/test_data/waf_logs_query.txt diff --git a/source/tests/test_solution_metrics.py b/source/log_parser/test/test_solution_metrics.py similarity index 100% rename from source/tests/test_solution_metrics.py rename to source/log_parser/test/test_solution_metrics.py diff --git a/source/log_parser/testing_requirements.txt b/source/log_parser/testing_requirements.txt new file mode 100644 index 00000000..2ea602b5 --- /dev/null +++ b/source/log_parser/testing_requirements.txt @@ -0,0 +1,12 @@ +botocore>=1.12.99 +boto3>=1.9.99 +mock>=2.0.0 +moto>=1.3.8 +pytest>=4.4.1 +pytest-mock>=1.10.4 +pytest-runner>=2.11.1 +uuid>=1.30 +backoff>=1.8.0 +freezegun>=0.3.15 +pytest-cov +pytest-env \ No newline at end of file diff --git a/source/reputation_lists_parser/reputation-lists.py b/source/reputation_lists_parser/reputation-lists.py index 127f772b..ff64d785 100644 --- a/source/reputation_lists_parser/reputation-lists.py +++ b/source/reputation_lists_parser/reputation-lists.py @@ -17,16 +17,21 @@ import requests import json import re +from time import sleep from ipaddress import ip_address from ipaddress import ip_network from ipaddress import IPv4Network from ipaddress import IPv6Network import boto3 +from os import environ +from botocore.config import Config from lib.solution_metrics import send_metrics from lib.waflibv2 import WAFLIBv2 +from lib.boto3_util import create_client waflib = WAFLIBv2() +delay_between_updates = 5 # Find matching ip address ranges from a line def find_ips(line, prefix=""): @@ -103,6 +108,9 @@ def populate_ipsets(log, scope, ipset_name_v4, ipset_name_v6, ipset_arn_v4, ipse log.info(ipset) log.info("There are %d IP addresses in IPSet %s", len(ipset["IPSet"]["Addresses"]), ipset_name_v4) + # Sleep for a few seconds to mitigate AWS WAF Update API call throttling issue + sleep(delay_between_updates) + waflib.update_ip_set(log, scope, ipset_name_v6, ipset_arn_v6, addressesV6) ipset = waflib.get_ip_set(log, scope, ipset_name_v6, ipset_arn_v6) @@ -157,7 +165,7 @@ def send_anonymous_usage_data(log, scope): return log.debug("[send_anonymous_usage_data] Start") - cw = boto3.client('cloudwatch') + cw = create_client('cloudwatch') usage_data = { "data_type": "reputation_lists", "ipv4_reputation_lists_size": 0,