夢とガラクタの集積場

落ちこぼれ三流エンジニアである管理人の夢想=『夢』と、潰えた夢=『ガラクタ』の集積場です。

AWS NACLの設定をCLIから行ってみた

AWSのNACLを試してみたのですが、
ネット上を調べたところ日本語の実例情報がそれほどなかったため、
とりあえずまとめておこう、ということでまとめてみました。

1. NACLとは?

下記のページにもありますが、
「サブネットのインバウンドトラフィックとアウトバウンドトラフィックを制御するファイアウォールとして動作するセキュリティのオプションレイヤー」です。

docs.aws.amazon.com


セキュリティグループと何が違うのか、というのは下記のページにあります。docs.aws.amazon.com


簡単にまとめてしまうと、こんなイメージかと。

セキュリティグループ NACL
インスタンスレベルで動作 サブネットレベルで動作
ステートフル: ルールに関係なく、返されたトラフィックが自動的に許可 ステートレス: 返されたトラフィックがルールによって明示的に許可

2. どんなネットワークを構築したいか?

今回構築したいネットワークは下の図のようになります。

1VPC内でマスターのサブネットとスレーブのサブネットが複数存在する構成で、
マスターのサブネットは全スレーブサブネットと通信可能、
スレーブのサブネットはスレーブ間では直接通信は出来ない、というものです。

尚、これらのサブネットは全てパブリックサブネットなので、外部との通信は可能です。
外部との間はセキュリティグループで明示的に許可しないと通信は出来ないのでそちらはセキュリティグループで。
今回はVPC内の通信をNACLで一律ガード出来ないか、ということを考えています。
f:id:kimutansk:20150923053913p:plain

3. 構築前準備(サブネットの作成)

まずはVPCを作成した上でインターネットゲートウェイをアタッチします。
単にCLIVPCを作成した場合、インターネットゲートウェイがアタッチされておらず、外部と通信が出来ないからです。

# aws ec2 create-vpc --cidr-block 10.0.0.0/16
{
    "Vpc": {
        "InstanceTenancy": "default",
        "State": "pending",
        "VpcId": "vpc-9342fcf6", ★アタッチ時に使用★
        "CidrBlock": "10.0.0.0/16",
        "DhcpOptionsId": "dopt-e9c9258c"
    }
}
# aws ec2 create-internet-gateway
{
    "InternetGateway": {
        "Tags": [],
        "InternetGatewayId": "igw-434b9e26", ★アタッチ時に使用★
        "Attachments": []
    }
}
# aws ec2 attach-internet-gateway --internet-gateway-id igw-434b9e26 --vpc-id vpc-9342fcf6

その後、ルーティング設定を行います。
こちらもCLIVPCを作成した場合インターネットゲートウェイがアタッチされていない関係上、
初期のルートテーブルにはインターネットゲートウェイへのルートが存在しないためです。

# aws ec2 describe-route-tables --filters Name=vpc-id,Values=vpc-9342fcf6
{
    "RouteTables": [
        {
            "Associations": [
                {
                    "RouteTableAssociationId": "rtbassoc-c86efcad",
                    "Main": true,
                    "RouteTableId": "rtb-c3a229a6"
                }
            ],
            "RouteTableId": "rtb-c3a229a6",
            "VpcId": "vpc-9342fcf6",
            "PropagatingVgws": [],
            "Tags": [],
            "Routes": [
                {
                    "GatewayId": "local",
                    "DestinationCidrBlock": "10.0.0.0/16",
                    "State": "active",
                    "Origin": "CreateRouteTable"
                }
            ]
        }
    ]
}
# aws ec2 create-route --route-table-id rtb-c3a229a6 --destination-cidr-block 0.0.0.0/0 --gateway-id igw-434b9e26
{
    "Return": true
}

上記完了後、サブネットを作成します。

