

# Plan your deployment
<a name="plan-your-deployment"></a>

This section describes the [cost](cost.md), [security](security.md), [Quotas](quotas.md), and other considerations prior to deploying the solution.

## Supported AWS Regions
<a name="supported-aws-regions"></a>

Depending on the template input parameters values you define, this solution requires different resources. These resources (listed in the following table) might not be available in all AWS Regions. Therefore, you must launch this solution in an AWS Region where these services are available. For the most current availability of AWS services by Region, see the [AWS Regional Services List](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/).


|  | AWS WAF Web ACL | AWS Glue | Amazon Athena | Amazon Kinesis Data Firehose | 
| --- | --- | --- | --- | --- | 
|   **Endpoint type**   |  |  |  |  | 
|  CloudFront  |  ✓  |  |  |  | 
|  Application Load Balancer (ALB)  |  ✓  |  |  |  | 
|   **Activate HTTP Flood Protection**   |  |  |  |  | 
|  yes - AWS Lambda log parser  |  |  |  |  ✓  | 
|  yes - Amazon Athena log parser  |  |  ✓  |  ✓  |  ✓  | 
|   **Activate Scanner & Probe Protection**   |  |  |  |  | 
|  yes - Amazon Athena log parser  |  |  ✓  |  ✓  |  | 

**Note**  
If you choose `CloudFront` as your **Endpoint**, you must deploy the solution in the US East (N. Virginia) Region (`us-east-1`).

# Cost
<a name="cost"></a>

You’re responsible for the cost of the AWS services used while running the Security Automations for AWS WAF solution. The total cost for running this solution depends on the protection activated and the amount of data ingested, stored, and processed.

