Skip to content

Enable IPv6 address assignment for runner instances #5018

@dcaruso-pathpoint

Description

@dcaruso-pathpoint

Summary

The module already supports IPv6 in security group rules (runner_egress_rules includes ::/0 by default), but EC2 runner instances don't receive IPv6 addresses because the launch template doesn't enable IPv6 assignment via the network_interfaces block.

Current State

  • Security groups: Already configured for IPv6 traffic (::/0 in default egress rules)
  • VPC/Subnets: Many users have IPv6-enabled VPCs and subnets with auto-assignment configured
  • Launch template: Uses vpc_security_group_ids instead of network_interfaces block
  • Instance IPv6 addresses: Not assigned even when subnet has AssignIpv6AddressOnCreation = true

When AWS launch templates use vpc_security_group_ids directly (without a network_interfaces block), they ignore the subnet's IPv6 auto-assignment setting, resulting in IPv4-only instances.

Infrastructure Verification

We've verified our infrastructure is IPv6-ready:

  • VPC has IPv6 CIDR block associated
  • All private subnets have IPv6 CIDR blocks with auto-assignment enabled
  • Egress-Only Internet Gateway configured for outbound IPv6 traffic
  • Route tables have ::/0 routes via EIGW
  • Security groups already allow IPv6 (default runner_egress_rules)

Despite this, running instances have no IPv6 addresses:

aws ec2 describe-instances \
  --filters "Name=tag:ghr:environment,Values=gh-ci-linux-arm" \
  --query 'Reservations[0].Instances[0].NetworkInterfaces[0].Ipv6Addresses'
# Returns: []

Proposed Solution

Add an optional enable_ipv6 configuration (default false for backward compatibility) that modifies the launch template behavior:

Option 1: Simple Boolean Flag

variable "enable_ipv6" {
  description = "Enable IPv6 address assignment on runner instances"
  type        = bool
  default     = false
}

Option 2: More Flexible Configuration

variable "ipv6_config" {
  description = "IPv6 configuration for runner instances"
  type = object({
    enable              = optional(bool, false)
    address_count       = optional(number, 1)
    enable_imds_ipv6    = optional(bool, true)
  })
  default = {
    enable = false
  }
}

Required Launch Template Changes

When IPv6 is enabled, the launch template needs to switch from:

resource "aws_launch_template" "runner" {
  vpc_security_group_ids = [...]  # Current approach
  
  metadata_options {
    http_protocol_ipv6 = null
  }
}

To:

resource "aws_launch_template" "runner" {
  # Use network_interfaces block instead
  network_interfaces {
    device_index                = 0
    associate_public_ip_address = var.associate_public_ipv4_address
    security_groups             = [...]
    ipv6_address_count          = var.enable_ipv6 ? 1 : 0
  }
  
  metadata_options {
    http_endpoint               = "enabled"
    http_tokens                 = "required"
    http_put_response_hop_limit = 1
    instance_metadata_tags      = "enabled"
    http_protocol_ipv6          = var.enable_ipv6 ? "enabled" : null
  }
}

Benefits

1. Cost Savings (~$30-50/month per deployment)

  • No NAT Gateway charges for IPv6 traffic (currently ~$0.045/hour per NAT GW)
  • No data processing charges for IPv6 (currently ~$0.045/GB)
  • IPv6 internet traffic is free in AWS

2. Performance & Scalability

  • Eliminates NAT Gateway as a bottleneck
  • Direct internet connectivity without address translation
  • No port exhaustion issues (65k limit per NAT GW connection)
  • Better connection pooling for concurrent workflows

3. Reliability

  • Removes NAT Gateway as single point of failure
  • No 55,000 simultaneous connection limit per NAT GW
  • Better suited for high-concurrency CI/CD workloads

4. Future-Proof Infrastructure

  • GitHub.com supports IPv6
  • Many package registries and CDNs prefer IPv6
  • Aligns with AWS best practices for modern applications

Compatibility Considerations

  • Backward Compatibility: Default enable_ipv6 = false ensures existing deployments unchanged
  • Dual-Stack Recommended: Runners should have both IPv4 and IPv6 (many services still require IPv4)
  • GitHub Actions: Fully supports IPv6 for API calls, webhooks, artifact storage, and container registries
  • Security: Egress-Only IGW ensures no inbound IPv6 traffic; security groups still apply

Testing

Once implemented, users can verify with:

# Check IPv6 address assignment
aws ec2 describe-instances \
  --filters "Name=tag:ghr:environment,Values=PREFIX" \
  --query 'Reservations[0].Instances[0].NetworkInterfaces[0].Ipv6Addresses'

# Test from runner instance (via SSM)
curl -6 https://api.github.com
ping6 2606:4700:4700::1111

References

Additional Context

This feature would benefit users who have:

  • IPv6-enabled VPCs with egress-only internet gateways
  • Private subnets with IPv6 CIDR blocks
  • Cost optimization goals (eliminating NAT Gateway charges)
  • High-throughput CI/CD pipelines that benefit from direct connectivity

I'm happy to contribute a PR if maintainers agree with this approach!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions