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
15 changes: 15 additions & 0 deletions apis/projectcontour/v1alpha1/contourdeployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,21 @@ type NetworkPublishing struct {
//
// +optional
ServiceAnnotations map[string]string `json:"serviceAnnotations,omitempty"`

// LoadBalancerSourceRanges is an optional list of IP ranges in CIDR form
// which are allowed to access the LoadBalancer type Envoy Service.
// This maps to Service.spec.loadBalancerSourceRanges.
// Only applies when Type is LoadBalancerService.
Comment on lines +336 to +339

@tsaarni tsaarni Aug 27, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could add This field may be ignored if the cloud-provider does not support it

Suggested change
// LoadBalancerSourceRanges is an optional list of IP ranges in CIDR form
// which are allowed to access the LoadBalancer type Envoy Service.
// This maps to Service.spec.loadBalancerSourceRanges.
// Only applies when Type is LoadBalancerService.
// LoadBalancerSourceRanges is an optional list of IP ranges in CIDR form
// which are allowed to access the LoadBalancer type Envoy Service.
// This maps to Service.spec.loadBalancerSourceRanges.
// This field may be ignored if the cloud-provider does not support it.
// Only applies when Type is LoadBalancerService.

//
// +optional
LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges,omitempty"`

// LoadBalancerClass is the class of the load balancer implementation
// to use for the Envoy Service when Type is LoadBalancerService.
// This maps to Service.spec.loadBalancerClass.
Comment on lines +344 to +346

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
// LoadBalancerClass is the class of the load balancer implementation
// to use for the Envoy Service when Type is LoadBalancerService.
// This maps to Service.spec.loadBalancerClass.
// LoadBalancerClass is the class of the load balancer implementation
// to use for the Envoy Service when Type is LoadBalancerService.
// This maps to Service.spec.loadBalancerClass.
// Once set, it cannot be changed without recreating the Service.
// Only applies when Type is LoadBalancerService.

//
// +optional
LoadBalancerClass *string `json:"loadBalancerClass,omitempty"`
}

// NetworkPublishingType is a way to publish network endpoints.
Expand Down
10 changes: 10 additions & 0 deletions apis/projectcontour/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions changelogs/unreleased/7665-VedantMadane-small.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Adds ContourDeployment.spec.envoy.networkPublishing.loadBalancerSourceRanges and loadBalancerClass so the Gateway provisioner can configure Envoy LoadBalancer Service source ranges and class.
15 changes: 15 additions & 0 deletions examples/contour/01-crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3985,6 +3985,21 @@ spec:
a single IP family on single-stack clusters), or "RequireDualStack"
(two IP families on dual-stack configured clusters, otherwise fail).
type: string
loadBalancerClass:
description: |-
LoadBalancerClass is the class of the load balancer implementation
to use for the Envoy Service when Type is LoadBalancerService.
This maps to Service.spec.loadBalancerClass.
type: string
loadBalancerSourceRanges:
description: |-
LoadBalancerSourceRanges is an optional list of IP ranges in CIDR form
which are allowed to access the LoadBalancer type Envoy Service.
This maps to Service.spec.loadBalancerSourceRanges.
Only applies when Type is LoadBalancerService.
items:
type: string
type: array
serviceAnnotations:
additionalProperties:
type: string
Expand Down
15 changes: 15 additions & 0 deletions examples/render/contour-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4210,6 +4210,21 @@ spec:
a single IP family on single-stack clusters), or "RequireDualStack"
(two IP families on dual-stack configured clusters, otherwise fail).
type: string
loadBalancerClass:
description: |-
LoadBalancerClass is the class of the load balancer implementation
to use for the Envoy Service when Type is LoadBalancerService.
This maps to Service.spec.loadBalancerClass.
type: string
loadBalancerSourceRanges:
description: |-
LoadBalancerSourceRanges is an optional list of IP ranges in CIDR form
which are allowed to access the LoadBalancer type Envoy Service.
This maps to Service.spec.loadBalancerSourceRanges.
Only applies when Type is LoadBalancerService.
items:
type: string
type: array
serviceAnnotations:
additionalProperties:
type: string
Expand Down
15 changes: 15 additions & 0 deletions examples/render/contour-gateway-provisioner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3996,6 +3996,21 @@ spec:
a single IP family on single-stack clusters), or "RequireDualStack"
(two IP families on dual-stack configured clusters, otherwise fail).
type: string
loadBalancerClass:
description: |-
LoadBalancerClass is the class of the load balancer implementation
to use for the Envoy Service when Type is LoadBalancerService.
This maps to Service.spec.loadBalancerClass.
type: string
loadBalancerSourceRanges:
description: |-
LoadBalancerSourceRanges is an optional list of IP ranges in CIDR form
which are allowed to access the LoadBalancer type Envoy Service.
This maps to Service.spec.loadBalancerSourceRanges.
Only applies when Type is LoadBalancerService.
items:
type: string
type: array
serviceAnnotations:
additionalProperties:
type: string
Expand Down
15 changes: 15 additions & 0 deletions examples/render/contour-gateway.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4021,6 +4021,21 @@ spec:
a single IP family on single-stack clusters), or "RequireDualStack"
(two IP families on dual-stack configured clusters, otherwise fail).
type: string
loadBalancerClass:
description: |-
LoadBalancerClass is the class of the load balancer implementation
to use for the Envoy Service when Type is LoadBalancerService.
This maps to Service.spec.loadBalancerClass.
type: string
loadBalancerSourceRanges:
description: |-
LoadBalancerSourceRanges is an optional list of IP ranges in CIDR form
which are allowed to access the LoadBalancer type Envoy Service.
This maps to Service.spec.loadBalancerSourceRanges.
Only applies when Type is LoadBalancerService.
items:
type: string
type: array
serviceAnnotations:
additionalProperties:
type: string
Expand Down
15 changes: 15 additions & 0 deletions examples/render/contour.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4210,6 +4210,21 @@ spec:
a single IP family on single-stack clusters), or "RequireDualStack"
(two IP families on dual-stack configured clusters, otherwise fail).
type: string
loadBalancerClass:
description: |-
LoadBalancerClass is the class of the load balancer implementation
to use for the Envoy Service when Type is LoadBalancerService.
This maps to Service.spec.loadBalancerClass.
type: string
loadBalancerSourceRanges:
description: |-
LoadBalancerSourceRanges is an optional list of IP ranges in CIDR form
which are allowed to access the LoadBalancer type Envoy Service.
This maps to Service.spec.loadBalancerSourceRanges.
Only applies when Type is LoadBalancerService.
items:
type: string
type: array
serviceAnnotations:
additionalProperties:
type: string
Expand Down
7 changes: 7 additions & 0 deletions internal/provisioner/controller/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,13 @@ func (r *gatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
}

