電通総研 テックブログ

電通総研が運営する技術ブログ

AWS環境でDDoS攻撃を受けた時の対処をCloudFormationで自動化する(EC2編)

Xイノベーション本部 ソフトウェアデザインセンター セキュリティグループの福山です。
先日、米政府(米サイバーセキュリティインフラストラクチャセキュリティ庁(CISA)や米連邦捜査局(FBI)、
MS-ISAC(Multi-State ISAC)の共同)から、DDoS攻撃に対するガイダンス「Understanding and Responding to Distributed Denial-of-Service Attacks」が公開されました。
業務でAWSに触れる機会が多いので、この機会にAWSにおけるDDoS攻撃対策を調査したいと思いました。
そこで今回は、AWS WAF、GuardDutyを有効活用できていないAWS上のWebアプリケーションに対してDDoS攻撃を受けた際に、対策となるリソースを追加するためのCloudFormationテンプレートや後続作業を調査しましたので、紹介したいと思います。


前提

  • AWSにおけるDDoS攻撃とその対策について知るため、以下の資料を確認しました。 こちらをベースに対策を考えました。 参考:AWS BlackBelt AWS上でのDDoS対策
    上記P9によると、AWSではインフラ層(L3/L4)とアプリ層(L6/L7)について対策する必要があるようです。

    上図(P12引用)のL3(ネットワーク層)を狙ったDDoS攻撃として、UDP反射攻撃などの処理能力を超えたトラフィックを送りつける攻撃が一般的です。これらの対策としては、セキュリティグループやネットワークACLなどの境界防御が挙げられます。 また、L7(アプリケーション層)に対してはHTTP GET、DNSクエリフラッドなど悪意のある要求を使用して、アプリケーションリソースを使用する攻撃が挙げられます。これらの対策サービスとして、AWS WAFなどがあります。 上記2点が標的となるWebアプリケーション構成として、EC2を利用しているケースは多いかと思います。そこで今回はEC2を利用しているケースで考えたいと思います。
  • 攻撃者がAWS外からDDoS攻撃を行っているケースを想定しています。
  • 本執筆では主に初動対応に焦点を当てており、いかに素早く対処できるかを重視した内容となっています。
  • 対応の自動化にあたりCloudFormationを利用します。CloudFormationはインフラをコードで管理できるサービスとなっています。なお、AWS CDKの利用が広がってきている中ではありますが、環境準備の手間が不要で、開発経験がない方でも手軽に作業ができる点を考慮し、CloudFormationを採用しました。
  • AWS Shield Advancedと呼ばれるDDoS対策を提供するAWSの有償サービス(月額3,000USD)がありますが、 今回は契約していない状態を想定しています。

初動対応

①隔離用のネットワークACLを関連付け(主にL3の防御)

【概要】

 攻撃対象のリソースが設置されているサブネットに、自動で新規ネットワークACLが適用されます。

【目的】

 悪用可能性のあるポート、プロトコルからの通信を遮断します。

【構成図】

 作成されるリソースは下図の赤枠部分となります。

【注意点】

 以下の手順でCloudFormationスタックを作成すると、元々アタッチされていたネットワークACL
 デタッチされます。その後、CloudFormationスタックを削除すると、defaultのネットワークACL
 アタッチされますのでご注意ください(元々default以外のネットワークACLをアタッチしていた場合も、
 defaultのネットワークACLに切り替わります)。

【手順】

 CloudFormationでリソースのあるリージョンを選択し、スタックの作成、テンプレートファイルのアップロード
 から下記コードをyml形式でアップロードし実行します。詳細な手順を確認したい場合は以下をご参考ください。
 参考:AWS CloudFormation コンソールでのスタックの作成

 コードを表示

AWSTemplateFormatVersion: '2010-09-09'

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - 
        Label:
          default: NACL Configuration
        Parameters:
          - Prefix
          - VpcId
          - SubnetId
          - VpcCidr

