📑

[AWS] Egress Only Internet Gatewayのみを利用してEC2にSSHでログインする

2024/02/08に公開

結論から

結論からいうと、Egress Only Internet Gatewayではできません。
IPv6のEC2からどうにか繋げようと思うと、下記のようにNAT GatewayとInternet Gateway(もしくはVPC Endpoint)に頼る必要があります。

期待していたけどできなかったこと

Egress Only Internet Gatewayを利用することで、NAT GatewayやVPC Endpointを介さずSSMに繋ぎ、EC2への安心安全(安価)な接続を実現すること。下記のような図のイメージです。

できない理由

この接続に必要な各種EndpointがIPv6に対応してないためです。まずは上述の構成を作成してみたものの接続できず。その原因を調査してみたので下記に記載していきます。

できない理由の調査

EC2をSession Managerを介して繋ぐための条件

Systems Managerのドキュメントを読んでみましょう。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-getting-started-privatelink.html

VPC エンドポイントを使用する代わりに、マネージドノードにアウトバウンド・インターネット アクセスを許可することができます。この場合、マネージドノードは、以下のエンドポイントに HTTPS (ポート 443) アウトバウンドトラフィックも許可する必要があります:
ec2messages.region.amazonaws.com
ssm.region.amazonaws.com
ssmmessages.region.amazonaws.com

つまり、EC2にSession Manager経由で繋ぐためには、上記のエンドポイントにつながる必要性があります。これには2通りの方法があり、一つはNAT Gatewayなどインターネットに一度出て接続する方法、もう一つは、VPC Endpointを介して接続する方法になります。後者は一度もインターネットに出ずにAWS内に閉じたネットワーク接続になる(はず)のでより安全です。

つまりは、これらEndpointに対してEgress Only Internet Gatewayで接続できれば、AWS Systems Manager Sessions Manager経由でアクセスができるはずです。

EndpointのIPv6サポート状況

さて、digってみましょう。

digコマンドでは、Aレコード(IPv4)やAAAAレコード(IPv6)を取得できます。
ちなみに、digはdomain information groperの略だそうです。普通に掘る(dig)で名付けたものと思ってました。

dig +short google.com a                            
172.217.175.110

❯ dig +short google.com aaaa 
2404:6800:4004:801::200e

こんな感じ。このコマンドによりgoogle.comはIPv4, IPv6ともに取得できていることがわかります。
さて、先ほど列挙したEndpointに対してdigしてみます。

dig +short ec2messages.us-west-2.amazonaws.com aaaa

❯ dig +short ec2messages.us-west-2.amazonaws.com a   
52.94.177.12

❯ dig +short ssm.us-west-2.amazonaws.com aaaa

❯ dig +short ssm.us-west-2.amazonaws.com a
52.119.171.48

❯ dig +short ssmmessages.us-west-2.amazonaws.com aaaa

❯ dig +short ssmmessages.us-west-2.amazonaws.com a   
52.94.185.41

AAAAレコード何も返ってきませんね。ダメそう。。。

いや、これは私のローカルからだからでEC2からなら上手く行ったりとか!と思いRoute 53 ResolverでDNSのクエリログを有効にしてみます。

Route 53 > Resolver > Query logging > Configure Query Logging

で特定のVPC内で発生したログを出力できます。

DNSのクエリログはCloudWatch logsに出せるので、CloudWatch Logs Live Tailを使って眺めてみます。

{
    "version":"1.100000",
    "account_id":"<deleted>",
    "region":"us-west-2",
    "vpc_id":"vpc-0bd4bc3f0bfa7c20d",
    "query_timestamp":"2024-02-06T16:06:13Z",
    "query_name":"ec2messages.us-west-2.amazonaws.com.",
    "query_type":"AAAA",
    "query_class":"IN",
    "rcode":"NOERROR",
    "answers":[],
    "srcaddr":"10.4.0.154",
    "srcport":"34606",
    "transport":"UDP",
    "srcids":{
        "instance":"i-0a6da828462a55805"
    }
}

。。。ダメか。answersが空配列ですね。

後から気づきましたが、IPv4が必須ということは、公式にも記載があります。

https://docs.aws.amazon.com/whitepapers/latest/ipv6-on-aws/ipv6-security-and-monitoring-considerations.html#aws-systems-manager

