IPv6サブネットからIPv4インターネットへCloudflare WARPでアクセスしてみた

2024.02.28

こんにちは。CX事業本部製造ビジネステクノロジー部のakkyです。

今月からAWSでIPv4アドレスが有料化され、まもなく1カ月が経とうとしています。これによってIPv4アドレス1つあたり月おおよそ3.6ドルの料金がかかるようになりました。(ただし、月あたり750時間(およそ1カ月ぶん)の無料枠があります)

最近はIPv6対応のISPも多いですし、内部で使用するAPIなどはIPv6だけでも成り立つかもしれませんが、 自分からアクセスする外部のサーバがIPv4のみの提供だと、結局自分のサーバにもIPv4アドレスを付けたり、NATゲートウェイを有効にしてDNS64/NAT64を利用する必要が出てきます。

また、AWS自体のサービスもすべてがIPv6対応しているわけではなく、IPv4のみ提供しているエンドポイントも多いのが現状です。

このような状況のため、しばらくはIPv4アドレスが必要な状況は続きますが、検証用の環境からIPv4アクセスしたいとき、若干の手間にはある程度目をつぶれる場合にコストを削減できないものでしょうか?

Cloudflare WARP

Cloudflare WARPはCloudflareが提供するセキュア接続のためのVPNサービスです。

WARPを使用すると、CloudflareへWireguardトンネルを張り、Cloudflareのエッジからインターネットに接続するようになります。 WARPのサーバへはIPv6のみで接続できるうえ、IPv4サイトへもアクセスできるようになります。

今回はCloudflare WARPを利用してIPv6サブネットに建てたEC2インスタンスからIPv4アクセスする方法を試してみました。

VPCの設定

原理上、WARPを使えばIPv6アドレスのみのインスタンスからIPv4インターネットへ出られるのですが、EC2 Instance Connectを利用して管理したいので、IPv4/v6デュアルスタックのサブネットを使います。もちろんグローバルIPv4アドレスは使用しません。

IPv6でインターネットに出るには「Egress Only インターネットゲートウェイ」が必須です。利用料は無料です。

今回はCDKで用意しました。ipProtocol: ec2.IpProtocol.DUAL_STACKと指定すればOKです。

import * as cdk from "aws-cdk-lib";
import * as ec2 from "aws-cdk-lib/aws-ec2";
import { Construct } from "constructs";

export class Ipv6VpcStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const vpc = new ec2.Vpc(this, "ipv6vpc", {
      maxAzs: 1,
      natGateways: 0,
      ipProtocol: ec2.IpProtocol.DUAL_STACK,
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: "PublicSubnet1",
          subnetType: ec2.SubnetType.PUBLIC,
        },
        {
          cidrMask: 24,
          name: "PrivateSubnet1",
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
        },
      ],
    });

    const ec2sg = new ec2.SecurityGroup(this, "ec2-sg", {
      vpc,
    });
    const eicsg = new ec2.SecurityGroup(this, "eic-sg", {
      vpc,
      allowAllOutbound: false,
    });

    ec2sg.addIngressRule(eicsg, ec2.Port.tcp(22));
    eicsg.addEgressRule(ec2sg, ec2.Port.tcp(22));

    new ec2.CfnInstanceConnectEndpoint(this, "eice", {
      subnetId: vpc.selectSubnets({ subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }).subnetIds[0],
      securityGroupIds: [eicsg.securityGroupId],
    });

    const internetsg = new ec2.SecurityGroup(this, "outband", {
      vpc,
      allowAllIpv6Outbound: true,
    });

    const server = new ec2.Instance(this, "ipv6server", {
      vpc: vpc,
      vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.T3,
        ec2.InstanceSize.MICRO
      ),
      machineImage: ec2.MachineImage.latestAmazonLinux2023({
        cpuType: ec2.AmazonLinuxCpuType.X86_64,
      }),
    });
    server.addSecurityGroup(ec2sg);
    server.addSecurityGroup(internetsg);
  }
}

