Skip to content

Commit 1804dde

Browse files
committed
Add dualstack without public IPv4 IP Address type
1 parent 3bbfb9d commit 1804dde

File tree

10 files changed

+178
-6
lines changed

10 files changed

+178
-6
lines changed

config/crd/bases/elbv2.k8s.aws_ingressclassparams.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ spec:
8383
enum:
8484
- ipv4
8585
- dualstack
86+
- dualstack-without-public-ipv4
8687
type: string
8788
loadBalancerAttributes:
8889
description: LoadBalancerAttributes define the custom attributes to

docs/guide/ingress/annotations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ You can add annotations to kubernetes Ingress and Service objects to customize t
2020
| [alb.ingress.kubernetes.io/group.name](#group.name) | string |N/A|Ingress|N/A|
2121
| [alb.ingress.kubernetes.io/group.order](#group.order) | integer |0|Ingress|N/A|
2222
| [alb.ingress.kubernetes.io/tags](#tags) | stringMap |N/A|Ingress,Service|Merge|
23-
| [alb.ingress.kubernetes.io/ip-address-type](#ip-address-type) | ipv4 \| dualstack |ipv4|Ingress|Exclusive|
23+
| [alb.ingress.kubernetes.io/ip-address-type](#ip-address-type) | ipv4 \| dualstack \| dualstack-without-public-ipv4 |ipv4|Ingress|Exclusive|
2424
| [alb.ingress.kubernetes.io/scheme](#scheme) | internal \| internet-facing |internal|Ingress|Exclusive|
2525
| [alb.ingress.kubernetes.io/subnets](#subnets) | stringList |N/A|Ingress|Exclusive|
2626
| [alb.ingress.kubernetes.io/security-groups](#security-groups) | stringList |N/A|Ingress|Exclusive|

docs/guide/ingress/ingress_class.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ Within any given availability zone, subnets with a cluster tag will be chosen ov
197197

198198
#### spec.ipAddressType
199199

200-
`ipAddressType` is an optional setting. The available options are `ipv4` or `dualstack`.
200+
`ipAddressType` is an optional setting. The available options are `ipv4`, `dualstack`, or `dualstack-without-public-ipv4`.
201201

202202
Cluster administrators can use `ipAddressType` field to restrict the ipAddressType for all Ingresses that belong to this IngressClass.
203203

helm/aws-load-balancer-controller/crds/crds.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ spec:
8383
enum:
8484
- ipv4
8585
- dualstack
86+
- dualstack-without-public-ipv4
8687
type: string
8788
loadBalancerAttributes:
8889
description: LoadBalancerAttributes define the custom attributes to

pkg/ingress/model_build_load_balancer.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ func (t *defaultModelBuildTask) buildLoadBalancerIPAddressType(_ context.Context
181181
return elbv2model.IPAddressTypeIPV4, nil
182182
case string(elbv2model.IPAddressTypeDualStack):
183183
return elbv2model.IPAddressTypeDualStack, nil
184+
case string(elbv2model.IPAddressTypeDualStackWithoutPublicIPV4):
185+
return elbv2model.IPAddressTypeDualStackWithoutPublicIPV4, nil
184186
default:
185187
return "", errors.Errorf("unknown IPAddressType: %v", rawIPAddressType)
186188
}
@@ -412,3 +414,12 @@ func buildLoadBalancerSubnetMappingsWithSubnetIDs(subnetIDs []string) []elbv2mod
412414
}
413415
return subnetMappings
414416
}
417+
418+
func isIPv6Supported(ipAddressType elbv2model.IPAddressType) bool {
419+
switch ipAddressType {
420+
case elbv2model.IPAddressTypeDualStack, elbv2model.IPAddressTypeDualStackWithoutPublicIPV4:
421+
return true
422+
default:
423+
return false
424+
}
425+
}

pkg/ingress/model_build_load_balancer_test.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,3 +1295,117 @@ func Test_defaultModelBuildTask_buildLoadBalancerSubnets(t *testing.T) {
12951295
})
12961296
}
12971297
}
1298+
1299+
func Test_defaultModelBuildTask_buildLoadBalancerIPAddressType(t *testing.T) {
1300+
type fields struct {
1301+
ingGroup Group
1302+
}
1303+
1304+
tests := []struct {
1305+
name string
1306+
fields fields
1307+
want elbv2.IPAddressType
1308+
wantErr error
1309+
}{
1310+
{
1311+
name: "No ip-address-type annotation set",
1312+
fields: fields{
1313+
ingGroup: Group{
1314+
ID: GroupID{Name: "explicit-group"},
1315+
Members: []ClassifiedIngress{
1316+
{
1317+
Ing: &networking.Ingress{
1318+
ObjectMeta: metav1.ObjectMeta{
1319+
Namespace: "awesome-ns",
1320+
Name: "ing-1",
1321+
},
1322+
},
1323+
},
1324+
},
1325+
},
1326+
},
1327+
want: "",
1328+
},
1329+
{
1330+
name: "The ip-address-type annotation is set to ipv4",
1331+
fields: fields{
1332+
ingGroup: Group{
1333+
ID: GroupID{Name: "explicit-group"},
1334+
Members: []ClassifiedIngress{
1335+
{
1336+
Ing: &networking.Ingress{
1337+
ObjectMeta: metav1.ObjectMeta{
1338+
Namespace: "awesome-ns",
1339+
Name: "ing-1",
1340+
Annotations: map[string]string{
1341+
"alb.ingress.kubernetes.io/ip-address-type": "ipv4",
1342+
},
1343+
},
1344+
},
1345+
},
1346+
},
1347+
},
1348+
},
1349+
want: elbv2.IPAddressTypeIPV4,
1350+
},
1351+
{
1352+
name: "The ip-address-type annotation is set to dualstack",
1353+
fields: fields{
1354+
ingGroup: Group{
1355+
ID: GroupID{Name: "explicit-group"},
1356+
Members: []ClassifiedIngress{
1357+
{
1358+
Ing: &networking.Ingress{
1359+
ObjectMeta: metav1.ObjectMeta{
1360+
Namespace: "awesome-ns",
1361+
Name: "ing-1",
1362+
Annotations: map[string]string{
1363+
"alb.ingress.kubernetes.io/ip-address-type": "dualstack",
1364+
},
1365+
},
1366+
},
1367+
},
1368+
},
1369+
},
1370+
},
1371+
want: elbv2.IPAddressTypeDualStack,
1372+
},
1373+
{
1374+
name: "The ip-address-type annotation is set to dualstack-without-public-ipv4",
1375+
fields: fields{
1376+
ingGroup: Group{
1377+
ID: GroupID{Name: "explicit-group"},
1378+
Members: []ClassifiedIngress{
1379+
{
1380+
Ing: &networking.Ingress{
1381+
ObjectMeta: metav1.ObjectMeta{
1382+
Namespace: "awesome-ns",
1383+
Name: "ing-1",
1384+
Annotations: map[string]string{
1385+
"alb.ingress.kubernetes.io/ip-address-type": "dualstack-without-public-ipv4",
1386+
"alb.ingress.kubernetes.io/scheme": "internet-facing",
1387+
},
1388+
},
1389+
},
1390+
},
1391+
},
1392+
},
1393+
},
1394+
want: elbv2.IPAddressTypeDualStackWithoutPublicIPV4,
1395+
},
1396+
}
1397+
for _, tt := range tests {
1398+
t.Run(tt.name, func(t *testing.T) {
1399+
task := &defaultModelBuildTask{
1400+
ingGroup: tt.fields.ingGroup,
1401+
annotationParser: annotations.NewSuffixAnnotationParser("alb.ingress.kubernetes.io"),
1402+
}
1403+
got, err := task.buildLoadBalancerIPAddressType(context.Background())
1404+
if err != nil {
1405+
assert.EqualError(t, err, tt.wantErr.Error())
1406+
} else {
1407+
assert.Equal(t, tt.want, got)
1408+
}
1409+
})
1410+
}
1411+
}

pkg/ingress/model_build_managed_sg.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func (t *defaultModelBuildTask) buildManagedSecurityGroupIngressPermissions(_ co
8383
},
8484
})
8585
}
86-
if ipAddressType == elbv2model.IPAddressTypeDualStack {
86+
if isIPv6Supported(ipAddressType) {
8787
for _, cidr := range cfg.inboundCIDRv6s {
8888
permissions = append(permissions, ec2model.IPPermission{
8989
IPProtocol: "tcp",

pkg/ingress/model_build_target_group.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ func (t *defaultModelBuildTask) buildTargetGroupIPAddressType(_ context.Context,
233233
}
234234
}
235235
if ipv6Configured {
236-
if *t.loadBalancer.Spec.IPAddressType != elbv2model.IPAddressTypeDualStack {
236+
if !isIPv6Supported(*t.loadBalancer.Spec.IPAddressType) {
237237
return "", errors.New("unsupported IPv6 configuration, lb not dual-stack")
238238
}
239239
return elbv2model.TargetGroupIPAddressTypeIPv6, nil

pkg/model/elbv2/load_balancer.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ const (
8383
type IPAddressType string
8484

8585
const (
86-
IPAddressTypeIPV4 IPAddressType = "ipv4"
87-
IPAddressTypeDualStack IPAddressType = "dualstack"
86+
IPAddressTypeIPV4 IPAddressType = "ipv4"
87+
IPAddressTypeDualStack IPAddressType = "dualstack"
88+
IPAddressTypeDualStackWithoutPublicIPV4 IPAddressType = "dualstack-without-public-ipv4"
8889
)
8990

9091
type SecurityGroupsInboundRulesOnPrivateLinkStatus string

test/e2e/ingress/vanilla_ingress_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,50 @@ var _ = Describe("vanilla ingress tests", func() {
723723
Status(http.StatusNotFound)
724724
})
725725
})
726+
727+
Context("with `alb.ingress.kubernetes.io/ip-address-type` variant settings", func() {
728+
It("with 'alb.ingress.kubernetes.io/ip-address-type' annotation explicitly specified, one ALB shall be created and functional", func() {
729+
appBuilder := manifest.NewFixedResponseServiceBuilder()
730+
ingBuilder := manifest.NewIngressBuilder()
731+
dp, svc := appBuilder.Build(sandboxNS.Name, "app", tf.Options.TestImageRegistry)
732+
ingBackend := networking.IngressBackend{
733+
Service: &networking.IngressServiceBackend{
734+
Name: svc.Name,
735+
Port: networking.ServiceBackendPort{
736+
Number: 80,
737+
},
738+
},
739+
}
740+
annotation := map[string]string{
741+
"kubernetes.io/ingress.class": "alb",
742+
"alb.ingress.kubernetes.io/scheme": "internet-facing",
743+
"alb.ingress.kubernetes.io/target-type": "ip",
744+
"alb.ingress.kubernetes.io/ip-address-type": "ipv4",
745+
}
746+
747+
if tf.Options.IPFamily == "IPv6" {
748+
annotation["alb.ingress.kubernetes.io/ip-address-type"] = "dualstack-without-public-ipv4"
749+
}
750+
751+
ing := ingBuilder.
752+
AddHTTPRoute("", networking.HTTPIngressPath{Path: "/path", PathType: &exact, Backend: ingBackend}).
753+
WithAnnotations(annotation).Build(sandboxNS.Name, "ing")
754+
resStack := fixture.NewK8SResourceStack(tf, dp, svc, ing)
755+
err := resStack.Setup(ctx)
756+
Expect(err).NotTo(HaveOccurred())
757+
758+
defer resStack.TearDown(ctx)
759+
760+
lbARN, lbDNS := ExpectOneLBProvisionedForIngress(ctx, tf, ing)
761+
762+
// test traffic
763+
ExpectLBDNSBeAvailable(ctx, tf, lbARN, lbDNS)
764+
httpExp := httpexpect.New(tf.LoggerReporter, fmt.Sprintf("http://%v", lbDNS))
765+
httpExp.GET("/path").Expect().
766+
Status(http.StatusOK).
767+
Body().Equal("Hello World!")
768+
})
769+
})
726770
})
727771

728772
// ExpectOneLBProvisionedForIngress expects one LoadBalancer provisioned for Ingress.

0 commit comments

Comments
 (0)