Resources managed by AWS Systems Manager must have IPv4 connectivity to Systems Manager’s endpoints. For example, to connect to an EC2 instance using Systems Manager Session Manager, the instance must be running dual-stack and must have an IPv4 connectivity to the internet or AWS PrivateLink VPC endpoint. Similarly, on-premises resources must also be in dual-stack network mode.

このため、少なくともIPv6 Onlyではそのままではつながらないことがわかります。

それでもIPv6のみのEC2を接続したい!

では、それでも、という場合どうするか。NAT64/DNS64というものを用いることになります。これらはセットで用いられ、IPv6/IPv4の変換を担ってくれます。

DNS64

まずはDNS64を有効にします。これはEC2が属するSubnetに対して設定を実施します。Subnetの設定変更画面に行くと下記設定があります。このチェックボックスにチェックを入れて有効にします。

VPC内でのDNS Queryログを見てましょう。

{
    "version": "1.100000",
    "account_id": "<deleted>",
    "region": "us-west-2",
    "vpc_id": "vpc-0bd4bc3f0bfa7c20d",
    "query_timestamp": "2024-02-06T14:37:29Z",
    "query_name": "ssm.us-west-2.amazonaws.com.",
    "query_type": "AAAA",
    "query_class": "IN",
    "rcode": "NOERROR",
    "answers": [
        {
            "Rdata": "64:ff9b::345e:b677",
            "Type": "AAAA",
            "Class": "IN"
        }
    ],
    "srcaddr": "10.4.0.157",
    "srcport": "49700",
    "transport": "UDP",
    "srcids": {
        "instance": "i-0276a0893b440e790"
    }
}

おや、AAAAレコードが返るようになりましたね。しかし、この64:ff9b::345e:b677はなんのIPv6アドレスなのでしょうか。実は、これこそがDNS64で使われる、IPv4へマッピングされるIPv6アドレスになります。DNS64では、IPv4しか持たないドメインに対する名前解決において、固有の予約Prefix 64:ff9b::/96を持つIPv6アドレスを返すことになっています。このIPv4/IPv6マッピングの仕様についてはRFC6052で定義されています。

https://datatracker.ietf.org/doc/html/rfc6052

2.1.  Well-Known Prefix

   This document reserves a "Well-Known Prefix" for use in an
   algorithmic mapping.  The value of this IPv6 prefix is:

      64:ff9b::/96

しかしながら、これは当然IPv6なので、このIPを使ってもIPv4しか持たないAWSのエンドポイントにはつながりません。

ではどうするか。NAT64がこれを解決してくれます。

NAT64

NAT64は、IPv6からIPv4に変換・マッピングすることで、実際にIPv6しか持たない機器がIPv4のドメインに繋げられるようにしてくれます。このマッピングについても、詳細は先のRFC6052に記載があります。

AWSでは、NAT64はNAT GWによってサポートされています。そう、ここで結局NAT GWが必要になるのです。DNSで解決されたIPv6へのリクエストをNAT GWに投げることで、NAT GWが変換をしてくれます。

最終構成

下の図のような構成になります。

まず、NAT GWを作成します。そして、EC2インスタンス側のPrivate Subnetで、IPv4にマッピングされるIPv6アドレス、すなわち64:ff9b::/96を、NAT GWにルートするルートテーブルを作成します。NAT GWには、Route Tableとして、Internet Gateway(Not Egress Only Internet Gateway)へのルートを定義します。

これで無事にIPv6の機器がInternet GWを介して、Sessions Managerの前提となるIPv4のみをサポートするドメインに繋ぐことができるようになります。

終わりに

上記でIPv6 EC2をSessions Managerに接続し、SSH接続することができました。しかし、これでは結局のところInternet GWもNAT GWも使うことになってしまうので、当初の目標であった安心安全(安価)で、というところはクリアできていません。

IPv6サポート待ってます!

参考リンク

https://www.nic.ad.jp/ja/newsletter/No64/0800.html
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/nat-gateway-nat64-dns64.html
https://datatracker.ietf.org/doc/html/rfc6052
https://docs.aws.amazon.com/whitepapers/latest/ipv6-on-aws/ipv6-security-and-monitoring-considerations.html#aws-systems-manager

Discussion