VPC origin がデュアルスタックをサポート。CloudFrontのオリジンリクエストが ALB まで IPv6 で届くか試してみた

VPC origin がデュアルスタックをサポート。CloudFrontのオリジンリクエストが ALB まで IPv6 で届くか試してみた

CloudFront VPC origin のデュアルスタック対応を、internal ALB への IPv6 接続で検証しました。VPC には通常の IGW が必要ですが、サブネットの IPv6 デフォルトルートを Egress-only IGW に向けた構成で作成できます。
2026.10.16

はじめに

2026年10月15日、CloudFront の VPC origin でデュアルスタックがサポートされました。

https://aws.amazon.com/about-aws/whats-new/2026/10/cloudfront-vpc-origin-dualstack/

このデュアルスタック対応により、CloudFront からプライベートサブネット上の ALB、NLB、EC2 まで、エンドツーエンドで IPv6 を利用できるようになりました。従来、この区間の通信は IPv4 のみでした。

本記事では、東京リージョンで internal ALB を VPC origin に設定し、ALB のアクセスログから、CloudFront の IPv6 アドレスが接続元として記録されることを確認しました。

構成

IPv6 を有効にした VPC にプライベートサブネットを 2 つ作り、IPv6 のデフォルトルート(::/0)は Egress-only IGW に向けました。サブネット内には internal ALB(デュアルスタック、HTTP:80 で固定応答 200)を置き、ALB のアクセスログを CloudWatch Logs へ配信します。

ALB の SG は、IPv6 のプレフィックスリスト com.amazonaws.global.ipv6.cloudfront.origin-facing から TCP 80 だけを許可しました。

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-vpc-origins.html

VPC origin の作成には、通常の IGW を VPC にアタッチし、プライベートサブネットに IPv4 と IPv6 の空きアドレスを 1 つ以上確保する必要があります。空きアドレスは、CloudFront が作成するサービス管理の ENI に使用されます。

通常の IGW 宛てのルートは作成せず、IPv6 のデフォルトルートは Egress-only IGW に向けます。

ALB のアクセスログで IPv6 を確認する

CloudFront ディストリビューションのドメイン名へリクエストすると、ALB の固定応答が 200 で返りました。

$ curl -sS -i https://dxxxxxxxxxxxxx.cloudfront.net/
HTTP/2 200
x-cache: Miss from cloudfront

hello from internal dualstack ALB

ALB のアクセスログ(CloudWatch Logs)には、このリクエストが次のレコードで残りました。

{
  "time": "2026-10-15T20:24:07.380120Z",
  "user_agent": "Amazon CloudFront",
  "client_port": "2001:db8:17bd:2f73:3ceb:b969:b646:3200:25216",
  "elb_status_code": "200",
  "ip_address": "192.168.28.87"
}

client_port は接続元アドレスとポートです。アドレスは例示用の文書用アドレスに置き換えています。確認した 4 件のアクセスログでは、置き換え前の client_port の IP アドレス部はいずれも IPv6 で、user_agent は Amazon CloudFront、elb_status_code は 200 でした。

まとめ

デュアルスタックの VPC origin を使用すると、IPv6 のデフォルトルートが Egress-only IGW を指すプライベートサブネット上の internal ALB に対し、CloudFront から IPv6 で接続できることを確認しました。

エンドツーエンドで IPv6 通信を利用するネットワークを構築したい場合や、外部公開の窓口を CloudFront に集約したい場合に有用です。オリジンをプライベートサブネットに配置したまま CloudFront 経由のアクセスに限定できるため、セキュリティグループの設定ミスなどによる直接アクセスのリスクも抑えられます。

CloudFormation テンプレート

検証に使用したテンプレートとスタック作成コマンドは次のとおりです。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: VPC origin dualstack verification (IPv6 VPC, internal dualstack ALB, CloudFront VPC origin, and ALB access logs)

Parameters:
  ProjectName:
    Type: String
    Default: vpco-ds
  CloudFrontIpv6PrefixListId:
    Type: String
    Default: pl-0f28cd4a128e7b13a
    Description: com.amazonaws.global.ipv6.cloudfront.origin-facing
  CloudFrontIpv4PrefixListId:
    Type: String
    Default: ''
    Description: com.amazonaws.global.cloudfront.origin-facing (empty = do not allow IPv4)

