[初心者向け]VPCのメインネットワークACLとサブネットのネットワークACLの関係性について

VPCにメインネットワークACLがデフォルトで設定されているって知ってました?
2023.01.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

どちらが評価されるのか?

こんにちは!AWS事業本部のおつまみです。

ネットワークACLは サブネット単位で全インスタンスに適用するファイアウォール機能です。

基本的に細かいトラフィック制御はネットワークACLではなく、セキュリティグループで行うのがスタンダートな方針です。

そのため、ネットワークACLの存在についてつい忘れがちになってしまいます。
そんな中、先日お客様にこのような質問をいただきました。

VPCに「メインネットワークACL」、サブネットに「ネットワーク ACL」が割り当たっていますが、この関係はどのようになっていますでしょうか?サブネットのネットワークACL→VPCのメインネットワークACLの順で評価されるのでしょうか?

今回はこの関係性についてお伝えしたいと思います!

いきなり結論

  • 順番で評価されるわけではなく、どちらか片方のみが評価される。
  • VPC作成時にデフォルトの「メインネットワークACL」が自動で割り当てられる。
  • サブネットには必ずいずれかのネットワーク ACLを割り当てる必要がある。
    • 個別にカスタマイズした「カスタムネットワーク ACL」
    • VPCの「メインネットワークACL」(設定しない場合はこっち)

AWS公式ドキュメントにも以下のように記載されています。

VPC 内の各サブネットにネットワーク ACL を関連付ける必要があります。ネットワーク ACL に明示的にサブネットを関連付けない場合、サブネットはデフォルトのネットワーク ACL に自動的に関連付けられます。
ネットワーク ACL を複数のサブネットに関連付けることができます。ただし、サブネットは一度に 1 つのネットワーク ACL にのみ関連付けることができます。サブネットとネットワーク ACL を関連付けると、以前の関連付けは削除されます。

検証してみた

どちらかのACLでのみ評価されることを確認するためにこのような構成で検証してみました。

  • Public subnet 1aにはカスタムネットワークACLを割り当てる。
    • インバウンドルール:PC端末からのSSH接続を拒否するよう設定
    • アウトバウンドルール:PC端末へのエフェメラルポート(1024-65335)の接続を拒否するよう設定
  • Public subnet 1cにネットワークACLを割り当てない。つまりVPCデフォルトのメインネットワークACLが割り当たる。

CloudFormationでの作成

上記の構成を作成するために、以下のテンプレートをCloudFormationで実行します。

template.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: "NetworkACL Template."

Parameters:
  # ------------------------------------------------------------#
  # Common
  # ------------------------------------------------------------#
  Prefix:
    Type: String
    Default: "network-acl-test"

  # ------------------------------------------------------------#
  # Network
  # ------------------------------------------------------------#
  VpcCidr:
    Type: String
    Default: "10.0.0.0/16"

  PublicSubnetCidr1a:
    Type: String
    Default: "10.0.1.0/24"

  PublicSubnetCidr1c:
    Type: String
    Default: "10.0.2.0/24"

  MyIP:
    Type: String
    Default: <MyPC IPAdress>

  # ------------------------------------------------------------#
  # EC2
  # ------------------------------------------------------------#
  EC2InstanceName:
    Type: String
    Default: "ec2"
  EC2InstanceAMI:
    Type: AWS::EC2::Image::Id
    Default: "ami-078296f82eb463377" # Amazon Linux 2 AMI (HVM) - Kernel 5.10, SSD Volume Type
  EC2InstanceInstanceType:
    Type: String
    Default: "t3.nano"
  EC2InstanceVolumeType:
    Type: String
    Default: "gp2"
  EC2InstanceVolumeSize:
    Type: String
    Default: "8"
  KeyName:
    Type: "AWS::EC2::KeyPair::KeyName"

Resources:
  # ------------------------------------------------------------#
  #  VPC
  # ------------------------------------------------------------#
  Vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCidr
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${Prefix}-vpc
  # ------------------------------------------------------------#
  #  InternetGateway
  # ------------------------------------------------------------#
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: ${Prefix}-InternetGateway
  # ------------------------------------------------------------#
  #  VPCとInternetGatewayの関連付け
  # ------------------------------------------------------------#
  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref Vpc
  # ------------------------------------------------------------#
  #  PublicSubnet
  # ------------------------------------------------------------#
  PublicSubnet1a:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref PublicSubnetCidr1a
      VpcId: !Ref Vpc
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: !Sub ${Prefix}-public-subnet-1a

  PublicSubnet1c:
    Type: AWS::EC2::Subnet
    Properties:
      CidrBlock: !Ref PublicSubnetCidr1c
      VpcId: !Ref Vpc
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: !Sub ${Prefix}-public-subnet-1c
  # ------------------------------------------------------------#
  #  PublicRouteTable
  # ------------------------------------------------------------#
  PublicRouteTable: 
    Type: AWS::EC2::RouteTable
    Properties: 
      VpcId: !Ref Vpc 
      Tags: 
        - Key: Name
          Value: !Sub "${Prefix}-table"
  # ------------------------------------------------------------#
  #  SubnetとRoutetableの関連付け
  # ------------------------------------------------------------#
  PublicSubnetTableAssociation1a: 
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties: 
      SubnetId: !Ref PublicSubnet1a
      RouteTableId: !Ref PublicRouteTable

  PublicSubnetTableAssociation1c: 
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties: 
      SubnetId: !Ref PublicSubnet1c
      RouteTableId: !Ref PublicRouteTable
  # ------------------------------------------------------------#
  #  Routeの指定
  # ------------------------------------------------------------#
  PublicRoute:
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      RouteTableId: !Ref PublicRouteTable
      GatewayId: !Ref InternetGateway
  # ------------------------------------------------------------#
  #  SecurityGroup
  # ------------------------------------------------------------#
  EC2SecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: !Ref Vpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref MyIP
      GroupName: !Sub "${Prefix}-sg"
      GroupDescription: "-"
      Tags:
        - Key: "Name"
          Value: !Sub "${Prefix}-sg"