Parameters:
  Prefix:
    Type: String
    Default: ddos
  VpcId:
    Type: AWS::EC2::VPC::Id
  SubnetId:
    Type: AWS::EC2::Subnet::Id
    Description: "Select the subnet to which you want to attach the NACL"
    ### VPC Cidrは手動で入力する
  VpcCidr:
    Type: String
    Default: xx.xx.xx.xx/xx
    Description: "Set the VPCCidrBlok to allow inbound traffic within the VPC"

Resources:
  Nacl:
    Type: AWS::EC2::NetworkAcl
    Properties:
      VpcId: !Ref VpcId
      Tags: 
        - Key: Name
          Value: !Sub ${Prefix}-nacl
  NaclAssoc:
    Type: AWS::EC2::SubnetNetworkAclAssociation
    Properties: 
      NetworkAclId: !Ref Nacl
      SubnetId: !Ref SubnetId
  ### ここからインバウンドルール
  ####  VPC内通信を許可
  NaclEntryInbound001:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 1
      RuleAction: allow
      Protocol: -1
      CidrBlock: !Ref VpcCidr
      NetworkAclId: !Ref Nacl
  ####  MemcachedのUDP通信をブロック
  NaclEntryInbound005:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 5
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 11211
        To: 11211
      NetworkAclId: !Ref Nacl
  ####  NTPのUDP通信を許可
  NaclEntryInbound010:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 10
      RuleAction: allow
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 123
        To: 123
      NetworkAclId: !Ref Nacl
  ####  CharGENのUDP通信をブロック
  NaclEntryInbound015:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 15
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 19
        To: 19
      NetworkAclId: !Ref Nacl
  ####  QOTDのUDP通信をブロック
  NaclEntryInbound020:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 20
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 17
        To: 17
      NetworkAclId: !Ref Nacl
  ####  RIPv1のUDP通信をブロック
  NaclEntryInbound025:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 25
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 520
        To: 520
      NetworkAclId: !Ref Nacl  
  ####  RIPv1のUDP通信をブロック
  NaclEntryInbound030:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 30
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 389
        To: 389
      NetworkAclId: !Ref Nacl
  ####  CLDAPのUDP通信をブロック
  NaclEntryInbound035:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 35
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 389
        To: 389
      NetworkAclId: !Ref Nacl
  ####  DNSのUDP通信を許可
  NaclEntryInbound040:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 40
      RuleAction: allow
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 53
        To: 53
      NetworkAclId: !Ref Nacl
  ####  Quake Network ProtocolのUDP通信をブロック
  NaclEntryInbound045:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 45
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 27960
        To: 27960
      NetworkAclId: !Ref Nacl
  ####  TFTPのUDP通信をブロック
  NaclEntryInbound050:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 50
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 69
        To: 69
      NetworkAclId: !Ref Nacl
  ####  SSDPのUDP通信をブロック
  NaclEntryInbound055:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 55
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 1900
        To: 1900
      NetworkAclId: !Ref Nacl
  ####  MSSQLのUDP通信をブロック
  NaclEntryInbound060:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 60
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 1434
        To: 1434
      NetworkAclId: !Ref Nacl
  ####  Kad (P2P)のUDP通信をブロック
  NaclEntryInbound065:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 65
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 751
        To: 751
      NetworkAclId: !Ref Nacl
  ####  Portmap (RPCbind)のUDP通信をブロック
  NaclEntryInbound070:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 70
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 111
        To: 111
      NetworkAclId: !Ref Nacl
  ####  Multicast DNSのUDP通信をブロック
  NaclEntryInbound075:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 75
      RuleAction: deny
      Protocol: 17
      CidrBlock: 0.0.0.0/0
      PortRange:
        From: 5353
        To: 5353
      NetworkAclId: !Ref Nacl
  ####  ICMPのエコー応答をブロック
  NaclEntryInbound080:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 80
      RuleAction: deny
      Protocol: 1
      CidrBlock: 0.0.0.0/0
      Icmp:
        Type: 0
        Code: -1
      NetworkAclId: !Ref Nacl
  ####  ICMPのエコー要求をブロック
  NaclEntryInbound085:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 85
      RuleAction: deny
      Protocol: 1
      CidrBlock: 0.0.0.0/0
      Icmp:
        Type: 8
        Code: -1
      NetworkAclId: !Ref Nacl
  ####  デフォルトの許可ルール
  NaclEntryInbound100:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 100
      RuleAction: allow
      Protocol: -1
      CidrBlock: 0.0.0.0/0
      NetworkAclId: !Ref Nacl
  ### ここからアウトバウンドルール
  ####  デフォルトの許可ルール
  NaclEntryOutbound100:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: true
      RuleNumber: 100
      RuleAction: allow
      Protocol: -1
      CidrBlock: 0.0.0.0/0
      NetworkAclId: !Ref Nacl  

 