We recommend creating a [budget](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/budgets-create.html) through [AWS Cost Explorer](https://aws.amazon.com/aws-cost-management/aws-cost-explorer/) to help manage costs. For full details, refer to the pricing webpage for each AWS service you used in this solution.

The following tables are example cost breakdowns for running this solution in the US East (N. Virginia) Region (excludes AWS Free Tier). Prices are subject to change.

 **Example 1: Activate Reputation List Protection, Bad Bot Protection, AWS Lambda Log Parser for HTTP Flood Protection, and Scanner & Probe Protection** 


| AWS service | Dimensions/Month | Cost [USD] | 
| --- | --- | --- | 
|  Amazon Data Firehose  |  100 GB  |  \$1\$12.90  | 
|  Amazon S3  |  100 GB  |  \$1\$12.30  | 
|  AWS Lambda  |  128 MB: 3 functions, 1M invocations, and average 500 millisecond duration per Lambda run 512 MB: 2 functions, 1M invocations, and average 500 millisecond duration per Lambda run  |  \$1\$15.40  | 
|  AWS WAF web ACL  |  1  |  \$15.00  | 
|  AWS WAF rule  |  4  |  \$14.00  | 
|  AWS WAF request  |  1M  |  \$10.60  | 
|   **Total**   |  |   **\$1\$120.60 per month**   | 

 **Example 2: Activate Reputation List Protection, Bad Bot Protection, Amazon Athena Log Parser for HTTP Flood Protection, and Scanner & Probe Protection** 


| AWS service | Dimensions/Month | Cost [USD] | 
| --- | --- | --- | 
|  Amazon Data Firehose  |  100 GB  |  \$1\$12.90  | 
|  Amazon S3  |  100 GB  |  \$1\$12.30  | 
|  AWS Lambda  |  128 MB: 3 functions, 1M invocations ,and average 500 millisecond duration per Lambda run 512 MB: 2 functions, 7560 invocations, and average 500 millisecond duration per Lambda run  |  \$1\$11.26  | 
|  Amazon Athena  |  1.2M CloudFront objects hits or 1.2M ALB requests per day that generates a \$1500 byte log record per hit or request  |  \$1\$14.32  | 
|  AWS WAF web ACL  |  1  |  \$15.00  | 
|  AWS WAF rule  |  4  |  \$14.00  | 
|  AWS WAF request  |  1M  |  \$10.60  | 
|   **Total**   |  |   **\$1\$120.38** **per month**   | 

 **Example 3: Activate IP Retention for Allowed and Denied IP Sets** 


| AWS service | Dimensions/Month | Cost [USD] | 
| --- | --- | --- | 
|  Amazon DynamoDB  |  1K writes and 1 MB data storage  |  \$1\$10.00  | 
|  AWS Lambda  |  128 MB: 1 function, 2K invocations, and average 500 millisecond duration per Lambda run 512 MB: 1 function, 2K invocations, and average 500 millisecond duration per Lambda run  |  \$1\$10.01  | 
|  Amazon CloudWatch  |  2K events  |  \$1\$10.00  | 
|  AWS WAF Web ACL  |  1  |  \$15.00  | 
|  AWS WAF Rule  |  2  |  \$12.00  | 
|  WAS WAF request  |  1M  |  \$10.60  | 
|   **Total**   |  |   **\$1\$17.61** **per month**   | 

## Cost estimate of CloudWatch logs
<a name="cost-estimate-of-cloudwatch-logs"></a>

Some AWS services used in this solution, such as Lambda, generate CloudWatch logs. These logs incur [charges](https://aws.amazon.com/cloudwatch/pricing/). We recommend deleting or archiving logs to reduce the cost. For log archive detail, refer to [Exporting log data to Amazon S3](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/S3Export.html) in the *Amazon CloudWatch Logs User Guide*.

If you choose to use the Athena log parser on installation, this solution schedules a query to run against the AWS WAF or application access logs in your Amazon S3 bucket(s) as configured. You’re charged based on the amount of data scanned by each query. The solution applies partitioning to logs and queries to minimize costs. By default, the solution moves application access logs from their original Amazon S3 location to a partitioned folder structure. You can also retain original, but you will be charged for duplicated log storage. This solution uses [workgroups](https://docs.aws.amazon.com/athena/latest/ug/manage-queries-control-costs-with-workgroups.html) to segment workloads, and you can configure both to manage query access and costs. Refer to [Cost estimate of Athena](#cost-estimate-of-athena) for a sample cost estimate calculation. For more information, refer to [Amazon Athena Pricing](https://aws.amazon.com/athena/pricing/).

## Cost estimate of Athena
<a name="cost-estimate-of-athena"></a>

If you use the Athena log parser option while running the **HTTP Flood Protection**, **Scanner & Probe Protection** or **Bad Bot Protection** rules, you will be charged for Athena usage. By default, each Athena query runs every five minutes and scans the past four hours of data. The solution applies partitioning to logs and Athena queries to minimize costs. You can configure the number of hours of data that a query scans by changing the value for the **WAF Block Period** template parameter. However, increasing the amount of data scanned will likely increase the Athena cost.

**Tip**  
The following is an example CloudFront logs cost calculation:  
On average, each CloudFront hit might generate around 500 bytes of data.  
If there are 1.2M CloudFront objects hit per day, then there will be 200K (1.2M/6) hits per four hours, assuming that data is ingested at a consistent rate. Consider your actual traffic patterns when calculate your cost.  
 `[500 bytes of data] * [200K hits per four hours] = [an average 100 MB (0.0001TB) data scanned per query]`   
Athena charges \$15.00 per TB of data scanned.  
 `[0.0001 TB] * [$5] = [$0.0005 per query scan]`   
The Athena query runs every five minutes, which is 12 runs per hour.  
 `[12 runs] * [24 hours] = [288 runs per day]`   
 `[$0.0005 per query scan] * [288 runs per day] * [30 days] = [$4.32 per month]`   
Actual costs vary depending on your application’s traffic patterns. For more information, refer to [Amazon Athena Pricing](https://aws.amazon.com/athena/pricing/).

# Security
<a name="security"></a>

When you build systems on AWS infrastructure, security responsibilities are shared between you and AWS. This [shared responsibility model](https://aws.amazon.com/compliance/shared-responsibility-model/) reduces your operational burden because AWS operates, manages, and controls the components including the host operating system, the virtualization layer, and the physical security of the facilities in which the services operate. For more information about AWS security, visit [AWS Cloud Security](https://aws.amazon.com/security/).

## IAM roles
<a name="iam-roles"></a>

With IAM roles, you can assign granular access, policies, and permissions to services and users on the AWS Cloud. This solution creates IAM roles with least privileges, and these roles grant the solution’s resources with needed permissions.

## Data
<a name="data"></a>

All data stored in Amazon S3 buckets and DynamoDB tables have encryption at rest. Data in transit with Firehose are also encrypted.

## Protection capabilities
<a name="protection-capabilities"></a>

Web applications are vulnerable to a variety of attacks. These attacks include specially crafted requests designed to exploit a vulnerability or take control of a server; volumetric attacks designed to take down a website; or bad bots and scrapers programmed to scrape and steal web content.

This solution uses CloudFormation to configure AWS WAF rules, including AWS Managed Rules rule groups and custom rules, to block the following common attacks:
+  **AWS Managed Rules** - This managed service provides protection against common application vulnerabilities or other unwanted traffic. This solution includes [AWS Managed IP reputation rule groups](https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-ip-rep.html), [AWS Managed baseline rule groups](https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-baseline.html), and [AWS Managed use-case specific rule groups](https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-use-case.html). You have the option of selecting one or more rules groups for your web ACL, up to the maximum web ACL capacity unit (WCU) quota.
+  **SQL injection** - Attackers insert malicious SQL code into web requests to extract data from your database. We designed this solution to block web requests that contain potentially malicious SQL code.
+  **XSS** - Attackers use vulnerabilities in a benign website as a vehicle to inject malicious client-site scripts into a legitimate user’s web browser. We designed this to inspect commonly explored elements of incoming requests to identify and block XSS attacks.
+  **HTTP floods** - Web servers and other backend resources are at risk of DDoS attacks, such as HTTP floods. This solution automatically invokes a rate-based rule when web requests from a client exceed a configurable quota. Alternatively, you can enforce this quota by processing AWS WAF logs using a Lambda function or Athena query.
+  **Scanners and probes** - Malicious sources scan and probe internet-facing web applications for vulnerabilities, by sending a series of requests that generate HTTP 4xx error codes. You can use this history to help identify and block malicious source IP addresses. This solution creates a Lambda function or Athena query that automatically parses CloudFront or ALB access logs, counts the number of bad requests from unique source IP addresses per minute, and updates AWS WAF to block further scans from addresses that reached the defined error quota.
+  **Known attacker origins (IP reputation lists)** - Many organizations maintain reputation lists of IP addresses operated by known attackers, such as spammers, malware distributors, and botnets. This solution leverages the information in these reputation lists to help you block requests from malicious IP addresses. In addition, this solution blocks attackers identified by IP reputation rule groups based on Amazon internal threat intelligence.
+  **Bots and scrapers** - Operators of publicly accessible web applications need to trust that the clients accessing their content identify themselves accurately, and that they use services as intended. However, some automated clients, such as content scrapers or bad bots, misrepresent themselves to bypass restrictions. This solution helps you identify and block bad bots and scrapers.

# Quotas
<a name="quotas"></a>

Service quotas, also referred to as limits, are the maximum number of service resources or operations for your AWS account.

## Quotas for AWS services in this solution
<a name="quotas-for-aws-services-in-this-solution"></a>

Make sure you have sufficient quota for each of the [services implemented in this solution](architecture-details.md#aws-services-in-this-solution). For more information, refer to [AWS service quotas](https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html). To see the service quotas for all AWS services in the documentation without switching pages, view the information in the [Service endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/aws-general.pdf#aws-service-information) page in the PDF instead.

## AWS WAF quotas
<a name="aws-waf-quotas"></a>

AWS WAF can block a maximum of 10,000 IP address ranges in Classless Inter-Domain Routing (CIDR) notation per IP match condition. Each list that this solution creates is subject to this quota. For more information, refer to [AWS WAF quotas](https://docs.aws.amazon.com/waf/latest/developerguide/limits.html). As of version 3.0, this solution creates two IP sets to attach to each rule, one for IPv4 and one for IPv6.

AWS WAF allows a maximum of one request per second, per account, per AWS Region for API calls to any individual `Create`, `Put`, or `Update` action. If you make these API calls outside the solution, you might encounter an API throttling issue. To prevent the issue, we recommend avoiding running other applications that make these API calls in the same account and Region where this solution is deployed.

# Deployment considerations
<a name="deployment-considerations"></a>

The following sections provide constraints and considerations for implementing this solution.

## AWS WAF rules
<a name="aws-waf-rules"></a>

The web ACL that this solution generates is designed to offer comprehensive protection for web applications. The solution provides a set of AWS Managed Rules and custom rules that you can add to the web ACL. To include a rule, choose `yes` for the relevant parameters when launching the CloudFormation stack. See [Step 1. Launch the stack](step-1.-launch-the-stack.md) for the list of parameters.

**Note**  
The out-of-box solution doesn’t support [AWS Firewall Manager](https://aws.amazon.com/firewall-manager). If you want to use the rules in Firewall Manager, we recommend that you to apply customizations to its [source code](https://github.com/aws-solutions/aws-waf-security-automations).

## Web ACL traffic logging
<a name="web-acl-traffic-logging"></a>

If you create the stack in an AWS Region other than US East (N. Virginia) and set the **Endpoint** as `CloudFront`, you must set **Activate HTTP Flood Protection** to `no` or `yes - AWS WAF rate based rule`.

The other two options (`yes - AWS Lambda log parser` and `yes - Amazon Athena log parser`) require activating AWS WAF logs on a web ACL that runs in all AWS edge locations, and this isn’t supported outside US East (N. Virginia). For more information about logging Web ACL traffic, refer to the [AWS WAF developer guide](https://docs.aws.amazon.com/waf/latest/developerguide/logging.html).

## Oversize handling for request components
<a name="oversize-handling-for-request-components"></a>

AWS WAF doesn’t support inspecting oversized content for the web request component’s body, headers, or cookies. When you write a rule statement that inspects one of these request component types, you can choose one of these options to tell AWS WAF what to do with these requests:
+  `yes` (continue) - Inspect the request component normally according to the rule inspection criteria. AWS WAF inspects the request component contents that are within the size limitations. This is the default option used in the solution.
+  `yes - MATCH` - Treat the web request as matching the rule statement. AWS WAF applies the rule action to the request without evaluating it against the rule’s inspection criteria. For a rule with `Block` action, this blocks the request with the oversize component.
+  `yes - NO_MATCH` - Treat the web request as not matching the rule statement, without evaluating it against the rule’s inspection criteria. AWS WAF continues its inspection of the web request by using the rest of the rules in the web ACL, like it would do for any non-matching rule.

For more information, refer to [Handling oversize web request components in AWS WAF](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-oversize-handling.html).

## Multiple solution deployments
<a name="multiple-solution-deployments"></a>

You can deploy the solution multiple times in the same account and Region. You must use a unique CloudFormation stack name and Amazon S3 bucket name for each deployment. Each unique deployment incurs additional charges and is subject to the [AWS WAF quotas](https://docs.aws.amazon.com/waf/latest/developerguide/limits.html) per account, per Region.

## Minimum role permissions for deployment (Optional)
<a name="minimum-role-permissions"></a>

Customers can manually create an IAM role with the minimum required permissions for deployment:
+ WAF Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "wafv2:CreateWebACL",
                "wafv2:UpdateWebACL",
                "wafv2:DeleteWebACL",
                "wafv2:GetWebACL",
                "wafv2:ListWebACLs",
                "wafv2:CreateIPSet",
                "wafv2:UpdateIPSet",
                "wafv2:DeleteIPSet",
                "wafv2:GetIPSet",
                "wafv2:AssociateWebACL",
                "wafv2:DisassociateWebACL",
                "wafv2:PutLoggingConfiguration",
                "wafv2:DeleteLoggingConfiguration",
                "wafv2:ListWebACLs",
                "wafv2:ListIPSets",
                "wafv2:ListTagsForResource"
            ],
            "Resource": [
                "arn:aws:wafv2:*:*:regional/webacl/*",
                "arn:aws:wafv2:*:*:regional/ipset/*",
                "arn:aws:wafv2:*:*:global/webacl/*",
                "arn:aws:wafv2:*:*:global/ipset/*"
            ]
        }
```
+ Lambda Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "lambda:CreateFunction",
                "lambda:DeleteFunction",
                "lambda:GetFunction",
                "lambda:InvokeFunction",
                "lambda:UpdateFunctionCode",
                "lambda:UpdateFunctionConfiguration",
                "lambda:AddPermission",
                "lambda:RemovePermission"
            ],
            "Resource": "arn:aws:lambda:*:*:function:*"
        }
```
+ Firehose Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "firehose:CreateDeliveryStream",
                "firehose:DeleteDeliveryStream",
                "firehose:DescribeDeliveryStream",
                "firehose:StartDeliveryStreamEncryption",
                "firehose:StopDeliveryStreamEncryption",
                "firehose:UpdateDestination"
            ],
            "Resource": "arn:aws:firehose:*:*:deliverystream/*"
        }
```
+ S3 Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "s3:CreateBucket",
                "s3:DeleteBucketPolicy",
                "s3:GetBucketAcl",
                "s3:GetBucketPolicy",
                "s3:GetObject",
                "s3:PutBucketAcl",
                "s3:PutBucketPolicy",
                "s3:PutBucketPublicAccessBlock",
                "s3:PutBucketVersioning",
                "s3:PutEncryptionConfiguration",
                "s3:PutObject",
                "s3:PutBucketTagging",
                "s3:PutLifecycleConfiguration",
                "s3:AbortMultipartUpload",
                "s3:GetBucketLocation",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:ListMultipartUploadParts",
                "s3:PutBucketLogging",
                "s3:GetBucketLogging"
            ],
            "Resource": "arn:aws:s3:::*"
        }
```
+ Athena Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "athena:CreateWorkGroup",
                "athena:DeleteWorkGroup",
                "athena:GetWorkGroup",
                "athena:UpdateWorkGroup",
                "athena:StartQueryExecution",
                "athena:GetQueryExecution",
                "athena:GetQueryResults",
                "athena:StopQueryExecution"
            ],
            "Resource": "arn:aws:athena:*:*:workgroup/WAF*"
        }
```
+ Glue Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "glue:CreateDatabase",
                "glue:DeleteDatabase",
                "glue:GetDatabase",
                "glue:GetDatabases",
                "glue:UpdateDatabase",
                "glue:CreateTable",
                "glue:DeleteTable",
                "glue:GetTable",
                "glue:GetTables",
                "glue:UpdateTable"
            ],
            "Resource": [
                "arn:aws:glue:*:*:catalog",
                "arn:aws:glue:*:*:database/*",
                "arn:aws:glue:*:*:table/*/*",
                "arn:aws:glue:*:*:userDefinedFunction/*"
            ]
        }
```
+ CloudWatch Logs Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "logs:DeleteLogGroup",
                "logs:DeleteLogStream",
                "logs:PutRetentionPolicy",
                "logs:DescribeLogGroups"
            ],
            "Resource": [
                "arn:aws:logs:*:*:log-group:/aws/lambda/*",
                "arn:aws:logs:*:*:log-group:*",
                "arn:aws:logs:*:*:log-group:/aws/kinesisfirehose/*"
            ]
        }
```
+ CloudWatch Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "cloudwatch:DeleteDashboards",
                "cloudwatch:GetDashboard",
                "cloudwatch:ListDashboards",
                "cloudwatch:PutDashboard",
                "cloudwatch:PutMetricData"
            ],
            "Resource": "*"
        }
```
+ SNS Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "sns:CreateTopic",
                "sns:DeleteTopic",
                "sns:Subscribe",
                "sns:Unsubscribe",
                "sns:SetTopicAttributes"
            ],
            "Resource": "arn:aws:sns:*:*:*"
        }
