AWS CloudFormationでNACL設定を入れてみる

ステートレスは辛いよ
2020.10.29

はじめに

ネットワークACL(NACL)設定をCloudFormation テンプレートで展開してみます。 使用するCFnリソースの説明と実際の展開例の紹介を行います。

※ 実際には NACLを導入する前に、セキュリティグループによるトラフィック制御で 代用できないか、オンプレ側セキュリティアプライアンスで対応できないか、 など検討すると良いです。

セキュリティグループに関する話は以下ブログに良くまとまっているので参照下さい。

CFnリソース解説

ざっくりとしたイメージは以下の通り。赤字で示した部分が NACL設定で必要なリソースです。

img

AWS::EC2::NetworkAcl

NACLを新規作成するためのリソースです。 NACLを設定する VPCを指定しましょう。

以下 リソース記述例です。

Nacl:
  Type: AWS::EC2::NetworkAcl
  Properties:
    VpcId: !Ref VpcId
    Tags: 
      - Key: Name
        Value: xxx-nacl

ちなみに、これだけだと インバウンド/アウトバウンド通信をすべて拒否する NACLになります。

AWS::EC2::SubnetNetworkAclAssociation

NACL関連付けを行うためのリソースです。 関連付けを行いたいサブネット毎に作成します。

以下 リソース記述例です。

NaclAssoc:
  Type: AWS::EC2::SubnetNetworkAclAssociation
  Properties: 
    NetworkAclId: !Ref Nacl
    SubnetId: !Ref SubnetId

AWS::EC2::NetworkAclEntry

実際の NACLのルール 1つ1つが このリソースに当たります。

マネコンの表記と、実際の CFnリソース記述との関連を表したイメージが以下になります。

img

各プロパティを以下説明します。

  1. NetworkAclId

    ルールを挿入したいNACLのIDを指定します。

  2. Egress

    アウトバウンドルールの場合は true 、インバウンドルールの場合は false を指定します。

  3. RuleNumber

    ルール番号を指定します。

    ※ NACLはルール番号の昇順で見ていって、最初にマッチしたルールが適用されます。 設計で注意が必要です。

  4. Protocol

    IPプロトコルを指定します。以下早見表です。

    プロトコル 指定する番号
    ICMP 1
    TCP 6
    UDP 17
    すべて -1
  5. PortRange

    UDP/TCP のポート範囲を指定します。

  6. Icmp

    Protocol で ICMPを選択した場合に必須です。 ICMPコードおよびタイプを記します。

    以下, Icmpパラメータの記述例です。

        # これは Echo Reply (すべての Code)
        Icmp:
          Type: 0
          Code: -1
        
        # これは Echo Request (すべての Code)
        Icmp:
          Type: 8
          Code: -1

    ICMP Type/Code の詳細は以下参照ください。

  7. CidrBlock

    CIDR表記で IPアドレスレンジを指定します。

  8. RuleAction

    許可 allow もしくは 拒否 deny です。

ユースケース/展開例

以下のようなケースを考えます。

img

要件は以下の通り。 AWSからオンプレへの方向への通信を制御します。

  • AWS(VPC)内 通信 や NATGW 経由のアウトバウンド通信 は すべて許可したい
  • オンプレ → AWS への方向の通信は すべて許可したい
  • AWS → オンプレ への方向の通信は基本的に すべて拒否したい
    • ただし オンプレサーバー 192.168.0.200 への通信( TCP/1218ポート ) は業務システムの都合上どうしても利用しないといけないため、許可する

上記要件を満たす NACLを展開してみましょう。

NACL 設計

NACL設計の際は以下気をつけましょう。

  • ルール番号の若い順番に評価されること
  • ルール数の上限は 20 (上限緩和申請で 40)
  1. インバウンドのルール
    ルール番号 タイプ プロトコル ポート範囲 送信先 許可/拒否 備考
    100 すべてのトラフィック すべて すべて 0.0.0.0/0 ALLOW デフォルトALLOW
    すべてのトラフィック すべて すべて 0.0.0.0/0 DENY デフォルトDENY

    今回の制御は 「AWSからオンプレへのアウトバウンド通信」がメインなので、 インバウンドルールは触りません。すべて 許可(ALLOW)とします。

  2. アウトバウンドのルール

    ルール番号 タイプ プロトコル ポート範囲 送信先 許可/拒否 備考
    1 すべてのトラフィック すべて すべて 10.0.0.0/16 ALLOW AWS(VPC)内通信
    2 カスタムTCPルール TCP 1218 192.168.0.200/32 ALLOW 特定オンプレサーバーへの通信
    10 カスタムTCPルール TCP 1024-65535 192.168.0.0/16 ALLOW エフェメラルポート(TCP)
    11 カスタムTCPルール UDP 1024-65535 192.168.0.0/16 ALLOW エフェメラルポート(UDP)
    12 カスタムICMPルール ICMP Echo Reply 192.168.0.0/16 ALLOW Ping 確認用
    50 すべてのトラフィック すべて すべて 192.168.0.0/16 DENY オンプレへの通信
    100 すべてのトラフィック すべて すべて 0.0.0.0/0 ALLOW デフォルトALLOW
    すべてのトラフィック すべて すべて 0.0.0.0/0 DENY デフォルトDENY

    設定したルールの概説は以下の通り。

    • ルール番号:1 - AWS(VPC)内通信を許可します
    • ルール番号:2 - 特定オンプレサーバーへの通信を許可します
    • ルール番号:10,11,12
      • 基本的には後述の ルール(50番) で AWS→オンプレ: (AWSからみて)行きの通信 を拒否しますが、 オンプレ→AWS: (AWSからみて)戻りの通信 は許可しないといけません
      • そのために TCP/UDP では戻り通信に使われるポート(エフェメラルポート)を、 ICMPでは オンプレからの ping 疎通確認を想定して Echo Reply を許可しています
    • ルール番号:50 - オンプレへの通信を拒否します
    • ルール番号:100 - デフォルトALLOWです。これが無いと NATGW経由アウトバウンドができません

