-
Notifications
You must be signed in to change notification settings - Fork 702
Description
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 (
::/0in default egress rules) - ✅ VPC/Subnets: Many users have IPv6-enabled VPCs and subnets with auto-assignment configured
- ❌ Launch template: Uses
vpc_security_group_idsinstead ofnetwork_interfacesblock - ❌ 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
::/0routes 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 = falseensures 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::1111References
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!