diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0a26a19..f279bb5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.5.0 + rev: v3.1.0 hooks: - id: check-added-large-files args: ['--maxkb=500'] @@ -18,7 +18,7 @@ repos: args: ['--allow-missing-credentials'] - id: trailing-whitespace - repo: git://github.com/antonbabenko/pre-commit-terraform - rev: v1.29.0 + rev: v1.31.0 hooks: - id: terraform_fmt - id: terraform_docs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7795df5..3a12873 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,13 @@ All notable changes to this project will be documented in this file. ## [Unreleased] -- update docs and add chglog + + + +## [0.2.0] - 2020-05-28 + +- Allow conditional association with ALB +- Feature/updates ([#3](https://github.com/umotif-public/terraform-aws-waf-webaclv2/issues/3)) @@ -23,5 +29,6 @@ All notable changes to this project will be documented in this file. - Initial commit -[Unreleased]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/0.1.0...HEAD +[Unreleased]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/0.2.0...HEAD +[0.2.0]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/0.1.0...0.2.0 [0.1.0]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/0.0.1...0.1.0 diff --git a/README.md b/README.md index 5409b31..ca35c22 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,7 @@ Terraform module to configure WAF WebACL V2 for Application Load Balancer. -This module is initally configured to use cloudformation as Terraform doesn't support WAFv2 API. Issue tracking progress on this can be found -> https://github.com/terraform-providers/terraform-provider-aws/issues/11046. - -This module will progress to version 1.0.0 once full support from Terraform is implemented and provided as part of terraform-aws-provider. - -Module support all AWS managed rules defained in https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html. +Module supports all AWS managed rules defained in https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html. ## Terraform versions @@ -19,13 +15,61 @@ Please pin down version of this module to exact version. ```hcl module "waf" { source = "umotif-public/waf-webaclv2/aws" - version = "0.1.0" + version = "~> 1.0.0" name_prefix = "test-waf-setup" alb_arn = module.alb.arn - enable_CommonRuleSet = true - enable_PHPRuleSet = true + create_alb_association = true + + visibility_config = { + cloudwatch_metrics_enabled = false + metric_name = "test-waf-setup-waf-main-metrics" + sampled_requests_enabled = false + } + + rules = [ + { + name = "AWSManagedRulesCommonRuleSet-rule-1" + priority = "1" + + visibility_config = { + cloudwatch_metrics_enabled = false + metric_name = "AWSManagedRulesCommonRuleSet-metric" + sampled_requests_enabled = false + } + + managed_rule_group_statement = { + name = "AWSManagedRulesCommonRuleSet" + vendor_name = "AWS" + excluded_rule = [ + "SizeRestrictions_QUERYSTRING", + "SizeRestrictions_BODY", + "GenericRFI_QUERYARGUMENTS" + ] + } + }, + { + name = "AWSManagedRulesKnownBadInputsRuleSet-rule-2" + priority = "2" + + visibility_config = { + cloudwatch_metrics_enabled = false + metric_name = "AWSManagedRulesKnownBadInputsRuleSet-metric" + sampled_requests_enabled = false + } + + managed_rule_group_statement = { + name = "AWSManagedRulesKnownBadInputsRuleSet" + vendor_name = "AWS" + } + } + ] + + tags = { + "Name" = "test-waf-setup" + "Env" = "test" + } } ``` @@ -33,6 +77,17 @@ module "waf" { Module is to be used with Terraform > 0.12. +## Current Limitations/Issues + +1. All rules deployed via this module are set to blocking mode. At this stage, I was unable to find a way to pass following block as an environment variable (feel free to create a PR to resolve it): +```tf +default_action { + block {} +} +``` +This problem is tracked -> https://discuss.hashicorp.com/t/conditional-block-or-allow-variable-for-wafv2-resource-when-using-override-action-or-default-action/10162 +2. There is a terraform provider issue where you can't update tags once your WAFv2 is deployed. Issue reported -> https://github.com/terraform-providers/terraform-provider-aws/issues/13863 + ## Examples * [WAF ACL](https://github.com/umotif-public/terraform-aws-waf-webaclv2/tree/master/examples/core) @@ -44,60 +99,37 @@ Module managed by [Marcin Cuber](https://github.com/marcincuber) [LinkedIn](http ## Requirements -No requirements. +| Name | Version | +|------|---------| +| terraform | ~> 0.12.6 | +| aws | ~> 2.67 | ## Providers | Name | Version | |------|---------| -| aws | n/a | +| aws | ~> 2.67 | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| AdminProtectionRuleSetExcludedRules | n/a | `string` | `""` | no | -| AmazonIpReputationListExcludedRules | n/a | `string` | `""` | no | -| CommonRuleSetExcludedRules | n/a | `string` | `""` | no | -| KnownBadInputsRuleSetExcludedRules | n/a | `string` | `""` | no | -| LinuxRuleSetExcludedRules | n/a | `string` | `""` | no | -| PHPRuleSetExcludedRules | n/a | `string` | `""` | no | -| RulesAnonymousIpListExcludedRules | n/a | `string` | `""` | no | -| SQLiRuleSetExcludedRules | n/a | `string` | `""` | no | -| UnixRuleSetExcludedRules | n/a | `string` | `""` | no | -| WindowsRuleSetExcludedRules | n/a | `string` | `""` | no | -| WordPressRuleSetExcludedRules | n/a | `string` | `""` | no | | alb\_arn | Application Load Balancer ARN | `string` | `""` | no | -| enable\_AdminProtectionRuleSet | n/a | `bool` | `false` | no | -| enable\_AmazonIpReputationList | n/a | `bool` | `false` | no | -| enable\_AnonymousIpList | n/a | `bool` | `false` | no | -| enable\_CommonRuleSet | n/a | `bool` | `false` | no | -| enable\_DefaultActionAllow | n/a | `bool` | `true` | no | -| enable\_KnownBadInputsRuleSet | n/a | `bool` | `false` | no | -| enable\_LinuxRuleSet | n/a | `bool` | `false` | no | -| enable\_OverrideActionCountAdminProtectionRuleSet | n/a | `bool` | `true` | no | -| enable\_OverrideActionCountAmazonIpReputationList | n/a | `bool` | `true` | no | -| enable\_OverrideActionCountAnonymousIpList | n/a | `bool` | `true` | no | -| enable\_OverrideActionCountCommonRuleSet | n/a | `bool` | `true` | no | -| enable\_OverrideActionCountKnownBadInputsRuleSet | n/a | `bool` | `true` | no | -| enable\_OverrideActionCountLinuxRuleSet | n/a | `bool` | `true` | no | -| enable\_OverrideActionCountPHPRuleSet | n/a | `bool` | `true` | no | -| enable\_OverrideActionCountSQLiRuleSet | n/a | `bool` | `true` | no | -| enable\_OverrideActionCountUnixRuleSet | n/a | `bool` | `true` | no | -| enable\_OverrideActionCountWindowsRuleSet | n/a | `bool` | `true` | no | -| enable\_OverrideActionCountWordPressRuleSet | n/a | `bool` | `true` | no | -| enable\_PHPRuleSet | n/a | `bool` | `false` | no | -| enable\_SQLiRuleSet | n/a | `bool` | `false` | no | -| enable\_UnixRuleSet | n/a | `bool` | `false` | no | -| enable\_WindowsRuleSet | n/a | `bool` | `false` | no | -| enable\_WordPressRuleSet | n/a | `bool` | `false` | no | +| create\_alb\_association | Whether to create alb association with WAF web acl | `bool` | `true` | no | | enabled | Whether to create the resources. Set to `false` to prevent the module from creating any resources | `bool` | `true` | no | | name\_prefix | Name prefix used to create resources. | `string` | n/a | yes | +| rules | List of WAF rules. | `list` | `[]` | no | | tags | A map of tags (key-value pairs) passed to resources. | `map(string)` | `{}` | no | +| visibility\_config | Visibility config for WAFv2 web acl. https://www.terraform.io/docs/providers/aws/r/wafv2_web_acl.html#visibility-configuration | `map(string)` | `{}` | no | ## Outputs -No output. +| Name | Description | +|------|-------------| +| web\_acl\_arn | n/a | +| web\_acl\_capacity | n/a | +| web\_acl\_id | n/a | +| web\_acl\_name | n/a | diff --git a/cfm/waf.yaml b/cfm/waf.yaml deleted file mode 100644 index 1167f5a..0000000 --- a/cfm/waf.yaml +++ /dev/null @@ -1,523 +0,0 @@ -Description: WebACL WAFv2 - -Parameters: - AlbArn: - Type: String - Description: "Arn of the Application loadbalancer to associate with WAF" - Default: "no" - NamePrefix: - Type: String - Description: "Name Prefix" - AWSManagedRulesCommonRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "no" - AWSManagedRulesAdminProtectionRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "no" - AWSManagedRulesKnownBadInputsRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "no" - AWSManagedRulesSQLiRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "no" - AWSManagedRulesLinuxRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "no" - AWSManagedRulesUnixRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "no" - AWSManagedRulesWindowsRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "no" - AWSManagedRulesPHPRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "no" - AWSManagedRulesWordPressRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "no" - AWSManagedRulesAmazonIpReputationListEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "no" - AWSManagedRulesAnonymousIpListEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "no" - - DefaultActionAllowEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - - OverrideActionCountCommonRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - OverrideActionCountAdminProtectionRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - OverrideActionCountKnownBadInputsRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - OverrideActionCountSQLiRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - OverrideActionCountLinuxRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - OverrideActionCountUnixRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - OverrideActionCountWindowsRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - OverrideActionCountPHPRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - OverrideActionCountWordPressRuleSetEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - OverrideActionCountAmazonIpReputationListEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - OverrideActionCountAnonymousIpListEnabled: - Type: String - AllowedValues: - - "yes" - - "no" - Default: "yes" - - CommonRuleSetExcludedRules: - Type: String - Default: "" - AdminProtectionRuleSetExcludedRules: - Type: String - Default: "" - KnownBadInputsRuleSetExcludedRules: - Type: String - Default: "" - SQLiRuleSetExcludedRules: - Type: String - Default: "" - LinuxRuleSetExcludedRules: - Type: String - Default: "" - UnixRuleSetExcludedRules: - Type: String - Default: "" - WindowsRuleSetExcludedRules: - Type: String - Default: "" - PHPRuleSetExcludedRules: - Type: String - Default: "" - WordPressRuleSetExcludedRules: - Type: String - Default: "" - AmazonIpReputationListExcludedRules: - Type: String - Default: "" - RulesAnonymousIpListExcludedRules: - Type: String - Default: "" - -Conditions: - IsAWSManagedRulesCommonRuleSetEnabled: !Equals [ !Ref AWSManagedRulesCommonRuleSetEnabled , "yes" ] - IsAWSManagedRulesAdminProtectionRuleSetEnabled: !Equals [ !Ref AWSManagedRulesAdminProtectionRuleSetEnabled , "yes" ] - IsAWSManagedRulesKnownBadInputsRuleSetEnabled: !Equals [ !Ref AWSManagedRulesKnownBadInputsRuleSetEnabled , "yes" ] - IsAWSManagedRulesSQLiRuleSetEnabled: !Equals [ !Ref AWSManagedRulesSQLiRuleSetEnabled , "yes" ] - IsAWSManagedRulesLinuxRuleSetEnabled: !Equals [ !Ref AWSManagedRulesLinuxRuleSetEnabled , "yes" ] - IsAWSManagedRulesUnixRuleSetEnabled: !Equals [ !Ref AWSManagedRulesUnixRuleSetEnabled , "yes" ] - IsAWSManagedRulesWindowsRuleSetEnabled: !Equals [ !Ref AWSManagedRulesWindowsRuleSetEnabled , "yes" ] - IsAWSManagedRulesPHPRuleSetEnabled: !Equals [ !Ref AWSManagedRulesPHPRuleSetEnabled , "yes" ] - IsAWSManagedRulesWordPressRuleSetEnabled: !Equals [ !Ref AWSManagedRulesWordPressRuleSetEnabled , "yes" ] - IsAWSManagedRulesAmazonIpReputationListEnabled: !Equals [ !Ref AWSManagedRulesAmazonIpReputationListEnabled , "yes" ] - IsAWSManagedRulesAnonymousIpListEnabled: !Equals [ !Ref AWSManagedRulesAnonymousIpListEnabled , "yes" ] - - IsDefaultActionAllowEnabled: !Equals [ !Ref DefaultActionAllowEnabled , "yes" ] - - IsOverrideActionCountCommonRuleSetEnabled: !Equals [ !Ref OverrideActionCountCommonRuleSetEnabled , "yes" ] - IsOverrideActionCountAdminProtectionRuleSetEnabled: !Equals [ !Ref OverrideActionCountAdminProtectionRuleSetEnabled, "yes" ] - IsOverrideActionCountKnownBadInputsRuleSetEnabled: !Equals [ !Ref OverrideActionCountKnownBadInputsRuleSetEnabled, "yes" ] - IsOverrideActionCountSQLiRuleSetEnabled: !Equals [ !Ref OverrideActionCountSQLiRuleSetEnabled, "yes" ] - IsOverrideActionCountLinuxRuleSetEnabled: !Equals [ !Ref OverrideActionCountLinuxRuleSetEnabled, "yes" ] - IsOverrideActionCountUnixRuleSetEnabled: !Equals [ !Ref OverrideActionCountUnixRuleSetEnabled, "yes" ] - IsOverrideActionCountWindowsRuleSetEnabled: !Equals [ !Ref OverrideActionCountWindowsRuleSetEnabled, "yes" ] - IsOverrideActionCountPHPRuleSetEnabled: !Equals [ !Ref OverrideActionCountPHPRuleSetEnabled, "yes" ] - IsOverrideActionCountWordPressRuleSetEnabled: !Equals [ !Ref OverrideActionCountWordPressRuleSetEnabled, "yes" ] - IsOverrideActionCountAmazonIpReputationListEnabled: !Equals [ !Ref OverrideActionCountAmazonIpReputationListEnabled, "yes" ] - IsOverrideActionCountAnonymousIpListEnabled: !Equals [ !Ref OverrideActionCountAnonymousIpListEnabled, "yes" ] - - IsCommonRuleSetExcludedRules: !Equals [ !Ref CommonRuleSetExcludedRules, "" ] - IsAdminProtectionRuleSetExcludedRules: !Equals [ !Ref AdminProtectionRuleSetExcludedRules, "" ] - IsKnownBadInputsRuleSetExcludedRules: !Equals [ !Ref KnownBadInputsRuleSetExcludedRules, "" ] - IsSQLiRuleSetExcludedRules: !Equals [ !Ref SQLiRuleSetExcludedRules, "" ] - IsLinuxRuleSetExcludedRules: !Equals [ !Ref LinuxRuleSetExcludedRules, "" ] - IsUnixRuleSetExcludedRules: !Equals [ !Ref UnixRuleSetExcludedRules, "" ] - IsWindowsRuleSetExcludedRules: !Equals [ !Ref WindowsRuleSetExcludedRules, "" ] - IsPHPRuleSetExcludedRules: !Equals [ !Ref PHPRuleSetExcludedRules, "" ] - IsWordPressRuleSetExcludedRules: !Equals [ !Ref WordPressRuleSetExcludedRules, "" ] - IsAmazonIpReputationListExcludedRules: !Equals [ !Ref AmazonIpReputationListExcludedRules, "" ] - IsRulesAnonymousIpListExcludedRules: !Equals [ !Ref RulesAnonymousIpListExcludedRules, "" ] - - IsAlbArnProvided: !Not [!Equals [ !Ref AlbArn, "no" ]] - -Resources: - WAFWebACL: - Type: AWS::WAFv2::WebACL - Properties: - Name: !Sub "${NamePrefix}-WAFv2-WebACL" - Scope: REGIONAL - DefaultAction: - 'Fn::If': - - IsDefaultActionAllowEnabled - - Allow: {} - - Block: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFv2WebACLMetric" - Rules: - - Fn::If: - - IsAWSManagedRulesCommonRuleSetEnabled - - - Name: AWSManagedRulesCommonRuleSet - Priority: 0 - OverrideAction: - 'Fn::If': - - IsOverrideActionCountCommonRuleSetEnabled - - Count: {} - - None: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFCommonRuleSetMetric" - Statement: - ManagedRuleGroupStatement: - VendorName: AWS - Name: AWSManagedRulesCommonRuleSet - ExcludedRules: - 'Fn::If': - - IsCommonRuleSetExcludedRules - - [] - - 'Fn::Split': [ ",", !Ref CommonRuleSetExcludedRules ] - - !Ref 'AWS::NoValue' - - Fn::If: - - IsAWSManagedRulesAdminProtectionRuleSetEnabled - - - Name: AWSManagedRulesAdminProtectionRuleSet - Priority: 1 - OverrideAction: - 'Fn::If': - - IsOverrideActionCountAdminProtectionRuleSetEnabled - - Count: {} - - None: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFAdminProtectionRuleSetMetric" - Statement: - ManagedRuleGroupStatement: - VendorName: AWS - Name: AWSManagedRulesAdminProtectionRuleSet - ExcludedRules: - 'Fn::If': - - IsAdminProtectionRuleSetExcludedRules - - [] - - 'Fn::Split': [ ",", !Ref AdminProtectionRuleSetExcludedRules ] - - !Ref 'AWS::NoValue' - - Fn::If: - - IsAWSManagedRulesKnownBadInputsRuleSetEnabled - - - Name: AWSManagedRulesKnownBadInputsRuleSet - Priority: 2 - OverrideAction: - 'Fn::If': - - IsOverrideActionCountKnownBadInputsRuleSetEnabled - - Count: {} - - None: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFKnownBadInputsRuleSetMetric" - Statement: - ManagedRuleGroupStatement: - VendorName: AWS - Name: AWSManagedRulesKnownBadInputsRuleSet - ExcludedRules: - 'Fn::If': - - IsKnownBadInputsRuleSetExcludedRules - - [] - - 'Fn::Split': [ ",", !Ref KnownBadInputsRuleSetExcludedRules ] - - !Ref 'AWS::NoValue' - - Fn::If: - - IsAWSManagedRulesSQLiRuleSetEnabled - - - Name: AWSManagedRulesSQLiRuleSet - Priority: 3 - OverrideAction: - 'Fn::If': - - IsOverrideActionCountSQLiRuleSetEnabled - - Count: {} - - None: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFSQLiRuleSetMetric" - Statement: - ManagedRuleGroupStatement: - VendorName: AWS - Name: AWSManagedRulesSQLiRuleSet - ExcludedRules: - 'Fn::If': - - IsSQLiRuleSetExcludedRules - - [] - - 'Fn::Split': [ ",", !Ref SQLiRuleSetExcludedRules ] - - !Ref 'AWS::NoValue' - - Fn::If: - - IsAWSManagedRulesLinuxRuleSetEnabled - - - Name: AWSManagedRulesLinuxRuleSet - Priority: 4 - OverrideAction: - 'Fn::If': - - IsOverrideActionCountLinuxRuleSetEnabled - - Count: {} - - None: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFLinuxRuleSetMetric" - Statement: - ManagedRuleGroupStatement: - VendorName: AWS - Name: AWSManagedRulesLinuxRuleSet - ExcludedRules: - 'Fn::If': - - IsLinuxRuleSetExcludedRules - - [] - - 'Fn::Split': [ ",", !Ref LinuxRuleSetExcludedRules ] - - !Ref 'AWS::NoValue' - - Fn::If: - - IsAWSManagedRulesUnixRuleSetEnabled - - - Name: AWSManagedRulesUnixRuleSet - Priority: 5 - OverrideAction: - 'Fn::If': - - IsOverrideActionCountUnixRuleSetEnabled - - Count: {} - - None: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFUnixRuleSetMetric" - Statement: - ManagedRuleGroupStatement: - VendorName: AWS - Name: AWSManagedRulesUnixRuleSet - ExcludedRules: - 'Fn::If': - - IsUnixRuleSetExcludedRules - - [] - - 'Fn::Split': [ ",", !Ref UnixRuleSetExcludedRules ] - - !Ref 'AWS::NoValue' - - Fn::If: - - IsAWSManagedRulesWindowsRuleSetEnabled - - - Name: AWSManagedRulesWindowsRuleSet - Priority: 6 - OverrideAction: - 'Fn::If': - - IsOverrideActionCountWindowsRuleSetEnabled - - Count: {} - - None: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFWindowsRuleSetMetric" - Statement: - ManagedRuleGroupStatement: - VendorName: AWS - Name: AWSManagedRulesWindowsRuleSet - ExcludedRules: - 'Fn::If': - - IsWindowsRuleSetExcludedRules - - [] - - 'Fn::Split': [ ",", !Ref WindowsRuleSetExcludedRules ] - - !Ref 'AWS::NoValue' - - Fn::If: - - IsAWSManagedRulesPHPRuleSetEnabled - - - Name: AWSManagedRulesPHPRuleSet - Priority: 7 - OverrideAction: - 'Fn::If': - - IsOverrideActionCountPHPRuleSetEnabled - - Count: {} - - None: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFPHPRuleSetMetric" - Statement: - ManagedRuleGroupStatement: - VendorName: AWS - Name: AWSManagedRulesPHPRuleSet - ExcludedRules: - 'Fn::If': - - IsPHPRuleSetExcludedRules - - [] - - 'Fn::Split': [ ",", !Ref PHPRuleSetExcludedRules ] - - !Ref 'AWS::NoValue' - - Fn::If: - - IsAWSManagedRulesWordPressRuleSetEnabled - - - Name: AWSManagedRulesWordPressRuleSet - Priority: 8 - OverrideAction: - 'Fn::If': - - IsOverrideActionCountWordPressRuleSetEnabled - - Count: {} - - None: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFWordPressRuleSetMetric" - Statement: - ManagedRuleGroupStatement: - VendorName: AWS - Name: AWSManagedRulesWordPressRuleSet - ExcludedRules: - 'Fn::If': - - IsWordPressRuleSetExcludedRules - - [] - - 'Fn::Split': [ ",", !Ref WordPressRuleSetExcludedRules ] - - !Ref 'AWS::NoValue' - - Fn::If: - - IsAWSManagedRulesAmazonIpReputationListEnabled - - - Name: AWSManagedRulesAmazonIpReputationList - Priority: 9 - OverrideAction: - 'Fn::If': - - IsOverrideActionCountAmazonIpReputationListEnabled - - Count: {} - - None: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFAmazonIpReputationListMetric" - Statement: - ManagedRuleGroupStatement: - VendorName: AWS - Name: AWSManagedRulesAmazonIpReputationList - ExcludedRules: - 'Fn::If': - - IsAmazonIpReputationListExcludedRules - - [] - - 'Fn::Split': [ ",", !Ref AmazonIpReputationListExcludedRules ] - - !Ref 'AWS::NoValue' - - Fn::If: - - IsAWSManagedRulesAnonymousIpListEnabled - - - Name: AWSManagedRulesAnonymousIpList - Priority: 10 - OverrideAction: - 'Fn::If': - - IsOverrideActionCountAnonymousIpListEnabled - - Count: {} - - None: {} - VisibilityConfig: - SampledRequestsEnabled: true - CloudWatchMetricsEnabled: true - MetricName: !Sub "${NamePrefix}-WAFAnonymousIpListMetric" - Statement: - ManagedRuleGroupStatement: - VendorName: AWS - Name: AWSManagedRulesAnonymousIpList - ExcludedRules: - 'Fn::If': - - IsRulesAnonymousIpListExcludedRules - - [] - - 'Fn::Split': [ ",", !Ref RulesAnonymousIpListExcludedRules ] - - !Ref 'AWS::NoValue' - - WAFWebACLAssociation: - Type: AWS::WAFv2::WebACLAssociation - Condition: IsAlbArnProvided - Properties: - ResourceArn: - Ref: AlbArn - WebACLArn: - Fn::GetAtt: [ WAFWebACL, Arn ] - -Outputs: - WAFWebName: - Description: The name of the created WafWebACL - Value: !Select [ 0, !Split ["|", !Ref WAFWebACL ]] - WAFWebArn: - Description: The ARN of the created WafWebACL - Value: !GetAtt [ WAFWebACL, Arn ] diff --git a/examples/core/main.tf b/examples/core/main.tf index 2af867f..05f57fa 100644 --- a/examples/core/main.tf +++ b/examples/core/main.tf @@ -26,7 +26,7 @@ module "vpc" { ##### module "alb" { source = "umotif-public/alb/aws" - version = "~> 1.0" + version = "~> 1.2.0" name_prefix = "alb-example" load_balancer_type = "application" @@ -77,7 +77,7 @@ resource "aws_ecs_cluster" "cluster" { module "fargate" { source = "umotif-public/ecs-fargate/aws" - version = "~> 1.1.1" + version = "~> 3.0.0" name_prefix = "ecs-fargate-example" vpc_id = module.vpc.vpc_id @@ -98,27 +98,77 @@ module "fargate" { } } +##### +# Web Application Firewall configuration +##### module "waf" { source = "../.." name_prefix = "test-waf-setup" alb_arn = module.alb.arn - enable_DefaultActionAllow = true - - enable_CommonRuleSet = true - enable_PHPRuleSet = true - enable_LinuxRuleSet = true - enable_SQLiRuleSet = true - enable_KnownBadInputsRuleSet = true - enable_UnixRuleSet = true + create_alb_association = true - enable_OverrideActionCountCommonRuleSet = false - enable_OverrideActionCountPHPRuleSet = false - enable_OverrideActionCountLinuxRuleSet = false - enable_OverrideActionCountSQLiRuleSet = false - enable_OverrideActionCountKnownBadInputsRuleSet = false - enable_OverrideActionCountUnixRuleSet = false + visibility_config = { + cloudwatch_metrics_enabled = false + metric_name = "test-waf-setup-waf-main-metrics" + sampled_requests_enabled = false + } - CommonRuleSetExcludedRules = "NoUserAgent_HEADER,UserAgent_BadBots_HEADER,SizeRestrictions_QUERYSTRING" + rules = [ + { + name = "AWSManagedRulesCommonRuleSet-rule-1" + priority = "1" + + visibility_config = { + cloudwatch_metrics_enabled = false + metric_name = "AWSManagedRulesCommonRuleSet-metric" + sampled_requests_enabled = false + } + + managed_rule_group_statement = { + name = "AWSManagedRulesCommonRuleSet" + vendor_name = "AWS" + excluded_rule = [ + "SizeRestrictions_QUERYSTRING", + "SizeRestrictions_BODY", + "GenericRFI_QUERYARGUMENTS" + ] + } + }, + { + name = "AWSManagedRulesKnownBadInputsRuleSet-rule-2" + priority = "2" + + visibility_config = { + cloudwatch_metrics_enabled = false + metric_name = "AWSManagedRulesKnownBadInputsRuleSet-metric" + sampled_requests_enabled = false + } + + managed_rule_group_statement = { + name = "AWSManagedRulesKnownBadInputsRuleSet" + vendor_name = "AWS" + } + }, + { + name = "AWSManagedRulesPHPRuleSet-rule-3" + priority = "3" + + visibility_config = { + cloudwatch_metrics_enabled = false + metric_name = "AWSManagedRulesPHPRuleSet-metric" + sampled_requests_enabled = false + } + + managed_rule_group_statement = { + name = "AWSManagedRulesPHPRuleSet" + vendor_name = "AWS" + } + } + ] + + tags = { + "Environment" = "test" + } } diff --git a/main.tf b/main.tf index b55aaf6..511b775 100644 --- a/main.tf +++ b/main.tf @@ -1,53 +1,68 @@ -resource "aws_cloudformation_stack" "waf" { +resource "aws_wafv2_web_acl" "main" { count = var.enabled ? 1 : 0 - name = "${var.name_prefix}-waf-stack" - capabilities = ["CAPABILITY_IAM"] - - template_body = file("${path.module}/cfm/waf.yaml") - - parameters = { - NamePrefix = var.name_prefix - AlbArn = var.alb_arn != "" ? var.alb_arn : "no" - - DefaultActionAllowEnabled = var.enable_DefaultActionAllow ? "yes" : "no" - - AWSManagedRulesCommonRuleSetEnabled = var.enable_CommonRuleSet ? "yes" : "no" - AWSManagedRulesAdminProtectionRuleSetEnabled = var.enable_AdminProtectionRuleSet ? "yes" : "no" - AWSManagedRulesKnownBadInputsRuleSetEnabled = var.enable_KnownBadInputsRuleSet ? "yes" : "no" - AWSManagedRulesSQLiRuleSetEnabled = var.enable_SQLiRuleSet ? "yes" : "no" - AWSManagedRulesLinuxRuleSetEnabled = var.enable_LinuxRuleSet ? "yes" : "no" - AWSManagedRulesUnixRuleSetEnabled = var.enable_UnixRuleSet ? "yes" : "no" - AWSManagedRulesWindowsRuleSetEnabled = var.enable_WindowsRuleSet ? "yes" : "no" - AWSManagedRulesPHPRuleSetEnabled = var.enable_PHPRuleSet ? "yes" : "no" - AWSManagedRulesWordPressRuleSetEnabled = var.enable_WordPressRuleSet ? "yes" : "no" - AWSManagedRulesAmazonIpReputationListEnabled = var.enable_AmazonIpReputationList ? "yes" : "no" - AWSManagedRulesAnonymousIpListEnabled = var.enable_AnonymousIpList ? "yes" : "no" - - OverrideActionCountCommonRuleSetEnabled = var.enable_OverrideActionCountCommonRuleSet ? "yes" : "no" - OverrideActionCountAdminProtectionRuleSetEnabled = var.enable_OverrideActionCountAdminProtectionRuleSet ? "yes" : "no" - OverrideActionCountKnownBadInputsRuleSetEnabled = var.enable_OverrideActionCountKnownBadInputsRuleSet ? "yes" : "no" - OverrideActionCountSQLiRuleSetEnabled = var.enable_OverrideActionCountSQLiRuleSet ? "yes" : "no" - OverrideActionCountLinuxRuleSetEnabled = var.enable_OverrideActionCountLinuxRuleSet ? "yes" : "no" - OverrideActionCountUnixRuleSetEnabled = var.enable_OverrideActionCountUnixRuleSet ? "yes" : "no" - OverrideActionCountWindowsRuleSetEnabled = var.enable_OverrideActionCountWindowsRuleSet ? "yes" : "no" - OverrideActionCountPHPRuleSetEnabled = var.enable_OverrideActionCountPHPRuleSet ? "yes" : "no" - OverrideActionCountWordPressRuleSetEnabled = var.enable_OverrideActionCountWordPressRuleSet ? "yes" : "no" - OverrideActionCountAmazonIpReputationListEnabled = var.enable_OverrideActionCountAmazonIpReputationList ? "yes" : "no" - OverrideActionCountAnonymousIpListEnabled = var.enable_OverrideActionCountAnonymousIpList ? "yes" : "no" - - CommonRuleSetExcludedRules = var.CommonRuleSetExcludedRules != "" ? var.CommonRuleSetExcludedRules : null - AdminProtectionRuleSetExcludedRules = var.AdminProtectionRuleSetExcludedRules != "" ? var.AdminProtectionRuleSetExcludedRules : null - KnownBadInputsRuleSetExcludedRules = var.KnownBadInputsRuleSetExcludedRules != "" ? var.KnownBadInputsRuleSetExcludedRules : null - SQLiRuleSetExcludedRules = var.SQLiRuleSetExcludedRules != "" ? var.SQLiRuleSetExcludedRules : null - LinuxRuleSetExcludedRules = var.LinuxRuleSetExcludedRules != "" ? var.LinuxRuleSetExcludedRules : null - UnixRuleSetExcludedRules = var.UnixRuleSetExcludedRules != "" ? var.UnixRuleSetExcludedRules : null - WindowsRuleSetExcludedRules = var.WindowsRuleSetExcludedRules != "" ? var.WindowsRuleSetExcludedRules : null - PHPRuleSetExcludedRules = var.PHPRuleSetExcludedRules != "" ? var.PHPRuleSetExcludedRules : null - WordPressRuleSetExcludedRules = var.WordPressRuleSetExcludedRules != "" ? var.WordPressRuleSetExcludedRules : null - AmazonIpReputationListExcludedRules = var.AmazonIpReputationListExcludedRules != "" ? var.AmazonIpReputationListExcludedRules : null - RulesAnonymousIpListExcludedRules = var.RulesAnonymousIpListExcludedRules != "" ? var.RulesAnonymousIpListExcludedRules : null + name = var.name_prefix + scope = "REGIONAL" + + default_action { + block {} + } + + dynamic "rule" { + for_each = var.rules + content { + name = lookup(rule.value, "name") + priority = lookup(rule.value, "priority") + + override_action { + none {} + } + + statement { + dynamic "managed_rule_group_statement" { + for_each = length(lookup(rule.value, "managed_rule_group_statement", {})) == 0 ? [] : [lookup(rule.value, "managed_rule_group_statement", {})] + content { + name = lookup(managed_rule_group_statement.value, "name") + vendor_name = lookup(managed_rule_group_statement.value, "vendor_name", "AWS") + + dynamic "excluded_rule" { + for_each = length(lookup(managed_rule_group_statement.value, "excluded_rule", {})) == 0 ? [] : toset(lookup(managed_rule_group_statement.value, "excluded_rule")) + content { + name = excluded_rule.value + } + } + } + } + } + + dynamic "visibility_config" { + for_each = length(lookup(rule.value, "visibility_config")) == 0 ? [] : [lookup(rule.value, "visibility_config", {})] + content { + cloudwatch_metrics_enabled = lookup(visibility_config.value, "cloudwatch_metrics_enabled", false) + metric_name = lookup(visibility_config.value, "metric_name", "${var.name_prefix}-default-rule-metric-name") + sampled_requests_enabled = lookup(visibility_config.value, "sampled_requests_enabled", false) + } + } + } } tags = var.tags + + dynamic "visibility_config" { + for_each = length(var.visibility_config) == 0 ? [] : [var.visibility_config] + content { + cloudwatch_metrics_enabled = lookup(visibility_config.value, "cloudwatch_metrics_enabled", false) + metric_name = lookup(visibility_config.value, "metric_name", "${var.name_prefix}-default-web-acl-metric-name") + sampled_requests_enabled = lookup(visibility_config.value, "sampled_requests_enabled", false) + } + } +} + +resource "aws_wafv2_web_acl_association" "main" { + count = var.enabled && var.create_alb_association ? 1 : 0 + + resource_arn = var.alb_arn + web_acl_arn = aws_wafv2_web_acl.main[0].arn + + depends_on = [aws_wafv2_web_acl.main] } diff --git a/outputs.tf b/outputs.tf index 4e875d7..1760bde 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,13 +1,15 @@ -locals { - waf_outputs = coalescelist(aws_cloudformation_stack.waf.*.outputs, [{}])[0] +output "web_acl_name" { + value = join("", aws_wafv2_web_acl.main.*.name) } -output waf_name { - description = "The name of the created WAF Web ACL" - value = lookup(local.waf_outputs, "WAFWebName", null) +output "web_acl_arn" { + value = join("", aws_wafv2_web_acl.main.*.arn) } -output waf_arn { - description = "The arn of the created WAF Web ACL" - value = lookup(local.waf_outputs, "WAFWebArn", null) +output "web_acl_id" { + value = join("", aws_wafv2_web_acl.main.*.id) +} + +output "web_acl_capacity" { + value = join("", aws_wafv2_web_acl.main.*.capacity) } diff --git a/variables.tf b/variables.tf index 061776d..3be8540 100644 --- a/variables.tf +++ b/variables.tf @@ -21,172 +21,19 @@ variable "tags" { default = {} } -variable "enable_CommonRuleSet" { - type = bool - default = false +variable "rules" { + description = "List of WAF rules." + default = [] } -variable "enable_AdminProtectionRuleSet" { - type = bool - default = false -} - -variable "enable_KnownBadInputsRuleSet" { - type = bool - default = false -} - -variable "enable_SQLiRuleSet" { - type = bool - default = false -} - -variable "enable_LinuxRuleSet" { - type = bool - default = false -} - -variable "enable_UnixRuleSet" { - type = bool - default = false -} - -variable "enable_WindowsRuleSet" { - type = bool - default = false -} - -variable "enable_PHPRuleSet" { - type = bool - default = false -} - -variable "enable_WordPressRuleSet" { - type = bool - default = false -} - -variable "enable_AmazonIpReputationList" { - type = bool - default = false -} - -variable "enable_AnonymousIpList" { - type = bool - default = false -} - -variable "enable_DefaultActionAllow" { - type = bool - default = true -} - -variable "enable_OverrideActionCountCommonRuleSet" { - type = bool - default = true -} - -variable "enable_OverrideActionCountAdminProtectionRuleSet" { - type = bool - default = true -} - -variable "enable_OverrideActionCountKnownBadInputsRuleSet" { - type = bool - default = true -} - -variable "enable_OverrideActionCountSQLiRuleSet" { - type = bool - default = true -} - -variable "enable_OverrideActionCountLinuxRuleSet" { - type = bool - default = true -} - -variable "enable_OverrideActionCountUnixRuleSet" { - type = bool - default = true -} - -variable "enable_OverrideActionCountWindowsRuleSet" { - type = bool - default = true -} - -variable "enable_OverrideActionCountPHPRuleSet" { - type = bool - default = true -} - -variable "enable_OverrideActionCountWordPressRuleSet" { - type = bool - default = true -} - -variable "enable_OverrideActionCountAmazonIpReputationList" { - type = bool - default = true -} - -variable "enable_OverrideActionCountAnonymousIpList" { - type = bool - default = true -} - -variable "CommonRuleSetExcludedRules" { - type = string - default = "" -} - -variable "AdminProtectionRuleSetExcludedRules" { - type = string - default = "" -} - -variable "KnownBadInputsRuleSetExcludedRules" { - type = string - default = "" -} - -variable "SQLiRuleSetExcludedRules" { - type = string - default = "" -} - -variable "LinuxRuleSetExcludedRules" { - type = string - default = "" -} - -variable "UnixRuleSetExcludedRules" { - type = string - default = "" -} - -variable "WindowsRuleSetExcludedRules" { - type = string - default = "" -} - -variable "PHPRuleSetExcludedRules" { - type = string - default = "" -} - -variable "WordPressRuleSetExcludedRules" { - type = string - default = "" -} - -variable "AmazonIpReputationListExcludedRules" { - type = string - default = "" +variable "visibility_config" { + description = "Visibility config for WAFv2 web acl. https://www.terraform.io/docs/providers/aws/r/wafv2_web_acl.html#visibility-configuration" + type = map(string) + default = {} } -variable "RulesAnonymousIpListExcludedRules" { - type = string - default = "" +variable "create_alb_association" { + type = bool + description = "Whether to create alb association with WAF web acl" + default = true } diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..e53358a --- /dev/null +++ b/versions.tf @@ -0,0 +1,7 @@ +terraform { + required_version = "~> 0.12.6" + + required_providers { + aws = "~> 2.67" + } +}