# ------------------------------------------------------------#
#  NetworkACL
# ------------------------------------------------------------#
  NetworkAcl:
      Type: AWS::EC2::NetworkAcl
      Properties:
         VpcId: !Ref Vpc
         Tags:
         - Key: Name
           Value: !Sub ${Prefix}-public-nacl

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

  # インバウンドルール
  # MyIPからのSSH接続を拒否
  NaclEntryInbound01:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 100
      RuleAction: deny
      Protocol: 6
      PortRange:
        From: 22
        To: 22
      CidrBlock: !Ref MyIP
      NetworkAclId: !Ref NetworkAcl

  # すべて許可
  NaclEntryInbound02:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: false
      RuleNumber: 110
      RuleAction: allow
      Protocol: -1
      CidrBlock: 0.0.0.0/0
      NetworkAclId: !Ref NetworkAcl

  # アウトバウンドルール
  # MyIPへのエフェメラルポート接続を拒否
  NaclEntryOutbound01:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: true
      RuleNumber: 100
      RuleAction: deny
      Protocol: 6
      PortRange:
        From: 1024
        To: 65535
      CidrBlock: !Ref MyIP
      NetworkAclId: !Ref NetworkAcl

  # すべて許可
  NaclEntryOutbound02:
    Type: AWS::EC2::NetworkAclEntry
    Properties: 
      Egress: true
      RuleNumber: 110
      RuleAction: allow
      Protocol: -1
      CidrBlock: 0.0.0.0/0
      NetworkAclId: !Ref NetworkAcl

  # ------------------------------------------------------------#
  #  EC2Instance
  # ------------------------------------------------------------#
  EC2Instance1a:
    Type: "AWS::EC2::Instance"
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${Prefix}-${EC2InstanceName}-1a"
      ImageId: !Ref EC2InstanceAMI
      KeyName: !Ref KeyName
      InstanceType: !Ref EC2InstanceInstanceType
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnet1a
          GroupSet:
            - !Ref EC2SecurityGroup
      UserData: !Base64 |
        #! /bin/bash
        yum update -y

  EC2Instance1c:
    Type: "AWS::EC2::Instance"
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${Prefix}-${EC2InstanceName}-1c"
      ImageId: !Ref EC2InstanceAMI
      KeyName: !Ref KeyName
      InstanceType: !Ref EC2InstanceInstanceType
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnet1c
          GroupSet:
            - !Ref EC2SecurityGroup
      UserData: !Base64 |
        #! /bin/bash
        yum update -y

設定状況の確認

期待通りの設定がされているか確認します。
VPCにはメインネットワークACLacl-0278c5e4691872389が割り当たっています。

メインネットワークACLacl-0278c5e4691872389を選択すると、1cのサブネットが関連づけられていることがわかります。
1cは明示的にサブネットを指定していないため、VPCにはメインネットワークACLが割り当たっています。

インバウンドルール・アウトバウンドルールはデフォルトですべてのトラフィックが許可されています。

次に1aのサブネットに関連づけられているネットワークACLを確認します。   CloudFormationで作成したカスタムネットワークACLnetwork-acl-test-public-naclが関連づけられていることがわかります。

インバウンドルール・アウトバウンドルールは下記の通り設定されています。  

  • インバウンドルール:PC端末からのSSH接続を拒否するよう設定  
  • アウトバウンドルール:PC端末へのエフェメラルポート(1024-65335)の接続を拒否するよう設定

接続確認

PC端末からsshで接続できるか確認してみます。

  • PublicSubnet1a側のEC2インスタンスのパブリックIP:54.250.206.108
  • PublicSubnet1c側のEC2インスタンスのパブリックIP:54.250.91.171

予想通り1a側のEC2には接続できませんでしたが、1c側のEC2インスタンスには接続できました!

最後に

今回はVPCのメインネットワークACLとサブネットのネットワーク ACLの関係性についてご紹介しました。

普段ネットワークACLを触る機会が少ないので、勉強になりました。

最後までお読みいただきありがとうございました!
どなたかのお役に立てれば幸いです。

以上、おつまみ(@AWS11077)でした!