EC2インスタンスにつけるセキュリティグループにallowAllIpv6Outbound: trueがないとIPv6でインターネットに出られません。IPv4はデフォルトでアウトバンドが全許可されているものの、IPv6は全拒否となっているためです。

起動直後の状況

上記CDKスタックで作成したEC2インスタンスはプライベートIPv4アドレスとIPv6グローバルユニキャストアドレスを持っているので、IPv6サーバにはアクセスできますが、IPv4サーバへは通信できません。

IPv6✅

[ec2-user@ip-10-0-1-112 ~]$ ping google.com
PING google.com(nrt20s21-in-x0e.1e100.net (2404:6800:4004:81f::200e)) 56 data bytes
64 bytes from nrt20s21-in-x0e.1e100.net (2404:6800:4004:81f::200e): icmp_seq=1 ttl=115 time=2.07 ms
64 bytes from nrt20s21-in-x0e.1e100.net (2404:6800:4004:81f::200e): icmp_seq=2 ttl=115 time=2.15 ms
64 bytes from nrt20s21-in-x0e.1e100.net (2404:6800:4004:81f::200e): icmp_seq=3 ttl=115 time=2.05 ms
64 bytes from nrt20s21-in-x0e.1e100.net (2404:6800:4004:81f::200e): icmp_seq=4 ttl=115 time=2.10 ms
^C
--- google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 2.045/2.090/2.150/0.038 ms

IPv4❌

[ec2-user@ip-10-0-1-112 ~]$ ping ipv4.google.com
PING ipv4.l.google.com (142.251.222.14) 56(84) bytes of data.
^C
--- ipv4.l.google.com ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1080ms

Cloudflare WARPのインストール

こちらのページを参考にwarp-cliをインストールします。

Amazon Linux2023を使用したので、RHELを参考に以下のようにしました。

curl -fsSl https://pkg.cloudflareclient.com/cloudflare-warp-ascii.repo | sudo tee /etc/yum.repos.d/cloudflare-warp.repo
sudo dnf update
sudo dnf install cloudflare-warp

Warpに接続します。本来はregister→connectの順番ですが、興味本位で順番を逆にしたところNICがない状態で作られてしまいました。

$ warp-cli connect
NOTICE:

Cloudflare only collects limited DNS query and traffic data (excluding payload)
that is sent to our network when you have the app enabled on your device. We
will not sell, rent, share, or otherwise disclose your personal information to
anyone, except as otherwise described in this Policy, without first providing
you with notice and the opportunity to consent. All information is handled in
accordance with our Privacy Policy.

More information is available at:
- https://www.cloudflare.com/application/terms/
- https://www.cloudflare.com/application/privacypolicy/

Accept Terms of Service and Privacy Policy? [y/N] y

Success

registerするとNICが作られました。

$ warp-cli register
Warning: The "register" command will be deprecated in a future release. Please use "registration new" instead

Success

本来は、以下のコマンドでいいはずです。

warp-cli registration new
warp-cli connect

connectした状態で、IPv4インターネットへアクセスできるようになりました。

$ ping ipv4.google.com
PING ipv4.l.google.com (142.251.42.142) 56(84) bytes of data.
64 bytes from nrt12s45-in-f14.1e100.net (142.251.42.142): icmp_seq=1 ttl=118 time=2.88 ms
64 bytes from nrt12s45-in-f14.1e100.net (142.251.42.142): icmp_seq=2 ttl=118 time=2.39 ms
64 bytes from nrt12s45-in-f14.1e100.net (142.251.42.142): icmp_seq=3 ttl=118 time=2.30 ms
64 bytes from nrt12s45-in-f14.1e100.net (142.251.42.142): icmp_seq=4 ttl=118 time=2.32 ms
^C
--- ipv4.l.google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 2.304/2.472/2.877/0.236 ms

以上