# aws ec2 create-subnet --vpc-id vpc-9342fcf6 --cidr-block 10.0.0.0/24
{
    "Subnet": {
        "VpcId": "vpc-9342fcf6",
        "CidrBlock": "10.0.0.0/24",
        "State": "pending",
        "AvailabilityZone": "ap-northeast-1c",
        "SubnetId": "subnet-0adb7253",
        "AvailableIpAddressCount": 251
    }
}
# aws ec2 create-subnet --vpc-id vpc-9342fcf6 --cidr-block 10.0.1.0/24
{
    "Subnet": {
        "VpcId": "vpc-9342fcf6",
        "CidrBlock": "10.0.1.0/24",
        "State": "pending",
        "AvailabilityZone": "ap-northeast-1c",
        "SubnetId": "subnet-02db725b",
        "AvailableIpAddressCount": 251
    }
}
# aws ec2 create-subnet --vpc-id vpc-9342fcf6 --cidr-block 10.0.2.0/24
{
    "Subnet": {
        "VpcId": "vpc-9342fcf6",
        "CidrBlock": "10.0.2.0/24",
        "State": "pending",
        "AvailabilityZone": "ap-northeast-1c",
        "SubnetId": "subnet-39db7260",
        "AvailableIpAddressCount": 251
    }
}
# aws ec2 create-subnet --vpc-id vpc-9342fcf6 --cidr-block 10.0.3.0/24
{
    "Subnet": {
        "VpcId": "vpc-9342fcf6",
        "CidrBlock": "10.0.3.0/24",
        "State": "pending",
        "AvailabilityZone": "ap-northeast-1c",
        "SubnetId": "subnet-3adb7263",
        "AvailableIpAddressCount": 251
    }
}

ここまでで、下記のようにネットワークの枠までは出来た状態になっています。
f:id:kimutansk:20150923062015p:plain

4. NACLの設定

では、各サブネットに対してNACLの設定を行います。
行う設定としては、各スレーブサブネットに対して下記の設定を行えばいい・・となるはずです。
※ルール#の順に並んでいて、タイプ/プロトコル/ポート範囲は全部、インバウンド/アウトバウンド共通

送信元/送信先 可否 説明
10.0.1.0/24 許可 自サブネット内の通信を許可
10.0.0.0/24 許可 マスタサブネットとの通信を許可
10.0.0.0/16 拒否 上記に当てはまらないVPC内の通信を拒否
0.0.0.0/0 許可 外部との通信は許可
0.0.0.0/0 拒否 デフォルトルール

これまでの手順の結果4サブネットに対して同一NACLが適用されているため、個別のNACLを作成して設定します。
はじめに4サブネットに対して割り振られたNACLの紐づけを行っているNetworkAclAssociationIdを取得しておきます。

# aws ec2 describe-network-acls --filters Name=vpc-id,Values=vpc-9342fcf6
{
    "NetworkAcls": [
        {
            "Associations": [
                {
                    "SubnetId": "subnet-3adb7263",
                    "NetworkAclId": "acl-c7c24ca2",
                    "NetworkAclAssociationId": "aclassoc-d128ccb5"
                },
                {
                    "SubnetId": "subnet-02db725b",
                    "NetworkAclId": "acl-c7c24ca2",
                    "NetworkAclAssociationId": "aclassoc-cc28cca8"
                },
                {
                    "SubnetId": "subnet-0adb7253",
                    "NetworkAclId": "acl-c7c24ca2",
                    "NetworkAclAssociationId": "aclassoc-fe28cc9a"
                },
                {
                    "SubnetId": "subnet-39db7260",
                    "NetworkAclId": "acl-c7c24ca2",
                    "NetworkAclAssociationId": "aclassoc-d528ccb1"
                }
            ],
            "NetworkAclId": "acl-c7c24ca2",
            "VpcId": "vpc-9342fcf6",
            "Tags": [],
            "Entries": [
                {
                    "CidrBlock": "0.0.0.0/0",
                    "RuleNumber": 100,
                    "Protocol": "-1",
                    "Egress": true,
                    "RuleAction": "allow"
                },
                {
                    "CidrBlock": "0.0.0.0/0",
                    "RuleNumber": 32767,
                    "Protocol": "-1",
                    "Egress": true,
                    "RuleAction": "deny"
                },
                {
                    "CidrBlock": "0.0.0.0/0",
                    "RuleNumber": 100,
                    "Protocol": "-1",
                    "Egress": false,
                    "RuleAction": "allow"
                },
                {
                    "CidrBlock": "0.0.0.0/0",
                    "RuleNumber": 32767,
                    "Protocol": "-1",
                    "Egress": false,
                    "RuleAction": "deny"
                }
            ],
            "IsDefault": true
        }
    ]
}