【ポイント解説】

  • ネットワークACLを選んだ理由
     ホワイトリストにより少ない定義量で書けるセキュリティグループも検討しましたが、以下の理由から
     ネットワークACLを採用しました。
     ・明示的に拒否ルールが書ける
     ・今後EC2が増えても追加設定なしで境界防御を実現できる
     ・NLBのようなセキュリティグループをサポートしないリソースも保護できる
     ・汎用性を重視したい
  • ルール全般について
     全ての通信を遮断するわけではなく、悪用実績のあるUDPサービスを増幅率の高い順でルール設定しています。
     (念のためICMPも拒否ルールを設定しています)
     参考:UDP-Based Amplification Attacks
     ただし、VPC内通信、53/udp、123/udpについては、システムへの影響を考慮して許可しています。
  • VPC Cidrについて
     対象VPC内の通信を許可するため、ParametersのVpcCidrにはIPアドレスレンジを入力します。
     こちらは最優先で適用されるルールとなるため、誤って0.0.0.0/0と入力してしまうと通信が全て許可されて
     しまいますので、ご注意ください。

AWS WAFの関連付け(主にL7の防御)

 攻撃者がレイヤーを変えてくる可能性があるため、①に続いて下記を速やかに実施します。

【概要】

 AWS WAFを作成し、適用します。

【目的】

 Botからの攻撃の遮断や地域制限を行うことができ、アプリケーションリソースを保護します。

【構成図】

 作成されるリソースは、下図A、Bの場合赤枠部分となります。
 CのケースはEC2が丸裸の構成です。

 (A)最前段がCloudFront構成

(B)最前段がALBで、CloudFrontなしの構成

(C)CloudFront、ALBが両方ともない構成

【注意点】

 以下の手順でCloudFormationスタックを作成すると、元々ディストリビューションまたはALBに関連付け
 されていたWeb ACLはデタッチされます。その後、CloudFormationスタックを削除しても、
 元のWeb ACLは変わらずデタッチされた状態となりますのでご注意ください。

【手順】

 以下A、B、Cの構成において、該当する作業を実施します。
 (A)最前段がCloudFront構成
  1. CloudFormationでus-east-1(バージニア北部)リージョンを選択し、スタックの作成、テンプレート
   ファイルのアップロードから、下記コードをyml形式でアップロードし実行します。

 コードを表示

AWSTemplateFormatVersion: 2010-09-09

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - 
        Label:
          default: WAF Configuration
        Parameters:
          - Prefix
          - WhiteListIP
          - RateLimit
          - SwitchGeoRestriction
          - WhiteListGeoRestriction

