どちらが評価されるのか?
こんにちは!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)でした!