NetworkAclAssociationIdは取得できたため、追加のNACLを作成します。
マスタサブネットは元々存在しているNACLで問題ないため、スレーブサブネット分の作成です。

# aws ec2 create-network-acl --vpc-id vpc-9342fcf6
{
    "NetworkAcl": {
        "Associations": [],
        "NetworkAclId": "acl-fac14f9f",
        "VpcId": "vpc-9342fcf6",
        "Tags": [],
        "Entries": [
            {
                "CidrBlock": "0.0.0.0/0",
                "RuleNumber": 32767,
                "Protocol": "-1",
                "Egress": true,
                "RuleAction": "deny"
            },
            {
                "CidrBlock": "0.0.0.0/0",
                "RuleNumber": 32767,
                "Protocol": "-1",
                "Egress": false,
                "RuleAction": "deny"
            }
        ],
        "IsDefault": false
    }
}
★以後NetworkAclId以外は同一のため省略
# aws ec2 create-network-acl --vpc-id vpc-9342fcf6
{
~~~~
        "NetworkAclId": "acl-c4c14fa1",
~~~~
}
[root@host1 ~ 06:41:40]# aws ec2 create-network-acl --vpc-id vpc-9342fcf6
{
~~~~
        "NetworkAclId": "acl-c7c14fa2",
~~~~
}

CLIで作成した場合、「全許容」のNACLエントリは存在しないため、それも追加する必要がありそうですね。

NACL設定が作成されたため、次はエントリの追加を行います。
こちらも3NACL分書くと長くなるため、1NACL分のみ。
1NACL分設定完了したら後はNetworkAclIdとサブネット内通信のCIDRを変えて実行すればOKです。

★自サブネット内の通信を許可
# aws ec2 create-network-acl-entry --network-acl-id acl-fac14f9f --ingress --rule-number 10 --protocol -1 --cidr-block 10.0.1.0/24 --rule-action allow
# aws ec2 create-network-acl-entry --network-acl-id acl-fac14f9f --egress --rule-number 10 --protocol -1 --cidr-block 10.0.1.0/24 --rule-action allow
★マスタサブネットとの通信を許可
# aws ec2 create-network-acl-entry --network-acl-id acl-fac14f9f --ingress --rule-number 20 --protocol -1 --cidr-block 10.0.0.0/24 --rule-action allow
# aws ec2 create-network-acl-entry --network-acl-id acl-fac14f9f --egress --rule-number 20 --protocol -1 --cidr-block 10.0.0.0/24 --rule-action allow
★上記に当てはまらないVPC内の通信を拒否
# aws ec2 create-network-acl-entry --network-acl-id acl-fac14f9f --ingress --rule-number 30 --protocol -1 --cidr-block 10.0.0.0/16 --rule-action deny
# aws ec2 create-network-acl-entry --network-acl-id acl-fac14f9f --egress --rule-number 30 --protocol -1 --cidr-block 10.0.0.0/16 --rule-action deny
★外部との通信は許可
# aws ec2 create-network-acl-entry --network-acl-id acl-fac14f9f --ingress --rule-number 100 --protocol -1 --cidr-block 0.0.0.0/0 --rule-action allow
# aws ec2 create-network-acl-entry --network-acl-id acl-fac14f9f --egress --rule-number 100 --protocol -1 --cidr-block 0.0.0.0/0 --rule-action allow

NACLのエントリ追加が終わったため、次はサブネットに対してNACLの紐づけを行います。
先ほど取得したNetworkAclAssociationIdを用いてサブネットに対するNACLの紐づけを行います。
尚、レスポンスの通り、このコマンドを実行するとNetworkAclAssociationId自体も変わるようです。

# aws ec2 replace-network-acl-association --association-id aclassoc-cc28cca8 --network-acl-id acl-fac14f9f
{
    "NewAssociationId": "aclassoc-5733d733"
}
# aws ec2 replace-network-acl-association --association-id aclassoc-d528ccb1 --network-acl-id acl-c4c14fa1
{
    "NewAssociationId": "aclassoc-5c33d738"
}
# aws ec2 replace-network-acl-association --association-id aclassoc-d128ccb5 --network-acl-id acl-c7c14fa2
{
    "NewAssociationId": "aclassoc-2433d740"
}

これまででNACLの設定が出来ましたので、実際に通信をして確認してみます。