CloudFormation

前述の NACL設計をそのまま CFnテンプレート化しました。 パラメータとして NACLを適用する VPC ID や Subnet IDを指定します。

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  # プレフィクス
  Prefix:
    Type: String
    Default: sample-env
  # NACL生成する VPC
  VpcId:
    Type: AWS::EC2::VPC::Id
  # VPC CIDR
  VpcCidr:
    Type: String
    Default: 10.0.0.0/16
  # NACL関連付けする サブネット
  SubnetId:
    Type: AWS::EC2::Subnet::Id
Resources:
  # ### NACL生成
  Nacl:
    Type: AWS::EC2::NetworkAcl
    Properties:
      VpcId: !Ref VpcId
      Tags: 
        - Key: Name
          Value: !Sub ${Prefix}-nacl

  # ### NACLの関連付け
  NaclAssoc:
    Type: AWS::EC2::SubnetNetworkAclAssociation
    Properties: 
      NetworkAclId: !Ref Nacl
      SubnetId: !Ref SubnetId

  # ### インバウンドルール
  # すべて許可
  NaclEntryInbound:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 100
      RuleAction: allow
      Protocol: -1
      CidrBlock: 0.0.0.0/0
      NetworkAclId: !Ref Nacl

  # ### アウトバウンドルール
  # VPC内はすべてALLOW
  NaclEntry001:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: true
      RuleNumber: 1
      RuleAction: allow
      Protocol: -1
      CidrBlock: !Ref VpcCidr
      NetworkAclId: !Ref Nacl

  # 特定サーバーへの通信は ALLOW
  NaclEntry002:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: true
      RuleNumber: 2
      RuleAction: allow
      Protocol: 6
      CidrBlock: 192.168.0.200/32
      PortRange:
        From: 1218
        To: 1218
      NetworkAclId: !Ref Nacl

  # オンプレへの戻り通信(TCP/UDP エフェメラルポート)は ALLOW
  NaclEntry010:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: true
      RuleNumber: 10
      RuleAction: allow
      Protocol: 6
      CidrBlock: 192.168.0.0/16
      PortRange:
        From: 1024
        To: 65535
      NetworkAclId: !Ref Nacl
  NaclEntry011:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: true
      RuleNumber: 11
      RuleAction: allow
      Protocol: 17
      CidrBlock: 192.168.0.0/16
      PortRange:
        From: 1024
        To: 65535
      NetworkAclId: !Ref Nacl
  # オンプレへの戻り通信(ping EchoReply)は ALLOW
  NaclEntry012:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: true
      RuleNumber: 12
      RuleAction: allow
      Protocol: 1
      Icmp:
        Code: -1
        Type: 0
      CidrBlock: 192.168.0.0/16
      NetworkAclId: !Ref Nacl

  # それ(戻り通信)以外のオンプレへの通信は すべてDENY
  NaclEntry050:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: true
      RuleNumber: 50
      RuleAction: deny
      Protocol: -1
      CidrBlock: 192.168.0.0/16
      NetworkAclId: !Ref Nacl

  # デフォルトのALLOW
  NaclEntry100:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: true
      RuleNumber: 100
      RuleAction: allow
      Protocol: -1
      CidrBlock: 0.0.0.0/0
      NetworkAclId: !Ref Nacl

確認

CFn 展開後の設定を見てみます。

  1. インバウンドのルール

    img

  2. アウトバウンドのルール

    img

    設計通りの内容になっていました。

おわりに

NACLはステートレスなので戻り通信のことを考えることが大変ですね。 できれば (AWS側は) Security Group、 (オンプレ側は) ステートフル制御対応のNW機器/Firewall で全てステートフルで済ませたいところです。

それら対応が難しい場合は NACLによる設計を検討下さい。 少しでもどなたかのお役に立てば幸いです。

参考

▼ Developers.IO

▼ AWS Document