Conditions:
  AllowIpv4: !Not [!Equals [!Ref CloudFrontIpv4PrefixListId, '']]

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 192.168.0.0/18
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Ref ProjectName

  IPv6CidrBlock:
    Type: AWS::EC2::VPCCidrBlock
    Properties:
      VpcId: !Ref VPC
      AmazonProvidedIpv6CidrBlock: true

  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 192.168.0.0/20
      AvailabilityZone: !Select [0, !GetAZs '']
      Ipv6CidrBlock: !Select [0, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 2, 64]]
      AssignIpv6AddressOnCreation: true
      Tags:
        - Key: Name
          Value: !Sub '${ProjectName}-private-1'

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    DependsOn: IPv6CidrBlock
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 192.168.16.0/20
      AvailabilityZone: !Select [1, !GetAZs '']
      Ipv6CidrBlock: !Select [1, !Cidr [!Select [0, !GetAtt VPC.Ipv6CidrBlocks], 2, 64]]
      AssignIpv6AddressOnCreation: true
      Tags:
        - Key: Name
          Value: !Sub '${ProjectName}-private-2'

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub '${ProjectName}-igw'

  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  EgressOnlyIGW:
    Type: AWS::EC2::EgressOnlyInternetGateway
    Properties:
      VpcId: !Ref VPC

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub '${ProjectName}-private-rt'

  PrivateRouteIPv6:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationIpv6CidrBlock: '::/0'
      EgressOnlyInternetGatewayId: !Ref EgressOnlyIGW

  PrivateSubnet1Association:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable

  PrivateSubnet2Association:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable

  AlbSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow CloudFront origin-facing prefix lists to the internal ALB
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourcePrefixListId: !Ref CloudFrontIpv6PrefixListId
          Description: CloudFront origin-facing (IPv6)
      Tags:
        - Key: Name
          Value: !Sub '${ProjectName}-alb-sg'

  AlbSecurityGroupIngressIpv4:
    Type: AWS::EC2::SecurityGroupIngress
    Condition: AllowIpv4
    Properties:
      GroupId: !Ref AlbSecurityGroup
      IpProtocol: tcp
      FromPort: 80
      ToPort: 80
      SourcePrefixListId: !Ref CloudFrontIpv4PrefixListId
      Description: CloudFront origin-facing (IPv4)

  Alb:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Sub '${ProjectName}-alb'
      Scheme: internal
      Type: application
      IpAddressType: dualstack
      Subnets:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2
      SecurityGroups:
        - !Ref AlbSecurityGroup

  AlbListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref Alb
      Port: 80
      Protocol: HTTP
      DefaultActions:
        - Type: fixed-response
          FixedResponseConfig:
            StatusCode: '200'
            ContentType: text/plain
            MessageBody: hello from internal dualstack ALB

  AccessLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub '/aws/vendedlogs/${ProjectName}-alb-access'
      RetentionInDays: 1

  AccessLogSource:
    Type: AWS::Logs::DeliverySource
    Properties:
      Name: !Sub '${ProjectName}-alb-access'
      LogType: ALB_ACCESS_LOGS
      ResourceArn: !Ref Alb

  CwlDestination:
    Type: AWS::Logs::DeliveryDestination
    Properties:
      Name: !Sub '${ProjectName}-cwl'
      DeliveryDestinationType: CWL
      OutputFormat: json
      DestinationResourceArn: !GetAtt AccessLogGroup.Arn

  AccessLogDelivery:
    Type: AWS::Logs::Delivery
    Properties:
      DeliverySourceName: !Ref AccessLogSource
      DeliveryDestinationArn: !GetAtt CwlDestination.Arn

  VpcOrigin:
    Type: AWS::CloudFront::VpcOrigin
    DependsOn: InternetGatewayAttachment
    Properties:
      VpcOriginEndpointConfig:
        Name: !Sub '${ProjectName}-origin'
        Arn: !Ref Alb
        HTTPPort: 80
        HTTPSPort: 443
        OriginProtocolPolicy: http-only
        IpAddressType: dualstack

  Distribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Comment: !Sub '${ProjectName} VPC origin dualstack verification'
        Enabled: true
        HttpVersion: http2and3
        IPV6Enabled: true
        Origins:
          - Id: VpcOriginAlb
            DomainName: !GetAtt Alb.DNSName
            VpcOriginConfig:
              VpcOriginId: !Ref VpcOrigin
        DefaultCacheBehavior:
          TargetOriginId: VpcOriginAlb
          ViewerProtocolPolicy: redirect-to-https
          CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # Managed-CachingDisabled
          Compress: true

Outputs:
  DistributionId:
    Value: !Ref Distribution
  DistributionDomainName:
    Value: !GetAtt Distribution.DomainName
  VpcOriginId:
    Value: !Ref VpcOrigin
  LogGroupName:
    Value: !Ref AccessLogGroup

:::

template.yaml として保存し、スタックを作成します。

aws cloudformation create-stack --stack-name vpco-ds --template-body file://template.yaml
aws cloudformation wait stack-create-complete --stack-name vpco-ds

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事