Skip to content

Add dualstack without public IPv4 IP Address type #3688

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 10, 2024
Merged
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
1 change: 1 addition & 0 deletions config/crd/bases/elbv2.k8s.aws_ingressclassparams.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ spec:
enum:
- ipv4
- dualstack
- dualstack-without-public-ipv4
type: string
loadBalancerAttributes:
description: LoadBalancerAttributes define the custom attributes to
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/ingress/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ You can add annotations to kubernetes Ingress and Service objects to customize t
| [alb.ingress.kubernetes.io/group.name](#group.name) | string |N/A|Ingress|N/A|
| [alb.ingress.kubernetes.io/group.order](#group.order) | integer |0|Ingress|N/A|
| [alb.ingress.kubernetes.io/tags](#tags) | stringMap |N/A|Ingress,Service|Merge|
| [alb.ingress.kubernetes.io/ip-address-type](#ip-address-type) | ipv4 \| dualstack |ipv4|Ingress|Exclusive|
| [alb.ingress.kubernetes.io/ip-address-type](#ip-address-type) | ipv4 \| dualstack \| dualstack-without-public-ipv4 |ipv4|Ingress|Exclusive|
| [alb.ingress.kubernetes.io/scheme](#scheme) | internal \| internet-facing |internal|Ingress|Exclusive|
| [alb.ingress.kubernetes.io/subnets](#subnets) | stringList |N/A|Ingress|Exclusive|
| [alb.ingress.kubernetes.io/security-groups](#security-groups) | stringList |N/A|Ingress|Exclusive|
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/ingress/ingress_class.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ Within any given availability zone, subnets with a cluster tag will be chosen ov

#### spec.ipAddressType

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

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

Expand Down
1 change: 1 addition & 0 deletions helm/aws-load-balancer-controller/crds/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ spec:
enum:
- ipv4
- dualstack
- dualstack-without-public-ipv4
type: string
loadBalancerAttributes:
description: LoadBalancerAttributes define the custom attributes to
Expand Down
11 changes: 11 additions & 0 deletions pkg/ingress/model_build_load_balancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ func (t *defaultModelBuildTask) buildLoadBalancerIPAddressType(_ context.Context
return elbv2model.IPAddressTypeIPV4, nil
case string(elbv2model.IPAddressTypeDualStack):
return elbv2model.IPAddressTypeDualStack, nil
case string(elbv2model.IPAddressTypeDualStackWithoutPublicIPV4):
return elbv2model.IPAddressTypeDualStackWithoutPublicIPV4, nil
default:
return "", errors.Errorf("unknown IPAddressType: %v", rawIPAddressType)
}
Expand Down Expand Up @@ -412,3 +414,12 @@ func buildLoadBalancerSubnetMappingsWithSubnetIDs(subnetIDs []string) []elbv2mod
}
return subnetMappings
}

func isIPv6Supported(ipAddressType elbv2model.IPAddressType) bool {
switch ipAddressType {
case elbv2model.IPAddressTypeDualStack, elbv2model.IPAddressTypeDualStackWithoutPublicIPV4:
return true
default:
return false
}
}
114 changes: 114 additions & 0 deletions pkg/ingress/model_build_load_balancer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1295,3 +1295,117 @@ func Test_defaultModelBuildTask_buildLoadBalancerSubnets(t *testing.T) {
})
}
}

func Test_defaultModelBuildTask_buildLoadBalancerIPAddressType(t *testing.T) {
type fields struct {
ingGroup Group
}

tests := []struct {
name string
fields fields
want elbv2.IPAddressType
wantErr error
}{
{
name: "No ip-address-type annotation set",
fields: fields{
ingGroup: Group{
ID: GroupID{Name: "explicit-group"},
Members: []ClassifiedIngress{
{
Ing: &networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Namespace: "awesome-ns",
Name: "ing-1",
},
},
},
},
},
},
want: "",
},
{
name: "The ip-address-type annotation is set to ipv4",
fields: fields{
ingGroup: Group{
ID: GroupID{Name: "explicit-group"},
Members: []ClassifiedIngress{
{
Ing: &networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Namespace: "awesome-ns",
Name: "ing-1",
Annotations: map[string]string{
"alb.ingress.kubernetes.io/ip-address-type": "ipv4",
},
},
},
},
},
},
},
want: elbv2.IPAddressTypeIPV4,
},
{
name: "The ip-address-type annotation is set to dualstack",
fields: fields{
ingGroup: Group{
ID: GroupID{Name: "explicit-group"},
Members: []ClassifiedIngress{
{
Ing: &networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Namespace: "awesome-ns",
Name: "ing-1",
Annotations: map[string]string{
"alb.ingress.kubernetes.io/ip-address-type": "dualstack",
},
},
},
},
},
},
},
want: elbv2.IPAddressTypeDualStack,
},
{
name: "The ip-address-type annotation is set to dualstack-without-public-ipv4",
fields: fields{
ingGroup: Group{
ID: GroupID{Name: "explicit-group"},
Members: []ClassifiedIngress{
{
Ing: &networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Namespace: "awesome-ns",
Name: "ing-1",
Annotations: map[string]string{
"alb.ingress.kubernetes.io/ip-address-type": "dualstack-without-public-ipv4",
"alb.ingress.kubernetes.io/scheme": "internet-facing",
},
},
},
},
},
},
},
want: elbv2.IPAddressTypeDualStackWithoutPublicIPV4,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
task := &defaultModelBuildTask{
ingGroup: tt.fields.ingGroup,
annotationParser: annotations.NewSuffixAnnotationParser("alb.ingress.kubernetes.io"),
}
got, err := task.buildLoadBalancerIPAddressType(context.Background())
if err != nil {
assert.EqualError(t, err, tt.wantErr.Error())
} else {
assert.Equal(t, tt.want, got)
}
})
}
}
2 changes: 1 addition & 1 deletion pkg/ingress/model_build_managed_sg.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (t *defaultModelBuildTask) buildManagedSecurityGroupIngressPermissions(_ co
},
})
}
if ipAddressType == elbv2model.IPAddressTypeDualStack {
if isIPv6Supported(ipAddressType) {
for _, cidr := range cfg.inboundCIDRv6s {
permissions = append(permissions, ec2model.IPPermission{
IPProtocol: "tcp",
Expand Down
2 changes: 1 addition & 1 deletion pkg/ingress/model_build_target_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ func (t *defaultModelBuildTask) buildTargetGroupIPAddressType(_ context.Context,
}
}
if ipv6Configured {
if *t.loadBalancer.Spec.IPAddressType != elbv2model.IPAddressTypeDualStack {
if !isIPv6Supported(*t.loadBalancer.Spec.IPAddressType) {
return "", errors.New("unsupported IPv6 configuration, lb not dual-stack")
}
return elbv2model.TargetGroupIPAddressTypeIPv6, nil
Expand Down
5 changes: 3 additions & 2 deletions pkg/model/elbv2/load_balancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ const (
type IPAddressType string

const (
IPAddressTypeIPV4 IPAddressType = "ipv4"
IPAddressTypeDualStack IPAddressType = "dualstack"
IPAddressTypeIPV4 IPAddressType = "ipv4"
IPAddressTypeDualStack IPAddressType = "dualstack"
IPAddressTypeDualStackWithoutPublicIPV4 IPAddressType = "dualstack-without-public-ipv4"
)

type SecurityGroupsInboundRulesOnPrivateLinkStatus string
Expand Down
44 changes: 44 additions & 0 deletions test/e2e/ingress/vanilla_ingress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,50 @@ var _ = Describe("vanilla ingress tests", func() {
Status(http.StatusNotFound)
})
})

Context("with `alb.ingress.kubernetes.io/ip-address-type` variant settings", func() {
It("with 'alb.ingress.kubernetes.io/ip-address-type' annotation explicitly specified, one ALB shall be created and functional", func() {
appBuilder := manifest.NewFixedResponseServiceBuilder()
ingBuilder := manifest.NewIngressBuilder()
dp, svc := appBuilder.Build(sandboxNS.Name, "app", tf.Options.TestImageRegistry)
ingBackend := networking.IngressBackend{
Service: &networking.IngressServiceBackend{
Name: svc.Name,
Port: networking.ServiceBackendPort{
Number: 80,
},
},
}
annotation := map[string]string{
"kubernetes.io/ingress.class": "alb",
"alb.ingress.kubernetes.io/scheme": "internet-facing",
"alb.ingress.kubernetes.io/target-type": "ip",
"alb.ingress.kubernetes.io/ip-address-type": "ipv4",
}

if tf.Options.IPFamily == "IPv6" {
annotation["alb.ingress.kubernetes.io/ip-address-type"] = "dualstack-without-public-ipv4"
}

ing := ingBuilder.
AddHTTPRoute("", networking.HTTPIngressPath{Path: "/path", PathType: &exact, Backend: ingBackend}).
WithAnnotations(annotation).Build(sandboxNS.Name, "ing")
resStack := fixture.NewK8SResourceStack(tf, dp, svc, ing)
err := resStack.Setup(ctx)
Expect(err).NotTo(HaveOccurred())

defer resStack.TearDown(ctx)

lbARN, lbDNS := ExpectOneLBProvisionedForIngress(ctx, tf, ing)

// test traffic
ExpectLBDNSBeAvailable(ctx, tf, lbARN, lbDNS)
httpExp := httpexpect.New(tf.LoggerReporter, fmt.Sprintf("http://%v", lbDNS))
httpExp.GET("/path").Expect().
Status(http.StatusOK).
Body().Equal("Hello World!")
})
})
})

// ExpectOneLBProvisionedForIngress expects one LoadBalancer provisioned for Ingress.
Expand Down