contourModel.Spec.NetworkPublishing.Envoy.ServiceAnnotations = networkPublishing.ServiceAnnotations

if len(networkPublishing.LoadBalancerSourceRanges) > 0 {
contourModel.Spec.NetworkPublishing.Envoy.LoadBalancerSourceRanges = networkPublishing.LoadBalancerSourceRanges
}
if networkPublishing.LoadBalancerClass != nil {
contourModel.Spec.NetworkPublishing.Envoy.LoadBalancerClass = networkPublishing.LoadBalancerClass
}
Comment on lines +312 to +317

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we can simplify

Suggested change
if len(networkPublishing.LoadBalancerSourceRanges) > 0 {
contourModel.Spec.NetworkPublishing.Envoy.LoadBalancerSourceRanges = networkPublishing.LoadBalancerSourceRanges
}
if networkPublishing.LoadBalancerClass != nil {
contourModel.Spec.NetworkPublishing.Envoy.LoadBalancerClass = networkPublishing.LoadBalancerClass
}
contourModel.Spec.NetworkPublishing.Envoy.LoadBalancerSourceRanges = networkPublishing.LoadBalancerSourceRanges
contourModel.Spec.NetworkPublishing.Envoy.LoadBalancerClass = networkPublishing.LoadBalancerClass

}

