AWSTemplateFormatVersion: '2010-09-09'
Description: WAFv2 lab for an existing dedicated regional ALB
Parameters:
  AlbArn:
    Type: String
    Description: ARN of a dedicated test ALB with no existing web ACL
    AllowedPattern: '^arn:[^:]+:elasticloadbalancing:[^:]+:[0-9]{12}:loadbalancer/app/.+$'
  ManagedMode:
    Type: String
    Default: Count
    AllowedValues: [Count, Enforce]
  RateMode:
    Type: String
    Default: Count
    AllowedValues: [Count, Block]
Conditions:
  EnforceManaged: !Equals [!Ref ManagedMode, Enforce]
  BlockRate: !Equals [!Ref RateMode, Block]
Resources:
  DenyIPv4:
    Type: AWS::WAFv2::IPSet
    Properties:
      Scope: REGIONAL
      IPAddressVersion: IPV4
      Addresses: []
  WebACL:
    Type: AWS::WAFv2::WebACL
    Properties:
      Scope: REGIONAL
      DefaultAction:
        Allow: {}
      VisibilityConfig:
        CloudWatchMetricsEnabled: true
        SampledRequestsEnabled: false
        MetricName: !Sub '${AWS::StackName}-webacl'
      Rules:
        - Name: LabHeaderBlock
          Priority: 0
          Action:
            Block: {}
          Statement:
            ByteMatchStatement:
              FieldToMatch:
                SingleHeader:
                  Name: x-waf-lab
              PositionalConstraint: EXACTLY
              SearchString: block
              TextTransformations:
                - Priority: 0
                  Type: NONE
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            SampledRequestsEnabled: false
            MetricName: lab-header-block
        - Name: DenyIPv4
          Priority: 1
          Action:
            Block: {}
          Statement:
            IPSetReferenceStatement:
              Arn: !GetAtt DenyIPv4.Arn
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            SampledRequestsEnabled: false
            MetricName: deny-ipv4
        - Name: LabRateLimit
          Priority: 2
          Action: !If [BlockRate, {Block: {}}, {Count: {}}]
          Statement:
            RateBasedStatement:
              AggregateKeyType: IP
              EvaluationWindowSec: 60
              Limit: 100
              ScopeDownStatement:
                ByteMatchStatement:
                  FieldToMatch:
                    UriPath: {}
                  PositionalConstraint: EXACTLY
                  SearchString: /waf-lab
                  TextTransformations:
                    - Priority: 0
                      Type: NONE
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            SampledRequestsEnabled: false
            MetricName: lab-rate-limit
        - Name: CommonRules
          Priority: 10
          OverrideAction: !If [EnforceManaged, {None: {}}, {Count: {}}]
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            SampledRequestsEnabled: false
            MetricName: common-rules
        - Name: KnownBadInputs
          Priority: 20
          OverrideAction: !If [EnforceManaged, {None: {}}, {Count: {}}]
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesKnownBadInputsRuleSet
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            SampledRequestsEnabled: false
            MetricName: known-bad-inputs
  Association:
    Type: AWS::WAFv2::WebACLAssociation
    Properties:
      ResourceArn: !Ref AlbArn
      WebACLArn: !GetAtt WebACL.Arn
  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub 'aws-waf-logs-${AWS::StackName}'
      RetentionInDays: 7
  Logging:
    Type: AWS::WAFv2::LoggingConfiguration
    DependsOn: LogGroup
    Properties:
      ResourceArn: !GetAtt WebACL.Arn
      LogDestinationConfigs:
        - !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:aws-waf-logs-${AWS::StackName}'
      RedactedFields:
        - SingleHeader:
            Name: authorization
        - SingleHeader:
            Name: cookie
Outputs:
  WebACLArn:
    Value: !GetAtt WebACL.Arn
  LogGroupName:
    Value: !Ref LogGroup
  DenyIPv4Arn:
    Value: !GetAtt DenyIPv4.Arn