```
+ DynamoDB Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:CreateTable",
                "dynamodb:DeleteTable",
                "dynamodb:DescribeTable",
                "dynamodb:PutItem",
                "dynamodb:GetItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem"
            ],
            "Resource": "arn:aws:dynamodb:*:*:table/*"
        }
```
+ CloudFormation Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "cloudformation:CreateStack",
                "cloudformation:DeleteStack",
                "cloudformation:DescribeStacks",
                "cloudformation:UpdateStack",
                "cloudformation:ListStacks"
            ],
            "Resource": "arn:aws:cloudformation:*:*:stack/*/*"
        }
```
+ Service Catalog App Registry Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "servicecatalog:CreateApplication",
                "servicecatalog:DeleteApplication",
                "servicecatalog:GetApplication",
                "servicecatalog:TagResource",
                "servicecatalog:CreateAttributeGroup",
                "servicecatalog:DeleteAttributeGroup",
                "servicecatalog:GetAttributeGroup",
                "servicecatalog:AssociateAttributeGroup",
                "servicecatalog:DisassociateAttributeGroup",
                "servicecatalog:AssociateResource",
                "servicecatalog:DisassociateResource"
            ],
            "Resource": "arn:aws:servicecatalog:*:*:*"
        }
```
+ X-Ray Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "xray:PutTraceSegments",
                "xray:PutTelemetryRecords"
            ],
            "Resource": "*"
        }
```
+ IAM Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "iam:AttachRolePolicy",
                "iam:CreatePolicy",
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:DeleteRolePolicy",
                "iam:DetachRolePolicy",
                "iam:GetRole",
                "iam:GetRolePolicy",
                "iam:ListRoles",
                "iam:PassRole",
                "iam:PutRolePolicy"
            ],
            "Resource": "arn:aws:iam::*:role/*"
        }
```
+ EventBridge Permissions

```
        {
            "Effect": "Allow",
            "Action": [
                "events:PutTargets",
                "events:RemoveTargets",
                "events:DescribeRule",
                "events:EnableRule",
                "events:ListRules",
                "events:PutRule",
                "events:DeleteRule",
                "events:ListEventSources",
                "events:DescribeEventSource",
                "events:ActivateEventSource",
                "events:DeactivateEventSource"
            ],
            "Resource": "arn:aws:events:*:*:rule/*"
        }
```