// Node placement
Expand Down
38 changes: 38 additions & 0 deletions internal/provisioner/controller/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,44 @@ func TestGatewayReconcile(t *testing.T) {
assert.Equal(t, int32(30001), svc.Spec.Ports[1].Port)
},
},
"If ContourDeployment.Spec.Envoy.NetworkPublishing sets LoadBalancer source ranges and class, they are applied to the Envoy service": {
gatewayClass: reconcilableGatewayClassWithParams("gatewayclass-1", controller),
gatewayClassParams: &contour_v1alpha1.ContourDeployment{
ObjectMeta: meta_v1.ObjectMeta{
Namespace: "projectcontour",
Name: "gatewayclass-1-params",
},
Spec: contour_v1alpha1.ContourDeploymentSpec{
Envoy: &contour_v1alpha1.EnvoySettings{
NetworkPublishing: &contour_v1alpha1.NetworkPublishing{
Type: contour_v1alpha1.LoadBalancerServicePublishingType,
LoadBalancerSourceRanges: []string{"10.0.0.0/8", "192.168.1.0/24"},
LoadBalancerClass: ptr.To("service.k8s.aws/nlb"),
},
},
},
},
gateway: makeGateway(),
assertions: func(t *testing.T, r *gatewayReconciler, gw *gatewayapi_v1.Gateway, reconcileErr error) {
require.NoError(t, reconcileErr)

require.NoError(t, r.client.Get(context.Background(), keyFor(gw), gw))
require.Len(t, gw.Status.Conditions, 1)
assert.Equal(t, string(gatewayapi_v1.GatewayConditionAccepted), gw.Status.Conditions[0].Type)
assert.Equal(t, meta_v1.ConditionTrue, gw.Status.Conditions[0].Status)

svc := &core_v1.Service{
ObjectMeta: meta_v1.ObjectMeta{
Namespace: "gateway-1",
Name: "envoy-gateway-1",
},
}
require.NoError(t, r.client.Get(context.Background(), keyFor(svc), svc))
assert.Equal(t, core_v1.ServiceTypeLoadBalancer, svc.Spec.Type)
assert.Equal(t, []string{"10.0.0.0/8", "192.168.1.0/24"}, svc.Spec.LoadBalancerSourceRanges)
assert.Equal(t, ptr.To("service.k8s.aws/nlb"), svc.Spec.LoadBalancerClass)
},
},
"If ContourDeployment.Spec.Envoy.WorkloadType is set to Deployment, an Envoy deployment is provisioned with the specified number of replicas": {
gatewayClass: reconcilableGatewayClassWithParams("gatewayclass-1", controller),
gatewayClassParams: &contour_v1alpha1.ContourDeployment{
Expand Down
10 changes: 10 additions & 0 deletions internal/provisioner/equality/equality.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ func LoadBalancerServiceChanged(current, expected *core_v1.Service) (*core_v1.Se
changed = true
}

if !apiequality.Semantic.DeepEqual(current.Spec.LoadBalancerSourceRanges, expected.Spec.LoadBalancerSourceRanges) {
updated.Spec.LoadBalancerSourceRanges = expected.Spec.LoadBalancerSourceRanges
changed = true
}

if !apiequality.Semantic.DeepEqual(current.Spec.LoadBalancerClass, expected.Spec.LoadBalancerClass) {
updated.Spec.LoadBalancerClass = expected.Spec.LoadBalancerClass
changed = true
}

Comment on lines +195 to +199

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The comment on LoadBalancerClass says (link)

This field can only be set when creating or updating a Service to type 'LoadBalancer'. Once set, it can not be changed. This field will be wiped when a service is updated to a non 'LoadBalancer' type.

So since we cannot update this, the inequality should be ignored, or what do you think?

if !changed {
return nil, false
}
Expand Down
14 changes: 14 additions & 0 deletions internal/provisioner/equality/equality_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,20 @@ func TestLoadBalancerServiceChanged(t *testing.T) {
},
expect: true,
},
{
description: "if load balancer source ranges changed",
mutate: func(svc *core_v1.Service) {
svc.Spec.LoadBalancerSourceRanges = []string{"10.0.0.0/8"}
},
expect: true,
},
{
description: "if load balancer class changed",
mutate: func(svc *core_v1.Service) {
svc.Spec.LoadBalancerClass = ptr.To("service.k8s.aws/nlb")
},
expect: true,
},
}