Parameters:
  Prefix:
    Type: String
    Default: ddos
  ### 社内のIP等、許可するIPを設定する
  WhiteListIP:
    Type: CommaDelimitedList
    Default: xx.xx.xx.xx/xx
    Description: Set IPs to Whitelist. Commas allow multiple sets(e.g. xx.xx.0.0/16, xx.xx.xx.xx/32).
  RateLimit:
    Type: Number
    Default: 100
    Description: Set value of WAF Rate Limit
  ### 地理的一致ルールを有効化したい場合はONにする
  SwitchGeoRestriction:
    Type: String
    AllowedValues: ["ON", "OFF"]
    Description: Select "ON" to block access except in designated countries, or "OFF" to not configure.
  ### アクセス許可したい国のコードを入力する(SwitchGeoRestrictionがOFFの場合はデフォルトのまま変更不要)
  WhiteListGeoRestriction:
    Type: CommaDelimitedList
    Default: JP
    Description: Set CountryCodes to which access is allowed. Commas allow multiple sets(e.g. JP, US).
     - https://docs.aws.amazon.com/ja_jp/waf/latest/APIReference/API_GeoMatchStatement.html

Conditions:
  GeoRestriction: 
    !Equals ["ON", !Ref SwitchGeoRestriction]

Resources:
  WebACL:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: !Ref Prefix
      DefaultAction: 
        Allow: {}
      Scope: CLOUDFRONT
      VisibilityConfig:
        CloudWatchMetricsEnabled: true
        MetricName: !Ref Prefix
        SampledRequestsEnabled: true
      Rules:
        - 
          Name: Custom-WhiteListIPSet
          Action:
              Allow: {}
          Priority: 0
          Statement:
            IPSetReferenceStatement:
              Arn: !GetAtt WhiteListIPSet.Arn
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: Custom-WhiteListIPSet
            SampledRequestsEnabled: true
        - 
          Name: AWS-AWSManagedRulesCommonRuleSet
          Priority: 1
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
          OverrideAction:
            None: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: AWSManagedRulesCommonRuleSet
            SampledRequestsEnabled: true
        - 
          Name: AWS-AWSManagedRulesKnownBadInputsRuleSet
          Priority: 2
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesKnownBadInputsRuleSet
          OverrideAction:
            None: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: AWSManagedRulesKnownBadInputsRuleSet
            SampledRequestsEnabled: true
        - 
          Name: AWS-AWSManagedRulesAmazonIpReputationList
          Priority: 3
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesAmazonIpReputationList
          OverrideAction:
            None: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: AWSManagedRulesAmazonIpReputationList
            SampledRequestsEnabled: true
        - 
          Name: Custom-Ratebased
          Action: 
            Block: {}
          Priority: 4
          Statement:
            RateBasedStatement:
              AggregateKeyType: IP
              Limit: !Ref RateLimit
              ScopeDownStatement:
                NotStatement:
                  Statement:
                    IPSetReferenceStatement:
                      Arn: !GetAtt WhiteListIPSet.Arn              
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: Custom-Ratebased
            SampledRequestsEnabled: true
        - !If 
          - GeoRestriction
          - Name: Custom-GeoRestriction
            Action: 
              Block: {}
            Priority: 5
            Statement:
              NotStatement:
                Statement:
                  GeoMatchStatement:
                      CountryCodes: !Ref WhiteListGeoRestriction
            VisibilityConfig:
              CloudWatchMetricsEnabled: true
              MetricName: Custom-GeoRestriction
              SampledRequestsEnabled: true
          - Ref: AWS::NoValue
  WhiteListIPSet:
    Type: "AWS::WAFv2::IPSet"
    Properties:
      Name: Custom-ipaddress-whitelist
      Scope: CLOUDFRONT
      IPAddressVersion: IPV4
      Addresses: !Ref WhiteListIP

  2. 作成されたWeb ACLを、対象のCloudFrontディストリビューションに手動でアタッチします。
   詳細な手順を確認したい場合は下記をご参考ください。
   参考:Web ACLとCloudFrontディストリビューションとの関連付け

 (B)最前段がALBで、CloudFrontなしの構成
  CloudFormationでリソースがあるリージョンを選択し、スタックの作成、テンプレートファイルの
  アップロードから下記コードをyml形式でアップロードし実行します。
  ※作成されるWeb ACLは、対象のALBに自動でアタッチされます。

 コードを表示