5. 動作確認

では、各サブネットにインスタンスを起動して確認してみます。
まずはインスタンスを起動します。(※レスポンスは省略)

# aws ec2 run-instances --image-id ami-9a2fb89a --key-name default-keypair --instance-type t2.micro --subnet-id subnet-0adb7253 --associate-public-ip-address
# aws ec2 run-instances --image-id ami-9a2fb89a --key-name default-keypair --instance-type t2.micro --subnet-id subnet-02db725b --associate-public-ip-address
# aws ec2 run-instances --image-id ami-9a2fb89a --key-name default-keypair --instance-type t2.micro --subnet-id subnet-39db7260 --associate-public-ip-address
# aws ec2 run-instances --image-id ami-9a2fb89a --key-name default-keypair --instance-type t2.micro --subnet-id subnet-3adb7263 --associate-public-ip-address

その後、外部からSSHログインが可能なように各インスタンスにセキュリティグループを付与してログインします。
で、実際に各通信を試してみた結果は下記のようになりました。

マスタサブネット
★外部への通信確認→OK
[ec2-user@ip-10-0-0-243 ~]$ curl http://www.google.com
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.jp/?gfe_rd=cr&amp;ei=DtsBVrCDG8Wm8wevxYbYCA">here</A>.
</BODY></HTML>
★マスタサブネットへの通信確認→OK
[ec2-user@ip-10-0-0-243 ~]$ ping -c 1 10.0.0.243
PING 10.0.0.243 (10.0.0.243) 56(84) bytes of data.
64 bytes from 10.0.0.243: icmp_seq=1 ttl=64 time=0.030 ms

--- 10.0.0.243 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.030/0.030/0.030/0.000 ms
★スレーブサブネット1への通信確認→OK
[ec2-user@ip-10-0-0-243 ~]$ ping -c 1 10.0.1.10
PING 10.0.1.10 (10.0.1.10) 56(84) bytes of data.
64 bytes from 10.0.1.10: icmp_seq=1 ttl=64 time=0.602 ms

--- 10.0.1.10 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.602/0.602/0.602/0.000 ms
★スレーブサブネット2への通信確認→OK
[ec2-user@ip-10-0-0-243 ~]$ ping -c 1 10.0.2.109
PING 10.0.2.109 (10.0.2.109) 56(84) bytes of data.
64 bytes from 10.0.2.109: icmp_seq=1 ttl=64 time=0.547 ms

--- 10.0.2.109 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.547/0.547/0.547/0.000 ms
★スレーブサブネット3への通信確認→OK
[ec2-user@ip-10-0-0-243 ~]$ ping -c 1 10.0.3.168
PING 10.0.3.168 (10.0.3.168) 56(84) bytes of data.
64 bytes from 10.0.3.168: icmp_seq=1 ttl=64 time=0.563 ms

--- 10.0.3.168 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.563/0.563/0.563/0.000 ms
スレーブサブネット1
★外部への通信確認→OK
[ec2-user@ip-10-0-1-10 ~]$ curl http://www.google.com
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.jp/?gfe_rd=cr&amp;ei=eNoBVrzBE8f98wfngau4DA">here</A>.
</BODY></HTML>
★マスタサブネットへの通信確認→OK
[ec2-user@ip-10-0-1-10 ~]$ ping -c 1 10.0.0.243
PING 10.0.0.243 (10.0.0.243) 56(84) bytes of data.
64 bytes from 10.0.0.243: icmp_seq=1 ttl=64 time=0.506 ms

--- 10.0.0.243 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.506/0.506/0.506/0.000 ms
★スレーブサブネット1への通信確認→OK
[ec2-user@ip-10-0-1-10 ~]$ ping -c 1 10.0.1.10
PING 10.0.1.10 (10.0.1.10) 56(84) bytes of data.
64 bytes from 10.0.1.10: icmp_seq=1 ttl=64 time=0.032 ms

--- 10.0.1.10 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.032/0.032/0.032/0.000 ms
★スレーブサブネット2への通信確認→NG
[ec2-user@ip-10-0-1-10 ~]$ ping -c 1 10.0.2.109
PING 10.0.2.109 (10.0.2.109) 56(84) bytes of data.