for _, tc := range testCases {
Expand Down
8 changes: 8 additions & 0 deletions internal/provisioner/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,14 @@ type EnvoyNetworkPublishing struct {
//
// If unset, defaults to "Local".
ExternalTrafficPolicy core_v1.ServiceExternalTrafficPolicy

// LoadBalancerSourceRanges is an optional list of IP ranges in CIDR form
// which are allowed to access the LoadBalancer type Envoy Service.
LoadBalancerSourceRanges []string

// LoadBalancerClass is the class of the load balancer implementation
// to use for the Envoy Service when Type is LoadBalancerService.
LoadBalancerClass *string
}

type NetworkPublishingType = contour_v1alpha1.NetworkPublishingType
Expand Down
10 changes: 10 additions & 0 deletions internal/provisioner/objects/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,16 @@ func DesiredEnvoyService(contour *model.Contour) *core_v1.Service {
maps.Copy(svc.Annotations, contour.Spec.NetworkPublishing.Envoy.ServiceAnnotations)
}

// Optional LoadBalancer Service fields from ContourDeployment networkPublishing.
if epType == model.LoadBalancerServicePublishingType {
if len(contour.Spec.NetworkPublishing.Envoy.LoadBalancerSourceRanges) > 0 {
svc.Spec.LoadBalancerSourceRanges = contour.Spec.NetworkPublishing.Envoy.LoadBalancerSourceRanges
}
if contour.Spec.NetworkPublishing.Envoy.LoadBalancerClass != nil {
svc.Spec.LoadBalancerClass = contour.Spec.NetworkPublishing.Envoy.LoadBalancerClass
}
}
Comment on lines +300 to +308

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Lets move these under load balancer type case

	switch epType {
	case model.LoadBalancerServicePublishingType:
       // all loadbalancer type related fields set here


return svc
}

Expand Down
36 changes: 36 additions & 0 deletions internal/provisioner/objects/service/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,39 @@ func TestDesiredEnvoyService(t *testing.T) {
checkServiceHasType(t, svc, core_v1.ServiceTypeClusterIP)
checkServiceHasAnnotations(t, svc) // passing no keys means we expect no annotations
}

func TestDesiredEnvoyServiceLoadBalancerFields(t *testing.T) {
cntr := model.Default(fmt.Sprintf("%s-%s", "test", "ns"), "test-contour")
cntr.Spec.NetworkPublishing.Envoy.Type = model.LoadBalancerServicePublishingType
cntr.Spec.NetworkPublishing.Envoy.LoadBalancerSourceRanges = []string{"10.0.0.0/8", "192.168.1.0/24"}
lbClass := "internal-nlb"
cntr.Spec.NetworkPublishing.Envoy.LoadBalancerClass = &lbClass

svc := DesiredEnvoyService(cntr)
if len(svc.Spec.LoadBalancerSourceRanges) != 2 {
t.Fatalf("expected 2 source ranges, got %v", svc.Spec.LoadBalancerSourceRanges)
}
if svc.Spec.LoadBalancerSourceRanges[0] != "10.0.0.0/8" {
t.Fatalf("unexpected source range: %v", svc.Spec.LoadBalancerSourceRanges)
}
if svc.Spec.LoadBalancerClass == nil || *svc.Spec.LoadBalancerClass != "internal-nlb" {
t.Fatalf("unexpected loadBalancerClass: %v", svc.Spec.LoadBalancerClass)
}
}

func TestDesiredEnvoyServiceLoadBalancerFieldsIgnoredForClusterIP(t *testing.T) {
// LoadBalancer-only fields must not leak onto non-LB publishing types.
cntr := model.Default(fmt.Sprintf("%s-%s", "test", "ns"), "test-contour")
cntr.Spec.NetworkPublishing.Envoy.Type = model.ClusterIPServicePublishingType
cntr.Spec.NetworkPublishing.Envoy.LoadBalancerSourceRanges = []string{"10.0.0.0/8"}
lbClass := "internal-nlb"
cntr.Spec.NetworkPublishing.Envoy.LoadBalancerClass = &lbClass

svc := DesiredEnvoyService(cntr)
if len(svc.Spec.LoadBalancerSourceRanges) != 0 {
t.Fatalf("expected no source ranges on ClusterIP service, got %v", svc.Spec.LoadBalancerSourceRanges)
}
if svc.Spec.LoadBalancerClass != nil {
t.Fatalf("expected nil loadBalancerClass on ClusterIP service, got %v", *svc.Spec.LoadBalancerClass)
}
}
31 changes: 31 additions & 0 deletions site/content/docs/main/config/api-reference.html
Original file line number Diff line number Diff line change
Expand Up @@ -8896,6 +8896,37 @@ <h3 id="projectcontour.io/v1alpha1.NetworkPublishing">NetworkPublishing
the provisioned Envoy service.</p>
</td>
</tr>
<tr>
<td style="white-space:nowrap">
<code>loadBalancerSourceRanges</code>
<br>
<em>
[]string
</em>
</td>
<td>
<em>(Optional)</em>
<p>LoadBalancerSourceRanges is an optional list of IP ranges in CIDR form
which are allowed to access the LoadBalancer type Envoy Service.
This maps to Service.spec.loadBalancerSourceRanges.
Only applies when Type is LoadBalancerService.</p>
</td>
</tr>
<tr>
<td style="white-space:nowrap">
<code>loadBalancerClass</code>
<br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>LoadBalancerClass is the class of the load balancer implementation
to use for the Envoy Service when Type is LoadBalancerService.
This maps to Service.spec.loadBalancerClass.</p>
</td>
</tr>
</tbody>
</table>
<h3 id="projectcontour.io/v1alpha1.NetworkPublishingType">NetworkPublishingType
Expand Down