AWSTemplateFormatVersion: 2010-09-09

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - 
        Label:
          default: WAF Configuration
        Parameters:
          - Prefix
          - WebAclAssociationResourceArn
          - WhiteListIP
          - RateLimit
          - SwitchGeoRestriction
          - WhiteListGeoRestriction

Parameters:
  Prefix:
    Type: String
    Default: ddos
  ### ALBのARNを入力する
  WebAclAssociationResourceArn:
    Type: String
    Default: "arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:loadbalancer/app/XXXXXXXXXXXX"
    Description: Enter RegionalResource(ALB) ARN to associate with WEBACL.
  ### 社内のIP等、許可するIPを設定する
  WhiteListIP:
    Type: CommaDelimitedList
    Default: xx.xx.xx.xx/xx
    Description: Set IPs to Whitelist. Commas allow multiple sets(e.g. xx.xx.0.0/16, xx.xx.xx.xx/32).
  RateLimit:
    Type: Number
    Default: 100
    Description: Set value of WAF Rate Limit
  ### 地理的一致ルールを有効化したい場合はONにする
  SwitchGeoRestriction:
    Type: String
    AllowedValues: ["ON", "OFF"]
    Description: Select "ON" to block access except in designated countries, or "OFF" to not configure.
  ### アクセス許可したい国のコードを入力する(SwitchGeoRestrictionがOFFの場合はデフォルトの値で変更不要)
  WhiteListGeoRestriction:
    Type: CommaDelimitedList
    Default: JP
    Description: Set CountryCodes to which access is allowed. Commas allow multiple sets(e.g. JP, US).
     - https://docs.aws.amazon.com/ja_jp/waf/latest/APIReference/API_GeoMatchStatement.html

Conditions:
  GeoRestriction: 
    !Equals ["ON", !Ref SwitchGeoRestriction]

Resources:
  WebACL:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: !Ref Prefix
      DefaultAction: 
        Allow: {}
      Scope: REGIONAL
      VisibilityConfig:
        CloudWatchMetricsEnabled: true
        MetricName: !Ref Prefix
        SampledRequestsEnabled: true
      Rules:
        - 
          Name: Custom-WhiteListIPSet
          Action:
              Allow: {}
          Priority: 0
          Statement:
            IPSetReferenceStatement:
              Arn: !GetAtt WhiteListIPSet.Arn
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: Custom-WhiteListIPSet
            SampledRequestsEnabled: true
        - 
          Name: AWS-AWSManagedRulesCommonRuleSet
          Priority: 1
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
          OverrideAction:
            None: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: AWSManagedRulesCommonRuleSet
            SampledRequestsEnabled: true
        - 
          Name: AWS-AWSManagedRulesKnownBadInputsRuleSet
          Priority: 2
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesKnownBadInputsRuleSet
          OverrideAction:
            None: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: AWSManagedRulesKnownBadInputsRuleSet
            SampledRequestsEnabled: true
        - 
          Name: AWS-AWSManagedRulesAmazonIpReputationList
          Priority: 3
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesAmazonIpReputationList
          OverrideAction:
            None: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: AWSManagedRulesAmazonIpReputationList
            SampledRequestsEnabled: true
        - 
          Name: Custom-Ratebased
          Action: 
            Block: {}
          Priority: 4
          Statement:
            RateBasedStatement:
              AggregateKeyType: IP
              Limit: !Ref RateLimit
              ScopeDownStatement:
                NotStatement:
                  Statement:
                    IPSetReferenceStatement:
                      Arn: !GetAtt WhiteListIPSet.Arn              
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: Custom-Ratebased
            SampledRequestsEnabled: true
        - !If 
          - GeoRestriction
          - Name: Custom-GeoRestriction
            Action: 
              Block: {}
            Priority: 5
            Statement:
              NotStatement:
                Statement:
                  GeoMatchStatement:
                      CountryCodes: !Ref WhiteListGeoRestriction
            VisibilityConfig:
              CloudWatchMetricsEnabled: true
              MetricName: Custom-GeoRestriction
              SampledRequestsEnabled: true
          - Ref: AWS::NoValue
  WhiteListIPSet:
    Type: "AWS::WAFv2::IPSet"
    Properties:
      Name: Custom-ipaddress-whitelist
      Scope: REGIONAL
      IPAddressVersion: IPV4
      Addresses: !Ref WhiteListIP 
  WebACLAssociation:
    Type: AWS::WAFv2::WebACLAssociation
    Properties: 
      ResourceArn: !Ref WebAclAssociationResourceArn
      WebACLArn: !GetAtt WebACL.Arn

 (C)CloudFront、ALBが両方ともない構成(A、Bで解消しない場合もこちら)
  この場合、AWS WAFはアタッチできないため、他の手を打つ必要があります。
  なお、上段A、Bで解消しない場合も最終手段として下記の作業を行うことになると考えます。
  以下α、βいずれかを判断の上、対応してください。
  (α)コストが掛かってもシステム稼働を優先したい
   ・複数インスタンス構成かつAuto Scaling Groupで稼働している場合
     Auto Scalingのインスタンス最大台数を増やします。
   ・単一インスタンス等、Auto Scaling Groupを利用せずに稼働している場合
     インスタンスタイプのスケールアップを実施します。
  (β)システム稼働よりもDDoS被害(コスト)軽減を優先したい
    対象EC2を停止します。