--- 10.0.2.109 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 10000ms
★スレーブサブネット3への通信確認→NG
[ec2-user@ip-10-0-1-10 ~]$ ping -c 1 10.0.3.168
PING 10.0.3.168 (10.0.3.168) 56(84) bytes of data.

--- 10.0.3.168 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 10000ms
スレーブサブネット2
★外部への通信確認→OK
[ec2-user@ip-10-0-2-109 ~]$ curl http://www.google.com
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.jp/?gfe_rd=cr&amp;ei=D9sBVqijJ8am8wfhkYWABg">here</A>.
</BODY></HTML>
★マスタサブネットへの通信確認→OK
[ec2-user@ip-10-0-2-109 ~]$ ping -c 1 10.0.0.243
PING 10.0.0.243 (10.0.0.243) 56(84) bytes of data.
64 bytes from 10.0.0.243: icmp_seq=1 ttl=64 time=0.641 ms

--- 10.0.0.243 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.641/0.641/0.641/0.000 ms
★スレーブサブネット1への通信確認→NG
[ec2-user@ip-10-0-2-109 ~]$ ping -c 1 10.0.1.10
PING 10.0.1.10 (10.0.1.10) 56(84) bytes of data.

--- 10.0.1.10 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 10000ms
★スレーブサブネット2への通信確認→OK
[ec2-user@ip-10-0-2-109 ~]$ ping -c 1 10.0.2.109
PING 10.0.2.109 (10.0.2.109) 56(84) bytes of data.
64 bytes from 10.0.2.109: icmp_seq=1 ttl=64 time=0.025 ms

--- 10.0.2.109 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.025/0.025/0.025/0.000 ms
★スレーブサブネット3への通信確認→NG
[ec2-user@ip-10-0-2-109 ~]$ ping -c 1 10.0.3.168
PING 10.0.3.168 (10.0.3.168) 56(84) bytes of data.

--- 10.0.3.168 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 10000ms
スレーブサブネット3
★外部への通信確認→OK
[ec2-user@ip-10-0-3-168 ~]$ curl http://www.google.com
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.jp/?gfe_rd=cr&amp;ei=ENsBVtnxOen98wf7iJm4Cw">here</A>.
</BODY></HTML>
★マスタサブネットへの通信確認→OK
[ec2-user@ip-10-0-3-168 ~]$ ping -c 1 10.0.0.243
PING 10.0.0.243 (10.0.0.243) 56(84) bytes of data.
64 bytes from 10.0.0.243: icmp_seq=1 ttl=64 time=0.457 ms

--- 10.0.0.243 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.457/0.457/0.457/0.000 ms
★スレーブサブネット1への通信確認→NG
[ec2-user@ip-10-0-3-168 ~]$ ping -c 1 10.0.1.10
PING 10.0.1.10 (10.0.1.10) 56(84) bytes of data.

--- 10.0.1.10 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 10000ms
★スレーブサブネット2への通信確認→NG
[ec2-user@ip-10-0-3-168 ~]$ ping -c 1 10.0.2.109
PING 10.0.2.109 (10.0.2.109) 56(84) bytes of data.

--- 10.0.2.109 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 10000ms
★スレーブサブネット3への通信確認→OK
[ec2-user@ip-10-0-3-168 ~]$ ping -c 1 10.0.3.168
PING 10.0.3.168 (10.0.3.168) 56(84) bytes of data.
64 bytes from 10.0.3.168: icmp_seq=1 ttl=64 time=0.024 ms

--- 10.0.3.168 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.024/0.024/0.024/0.000 ms

まとめると下記のようになります。

インスタンス 外部への通信 マスタサブネットへの通信 スレーブサブネット1への通信 スレーブサブネット2への通信 スレーブサブネット3への通信
マスタサブネットインスタンス OK OK OK OK OK
スレーブサブネット1インスタンス OK OK OK NG NG
スレーブサブネット2インスタンス OK OK NG OK NG
スレーブサブネット3インスタンス OK OK NG NG OK

とりあえず、NACLで目的としたVPC内の直接通信を防ぐ設定は成功したようです。
NACLエントリの作成やサブネットへの紐づけ等コマンドをうつ回数は多くなりましたが、CLIで実際に出来ることも確認できました。

ただ、この手の構築はCloudformationでやってみたいところですので、機会があればそれも出来ないか確認してみますか。