DEV Community

Fernando Azevedo
Fernando Azevedo

Posted on Originally published at fernando.moretes.com

CloudFront dual-stack VPC origins: IPv6 to private origins, with caveats

For almost two years, anyone who adopted CloudFront VPC origins and had an IPv6 target lived with a bad choice: keep the ALB in a private subnet and stay on IPv4 between edge and origin, or expose the origin to the internet to get end-to-end IPv6. The 10/15/2026 announcement removes that dilemma. The question that matters now is not 'can I get IPv6 to a private origin?', it's 'what in my VPC, my security group and my change process breaks when I turn it on?'. That is the question this analysis answers.

The launch in numbers

  • US$ 0: Additional cost. Dual-stack VPC origins carry no extra charge; the ENI addresses can be private.
  • 34: Commercial Regions. Every Region with VPC origins, including sa-east-1; four have one excluded AZ.
  • 55/60: Prefix list weight. The CloudFront managed list weighs 55 against the default 60 rules per security group.

What actually changed

VPC origins, launched in November 2024, places an ALB, NLB or EC2 instance in a private subnet and makes CloudFront the single point of entry. The connection arrives through a service-managed ENI created inside your subnet, and access is controlled by a security group AWS creates with the naming pattern CloudFront-VPCOrigins-Service-SG. Until yesterday that ENI spoke IPv4 only.

In September 2025 CloudFront gained IPv6 for custom origins, with three options: IPv4 only (default), IPv6 only and dual-stack. That announcement excluded S3 and VPC origins. What shipped now closes half of that gap: VPC origins accept dual-stack. The other half stays open, because the current CloudFront IPv6 documentation still lists IPv6 only as "excluding Amazon S3 and VPC origins".

In practice, the change is one field: when you create the VPC origin, the console asks for Origin type, and the default is still IPv4. For dual-stack to work, the private subnet needs at least one free IPv6 address in addition to the IPv4 one, because that is where the service ENI is born. Without it, ENI creation fails.

What does not change: gRPC is still out, Lambda@Edge origin request and origin response triggers are still out, a Gateway Load Balancer cannot be an origin, and neither can an NLB with a TLS listener. If you ruled out VPC origins for one of those reasons, you have no new reason to revisit.

End-to-end IPv6 path with a private origin

Every hop where IPv6 can silently fall back to IPv4, and the control that governs that hop.

🌐 DNS e borda

  • Route 53 alias A + alias AAAA (network)
  • CloudFront edge IPv6 de viewer ligado (edge)
  • Origin-facing escolhe IPv4 ou IPv6 (edge)

🟧 AWS: VPC privada (sa-east-1)

  • ENI do serviço 1 IPv4 + 1 IPv6 livres (network)
  • ALB interno IpAddressType: dualstack (compute)
  • Target group IPv4 ou IPv6 (compute)

🔐 Controles

  • CloudFront-VPCOrigins-Service-SG fonte da regra de entrada (security)
  • NACL de saída efêmeras 1024–65535 IPv4 e IPv6 (security)

Flows

  • viewer -> r53: AAAA lookup
  • viewer -> edge: HTTPS over IPv6
  • edge -> ofs: cache miss
  • ofs -> eni: private connection, family picked by the service
  • eni -> alb: allowed by service SG
  • alb -> tg: new connection, target group family
  • svcsg -> alb: inbound rule
  • nacl -> alb: return path

Where it shines

  • The trade-off is gone: IPv6 to the origin no longer requires a public subnet, an internet-facing ALB and an IP list to maintain.
  • Zero license cost: no additional charge, and the ENI IPv6 addresses do not need to be public.
  • Same security model: the service SG still restricts the origin to your distributions, now across both families.
  • Brazil included: sa-east-1 is on the list, so a regulated workload that must stay in-country is not left out.

Dual-stack is not guaranteed IPv6

This is the point the announcement does not make explicit, and it matters to whoever has to answer the audit. The CloudFront documentation describes dual-stack mode this way: the service automatically picks IPv4 or IPv6 for the origin connection to prioritize performance and availability. In other words, you don't decide the family of each connection. CloudFront does.

For most sites that is exactly the right behavior. For a team that has to prove to a regulator or a contract that traffic runs over IPv6 all the way to the origin, it is an evidence problem. Turning on dual-stack produces no proof at all; measurement does.

The same holds on the viewer side. The documentation itself warns that CloudFront may answer a viewer over IPv4 when its data says the experience will be better, and that the IPv6 share should remain a minority because not every access network supports the protocol. Two automatic decisions, one at each end, and neither is yours.

What I would do: treat "end-to-end IPv6" as a measured SLO, not a setting. At the edge, the c-ip field in standard logs shows the viewer family. At the origin, ALB access logs show the address that opened the connection, which for VPC origins is the service ENI. The daily ratio of IPv6 connections to total is the number that goes into the report. If the requirement is IPv6-only, VPC origins still doesn't meet it: IPv6 only remains excluded.

Network prerequisites that fail silently

The CloudFront side is one field. The real work is in the VPC, and much of it fails without a clear message.

IPv6 in the VPC and subnets: the ALB only accepts IpAddressType: dualstack if the VPC and its subnets have an associated IPv6 CIDR block, the route tables route IPv6, and the SG and NACL allow IPv6. In an older account built IPv4-only, that is a project, not a click.