【ポイント解説】

  • Aに関して、CloudFormationでは既存のCloudFrontにAWS WAFをアタッチすることができません。
    スタック作成後、手動でCloudFrontにアタッチする必要があります。
  • A、B共通して以下のルールが作成されます。優先度順に記載します。
  • ホワイトリストIP(許可)
    ・ParametersのWhiteListIPに社内のIP等、許可するIPを入力(複数可)
  • AWSマネージドルール(拒否)
    ・AWSManagedRulesCommonRuleSet
    ・AWSManagedRulesKnownBadInputsRuleSet
    ・AWSManagedRulesAmazonIpReputationList
  • レートベースのルール(アクセス制限)
    ・ParametersのRateLimitにレート制限値を入力
    ・ParametersのWhiteListIPで設定したIPは対象外
  • 地理的一致ルール(許可)
    ・ParametersのSwitchGeoRestrictionをONにすることで有効化
    ・ParametersのWhiteListGeoRestrictionにアクセス許可する国のコードを入力(複数可)
     参考:CountryCodes
    ・ParametersのSwitchGeoRestrictionをOFFにする場合、デフォルトの値から変更不要

③GuardDutyの全リージョン有効化

 ガイダンスによると、より悪意のある攻撃から注意を反らすためにDDoS攻撃が使用されることもある
 との記載がありました(P4)。AWSの脅威検知サービスであるGuardDutyを全リージョン有効化
 していない場合は、このタイミングで有効にすることをお勧めします。
 以下のサイトでは、全リージョン一括で有効化して通知設定する方法が紹介されていました。
 参考:https://dev.classmethod.jp/articles/set-guardduty-all-region/


保全

・CloudWatch Logs等、関連するログのエクスポート(ログローテーションによる消失を回避するため)。


事後調査

・ログの分析、原因調査。


事後対策

・今回適用したネットワークACLAWS WAFについて、アタッチを継続するか、設定変更するか等を判断。
 今回作成したリソースは、CloudFormationスタックを削除することで消すことができる。
アーキテクチャの見直し(インスタンスをプライベートサブネットに設置、CloudFrontの導入、Route53への移行等)。
・Auto Scalingの最大台数、インスタンスタイプの見直し。
・セキュリティグループの設定見直し。


まとめ

DDoS攻撃を受けた時の初動対応をできるだけ自動化してみました。
本記事が皆様のお役に立てれば幸いです。


〜最後に〜
私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募お待ちしています。
- セキュリティエンジニア(セキュリティ設計)

執筆:@fuku.dancho、レビュー:@yamashita.tsuyoshiShodoで執筆されました