Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ func main() {
}

log.Debug("kubernetes.NewAdapter")
kubeAdapter, err = kubernetes.NewAdapter(kubeConfig, ingressAPIVersion, ingressClassFiltersList, awsAdapter.SecurityGroupID(), sslPolicy, loadBalancerType, clusterLocalDomain, disableInstrumentedHttpClient)
kubeAdapter, err = kubernetes.NewAdapter(kubeConfig, ingressAPIVersion, ingressClassFiltersList, awsAdapter.SecurityGroupID(), sslPolicy, loadBalancerType, clusterLocalDomain, ipAddressType, disableInstrumentedHttpClient)
if err != nil {
log.Fatal(err)
}
Expand Down
27 changes: 19 additions & 8 deletions kubernetes/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type Adapter struct {
ingressDefaultSecurityGroup string
ingressDefaultSSLPolicy string
ingressDefaultLoadBalancerType string
ingressIpAddressType string
clusterLocalDomain string
routeGroupSupport bool
}
Expand Down Expand Up @@ -123,7 +124,7 @@ func (c *ConfigMap) String() string {
}

// NewAdapter creates an Adapter for Kubernetes using a given configuration.
func NewAdapter(config *Config, ingressAPIVersion string, ingressClassFilters []string, ingressDefaultSecurityGroup, ingressDefaultSSLPolicy, ingressDefaultLoadBalancerType, clusterLocalDomain string, disableInstrumentedHttpClient bool) (*Adapter, error) {
func NewAdapter(config *Config, ingressAPIVersion string, ingressClassFilters []string, ingressDefaultSecurityGroup, ingressDefaultSSLPolicy, ingressDefaultLoadBalancerType, clusterLocalDomain, ingressIpAddressType string, disableInstrumentedHttpClient bool) (*Adapter, error) {
if config == nil || config.BaseURL == "" {
return nil, ErrInvalidConfiguration
}
Expand All @@ -139,6 +140,7 @@ func NewAdapter(config *Config, ingressAPIVersion string, ingressClassFilters []
ingressDefaultSecurityGroup: ingressDefaultSecurityGroup,
ingressDefaultSSLPolicy: ingressDefaultSSLPolicy,
ingressDefaultLoadBalancerType: loadBalancerTypesAWSToIngress[ingressDefaultLoadBalancerType],
ingressIpAddressType: ingressIpAddressType,
clusterLocalDomain: clusterLocalDomain,
routeGroupSupport: true,
}, nil
Expand Down Expand Up @@ -200,9 +202,23 @@ func (a *Adapter) newIngress(typ IngressType, metadata kubeItemMetadata, host st
shared = false
}

ipAddressType := aws.IPAddressTypeIPV4
if getAnnotationsString(annotations, ingressALBIPAddressType, "") == aws.IPAddressTypeDualstack {
ipAddressType := a.ingressIpAddressType
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is strange - looks like a.ingressIpAddressType was never used before for anything (or broken at some point) although we have a flag for it. Could you please check history to understand that?
With this change we'll use flag value as the default ip address type for all ingresses so if any deployment happened to have -ip-addr-type=dualstack this will update all loadbalancers iiuc.

albIPType := getAnnotationsString(annotations, ingressALBIPAddressType, "")
ipType := getAnnotationsString(annotations, ingressIPAddressType, "")
if albIPType != "" {
log.Warnf("Deprecated annotation %q in use for %q resource named %q in namespace %q", ingressALBIPAddressType, typ, metadata.Name, metadata.Namespace)

if ipType != "" {
log.Warnf("Both annotations are set for %q resource named %q in namespace %q, deprecated annotation %q=%q will be ignored, using %q=%q",
typ, metadata.Name, metadata.Namespace, ingressALBIPAddressType, albIPType, ingressIPAddressType, ipType)
}
}
Comment on lines +206 to +215
Copy link
Member

@AlexanderYastrebov AlexanderYastrebov Sep 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we should bother deprecating or just support both like

ipType := getAnnotationsString(annotations, ingressIPAddressType,
               getAnnotationsString(annotations, ingressALBIPAddressType, ""))

anyways after extracting the values I think we should end up with a single variable ipType to have a simple switch over it below.
We should better return an error instead of logging in case both values are used (or at least if they are different).

// Prefer ingressIPAddressType if set, otherwise fallback to deprecated ingressALBIPAddressType
switch {
case ipType == aws.IPAddressTypeDualstack || albIPType == aws.IPAddressTypeDualstack:
ipAddressType = aws.IPAddressTypeDualstack
case ipType == aws.IPAddressTypeIPV4 || albIPType == aws.IPAddressTypeIPV4:
ipAddressType = aws.IPAddressTypeIPV4
}

sslPolicy := getAnnotationsString(annotations, ingressSSLPolicyAnnotation, a.ingressDefaultSSLPolicy)
Expand Down Expand Up @@ -243,11 +259,6 @@ func (a *Adapter) newIngress(typ IngressType, metadata kubeItemMetadata, host st
// convert to the internal naming e.g. nlb -> network
loadBalancerType = loadBalancerTypesIngressToAWS[loadBalancerType]

if loadBalancerType == aws.LoadBalancerTypeNetwork {
// ensure ipv4 for network load balancers
ipAddressType = aws.IPAddressTypeIPV4
}

http2 := true
if getAnnotationsString(annotations, ingressHTTP2Annotation, "") == "false" {
http2 = false
Expand Down
82 changes: 75 additions & 7 deletions kubernetes/adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,74 @@ func TestNewIngressFromKube(tt *testing.T) {
},
},
},
{
msg: "test NLB with dualstack ip annotation",
defaultLoadBalancerType: aws.LoadBalancerTypeNetwork,
ingress: &Ingress{
ResourceType: TypeIngress,
Namespace: "default",
Name: "foo",
Hostname: "bar",
Scheme: "internet-facing",
Shared: true,
HTTP2: true,
ClusterLocal: true,
SSLPolicy: testSSLPolicy,
IPAddressType: aws.IPAddressTypeDualstack,
LoadBalancerType: aws.LoadBalancerTypeNetwork,
SecurityGroup: testIngressDefaultSecurityGroup,
},
kubeIngress: &ingress{
Metadata: kubeItemMetadata{
Namespace: "default",
Name: "foo",
Annotations: map[string]string{
ingressIPAddressType: aws.IPAddressTypeDualstack,
},
},
Status: ingressStatus{
LoadBalancer: ingressLoadBalancerStatus{
Ingress: []ingressLoadBalancer{
{Hostname: "bar"},
},
},
},
},
},
{
msg: "test ALB with dualstack ip annotation",
defaultLoadBalancerType: aws.LoadBalancerTypeApplication,
ingress: &Ingress{
ResourceType: TypeIngress,
Namespace: "default",
Name: "foo",
Hostname: "bar",
Scheme: "internet-facing",
Shared: true,
HTTP2: true,
ClusterLocal: true,
SSLPolicy: testSSLPolicy,
IPAddressType: aws.IPAddressTypeDualstack,
LoadBalancerType: aws.LoadBalancerTypeApplication,
SecurityGroup: testIngressDefaultSecurityGroup,
},
kubeIngress: &ingress{
Metadata: kubeItemMetadata{
Namespace: "default",
Name: "foo",
Annotations: map[string]string{
ingressIPAddressType: aws.IPAddressTypeDualstack,
},
},
Status: ingressStatus{
LoadBalancer: ingressLoadBalancerStatus{
Ingress: []ingressLoadBalancer{
{Hostname: "bar"},
},
},
},
},
},
{
msg: "test default NLB with security group fallbacks to ALB",
defaultLoadBalancerType: aws.LoadBalancerTypeNetwork,
Expand Down Expand Up @@ -443,7 +511,7 @@ func TestNewIngressFromKube(tt *testing.T) {
},
} {
tt.Run(tc.msg, func(t *testing.T) {
a, err := NewAdapter(testConfig, IngressAPIVersionNetworking, testIngressFilter, testIngressDefaultSecurityGroup, testSSLPolicy, tc.defaultLoadBalancerType, DefaultClusterLocalDomain, false)
a, err := NewAdapter(testConfig, IngressAPIVersionNetworking, testIngressFilter, testIngressDefaultSecurityGroup, testSSLPolicy, tc.defaultLoadBalancerType, DefaultClusterLocalDomain, aws.DefaultIpAddressType, false)
if err != nil {
t.Fatalf("cannot create kubernetes adapter: %v", err)
}
Expand Down Expand Up @@ -518,7 +586,7 @@ func (c *mockClient) patch(res string, payload []byte) (io.ReadCloser, error) {
}

func TestListIngress(t *testing.T) {
a, _ := NewAdapter(testConfig, IngressAPIVersionNetworking, testIngressFilter, testIngressDefaultSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, false)
a, _ := NewAdapter(testConfig, IngressAPIVersionNetworking, testIngressFilter, testIngressDefaultSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, aws.DefaultIpAddressType, false)
client := &mockClient{}
a.kubeClient = client
ingresses, err := a.ListIngress()
Expand All @@ -536,7 +604,7 @@ func TestListIngress(t *testing.T) {
}

func TestAdapterUpdateIngressLoadBalancer(t *testing.T) {
a, _ := NewAdapter(testConfig, IngressAPIVersionNetworking, testIngressFilter, testSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, false)
a, _ := NewAdapter(testConfig, IngressAPIVersionNetworking, testIngressFilter, testSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, aws.DefaultIpAddressType, false)
client := &mockClient{}
a.kubeClient = client
ing := &Ingress{
Expand Down Expand Up @@ -565,7 +633,7 @@ func TestAdapterUpdateIngressLoadBalancer(t *testing.T) {
}

func TestUpdateRouteGroupLoadBalancer(t *testing.T) {
a, _ := NewAdapter(testConfig, IngressAPIVersionNetworking, testIngressFilter, testSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, false)
a, _ := NewAdapter(testConfig, IngressAPIVersionNetworking, testIngressFilter, testSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, aws.DefaultIpAddressType, false)
client := &mockClient{}
a.kubeClient = client
ing := &Ingress{
Expand Down Expand Up @@ -604,7 +672,7 @@ func TestBrokenConfig(t *testing.T) {
{"broken-cert", &Config{BaseURL: "dontcare", TLSClientConfig: TLSClientConfig{CAFile: "testdata/broken.pem"}}},
} {
t.Run(fmt.Sprintf("%v", test.cfg), func(t *testing.T) {
_, err := NewAdapter(test.cfg, IngressAPIVersionNetworking, testIngressFilter, testSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, false)
_, err := NewAdapter(test.cfg, IngressAPIVersionNetworking, testIngressFilter, testSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, aws.DefaultIpAddressType, false)
if err == nil {
t.Error("expected an error")
}
Expand All @@ -613,7 +681,7 @@ func TestBrokenConfig(t *testing.T) {
}

func TestAdapter_GetConfigMap(t *testing.T) {
a, _ := NewAdapter(testConfig, IngressAPIVersionNetworking, testIngressFilter, testIngressDefaultSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, false)
a, _ := NewAdapter(testConfig, IngressAPIVersionNetworking, testIngressFilter, testIngressDefaultSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, aws.DefaultIpAddressType, false)
client := &mockClient{}
a.kubeClient = client

Expand Down Expand Up @@ -727,7 +795,7 @@ func TestListIngressFilterClass(t *testing.T) {
},
} {
t.Run(name, func(t *testing.T) {
a, _ := NewAdapter(testConfig, IngressAPIVersionNetworking, test.ingressClassFilters, testIngressDefaultSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, false)
a, _ := NewAdapter(testConfig, IngressAPIVersionNetworking, test.ingressClassFilters, testIngressDefaultSecurityGroup, testSSLPolicy, aws.LoadBalancerTypeApplication, DefaultClusterLocalDomain, aws.DefaultIpAddressType, false)
client := &mockClient{}
a.kubeClient = client
ingresses, err := a.ListResources()
Expand Down
2 changes: 2 additions & 0 deletions kubernetes/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ type ingressLoadBalancer struct {
}

const (
// deprecated, use ingressIPAddressType instead
// ingressALBIPAddressType is used in external-dns, https://github.com/kubernetes-incubator/external-dns/pull/1079
ingressALBIPAddressType = "alb.ingress.kubernetes.io/ip-address-type"
ingressIPAddressType = "ingress.kubernetes.io/ip-address-type"
IngressAPIVersionExtensions = "extensions/v1beta1"
IngressAPIVersionNetworking = "networking.k8s.io/v1"
ingressListResource = "/apis/%s/ingresses"
Expand Down
16 changes: 16 additions & 0 deletions testdata/ingress_alb_dualstack/input/k8s/ing.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: networking.k8s.io/v1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all the test data is copied from existing data and then updated to use dualstack

kind: Ingress
metadata:
name: myingress
spec:
rules:
- host: foo.bar.org
http:
paths:
- backend:
service:
name: foo-bar-service
port:
name: main-port
path: /
pathType: ImplementationSpecific
54 changes: 54 additions & 0 deletions testdata/ingress_alb_dualstack/output/params/ing.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
[
{
"parameterKey": "LoadBalancerSchemeParameter",
"parameterValue": "internet-facing"
},
{
"parameterKey": "LoadBalancerSecurityGroupParameter",
"parameterValue": "42"
},
{
"parameterKey": "LoadBalancerSubnetsParameter",
"parameterValue": "foo1"
},
{
"parameterKey": "TargetGroupVPCIDParameter",
"parameterValue": "1"
},
{
"parameterKey": "TargetGroupTargetPortParameter",
"parameterValue": "0"
},
{
"parameterKey": "ListenerSslPolicyParameter",
"parameterValue": "ELBSecurityPolicy-2016-08"
},
{
"parameterKey": "IpAddressType",
"parameterValue": "dualstack"
},
{
"parameterKey": "Type",
"parameterValue": "application"
},
{
"parameterKey": "HTTP2",
"parameterValue": "true"
},
{
"parameterKey": "TargetGroupHealthCheckPathParameter",
"parameterValue": ""
},
{
"parameterKey": "TargetGroupHealthCheckPortParameter",
"parameterValue": "0"
},
{
"parameterKey": "TargetGroupHealthCheckIntervalParameter",
"parameterValue": "0"
},
{
"parameterKey": "TargetGroupHealthCheckTimeoutParameter",
"parameterValue": "0"
}
]
12 changes: 12 additions & 0 deletions testdata/ingress_alb_dualstack/output/tags/ing.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"key": "kubernetes:application",
"value": ""
},{
"key": "kubernetes.io/cluster/aws:123:eu-central-1:kube-1",
"value": "owned"
},{
"key": "ingress:certificate-arn/DUMMY",
"value": "0001-01-01T00:00:00Z"
}
]
Loading