An address for the ENI: the subnet where the VPC origin lives needs a free IPv6 address. A /28 that runs out of IPv4 is already a known problem; with dual-stack the same math repeats in the other family.

Origin security group: the documentation gives two options. Managed prefix lists, and for dual-stack that means both, com.amazonaws.global.cloudfront.origin-facing and com.amazonaws.global.ipv6.cloudfront.origin-facing. The VPC documentation assigns the CloudFront list a weight of 55, against the default of 60 rules per security group, which leaves 5 rules for everything else. The other option is to reference CloudFront-VPCOrigins-Service-SG: it takes one rule and restricts the origin to your distributions, not to any CloudFront distribution. That is the one I use.

Outbound NACL: inbound NACL rules are not evaluated for traffic from CloudFront, but outbound rules are, on the return path, on ephemeral ports 1024–65535. A NACL keeps IPv6 rules separate from IPv4 ones. If you only allowed 0.0.0.0/0, you will watch the IPv6 handshake die on the way back.

Limits that still apply: IPv6 only is still unavailable for VPC origins. gRPC and Lambda@Edge origin triggers are not supported. A Gateway Load Balancer and an NLB with a TLS listener cannot be origins, and an NLB must have a security group attached. And IPv6 ends at the ALB: the connection to targets uses the target group's family, so a dual-stack ALB with an IPv4 target group is IPv6 to the ALB, not to the application.

Migrating a VPC origin already in production

Here is the cost the announcement does not show. Per the documented procedure, updating a VPC origin requires first making sure it is not the default origin of any cache behavior, then disassociating it from every distribution that uses it, editing, waiting for the status to return to Deployed (up to 15 minutes), and only then associating it again. In production, that is a scheduled outage window, multiplied by the number of distributions sharing the origin.

I would not edit the existing VPC origin. The safer path is to create a second, dual-stack VPC origin pointing at the same ALB ARN, and swap origins through CloudFront continuous deployment: a staging distribution gets the new origin, you test with a slice of traffic, and you promote the configuration when the signals are clean. Rollback is promoting the previous configuration back, without waiting 15 minutes for a VPC origin to propagate.

The signals I would watch on staging: the distribution's 5xxErrorRate and OriginLatency in CloudWatch, the ALB's TargetConnectionErrorCount and HTTPCode_ELB_5XX_Count, and the share of IPv6 connections in the ALB access logs. If that share stays at zero, the cause is almost always an SG or NACL missing the IPv6 rule, and CloudFront falls back to IPv4 without complaining, which is good for availability and terrible for the target.

If you share VPC origins across accounts through AWS RAM, add coordination with the owner of every consuming distribution.

How to adopt without an outage window

  1. Prepare the VPC: Associate an IPv6 CIDR with the VPC and private subnets, adjust route tables and confirm each subnet has a free IPv6 address for the ENI.

  2. Move the ALB to dual-stack: Run aws elbv2 set-ip-address-type --ip-address-type dualstack on the internal ALB; decide separately whether the target group also moves to IPv6.

  3. Lock down SG and NACL: ALB inbound from CloudFront-VPCOrigins-Service-SG; NACL outbound on ephemeral 1024–65535 for both IPv4 and IPv6.

  4. Create a new VPC origin: Origin type dual-stack, same ALB ARN. Don't edit the existing one; wait for Deployed status.

  5. Test on staging and promote: Staging distribution with the new origin, partial traffic, 5xx signals and IPv6 share; promote only when both are clean.

  6. Finish the edge: Enable viewer IPv6 and add a second AAAA alias in Route 53 for each alternate domain name; review signed URLs using a custom IpAddress policy.

Anti-patterns

  • Editing the VPC origin in production: the procedure requires disassociating from every distribution, and the wait of up to 15 minutes becomes an outage.
  • Claiming compliance because the field says dual-stack: CloudFront picks the family per connection; without log measurement, there is no evidence.
  • Allowing the prefix lists when the origin only serves your own CloudFront: it consumes 55 of the default 60 rules and accepts any distribution, not just yours.
  • Forgetting the target group: a dual-stack ALB with IPv4 targets delivers IPv6 to the load balancer, not to the application.

Curator's note: In a financial environment I would turn this on first for a low-risk distribution, with staging and an IPv6 share target written down before the change. I have seen an IP family migration pass functional testing and fail the first audit report, because the fallback to IPv4 is silent by design. The lesson: in networking, whatever degrades without an error needs its own metric, otherwise you find out from the wrong person. And I would not edit an existing VPC origin under any circumstances; creating another one and swapping via continuous deployment costs an afternoon and saves a 2 AM window.

Verdict

Adopt it when you have an end-to-end IPv6 requirement, contractual, regulatory or platform-driven, and the origin already is or needs to be in a private subnet: there is no additional cost and the security model does not get worse. Wait if the requirement is IPv6-only, because IPv6 only is still out for VPC origins, or if the VPC has no IPv6 CIDR yet, because then the project is a network project, not a CDN one. Either way, create a new VPC origin and swap via staging; do not edit the one serving traffic.

Rating: 4/5

References


Originally published at fernando.moretes.com. By Fernando F. Azevedo: Senior Solutions Architect.

Top comments (0)