Set loadBalancerSourceRanges and loadBalancerClass on the gateway and leafnode Services #11

Closed
opened 2026-10-04 10:13:17 +00:00 by mikluko · 0 comments
mikluko commented 2026-10-04 10:13:17 +00:00 (Migrated from github.com)

Summary

ServiceTemplate accepts type and annotations.
Add loadBalancerSourceRanges and loadBalancerClass to it.
Then gateway.service and leafnodes.service can state which clients a load balancer accepts and which implementation serves it.

Problem

A NatsCluster with gateway.service.type set to LoadBalancer gets a load balancer that accepts what the platform accepts by default.
The observation comes from EKS Auto Mode with Kubernetes 1.36 and nats-operator 0.1.1.
An internal load balancer created this way accepted connections from VPCs peered with the Kubernetes cluster's VPC.

That default matters most for a gateway without TLS.
The install page says that under --allow-gateway-without-tls "any peer that reaches the gateway port joins the supercluster".
For such a gateway the network is the only admission, and the template cannot narrow it.

An annotation does not close the gap on every platform.
The EKS Auto Mode load balancer documentation directs you from the service.beta.kubernetes.io/load-balancer-source-ranges annotation to spec.loadBalancerSourceRanges.
The same page directs you from the service.beta.kubernetes.io/aws-load-balancer-type annotation to spec.loadBalancerClass.

Proposed fields

The table lists the two fields to add to ServiceTemplate in api/cluster/v1beta1/natscluster_types.go.

Field Type Sets on the Service Validation
loadBalancerSourceRanges list of CIDR strings spec.loadBalancerSourceRanges Refused unless type is LoadBalancer.
loadBalancerClass string spec.loadBalancerClass Refused unless type is LoadBalancer. Refused when it changes.

Kubernetes rejects a change to spec.loadBalancerClass.
The API describes the field with "Once set, it can not be changed".
A transition rule on the NatsCluster reports that refusal when you apply the manifest.

A gateway that uses both fields looks like this:

gateway:
  service:
    type: LoadBalancer
    loadBalancerClass: eks.amazonaws.com/nlb
    loadBalancerSourceRanges:
      - 10.20.0.0/16
      - 2001:db8:20::/56
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-scheme: internal

Controller changes

The cluster controller renders and updates each Service in separate places, and both need the fields.

  • Render. gatewayService in internal/natscluster/objects.go and leafnodesService in internal/natscluster/leafnodes.go copy the two fields from the template into the Service.
  • Update. applyShared in internal/natscluster/controller.go and applyLeafnodes in internal/natscluster/leafnodes.go update an existing Service field by field. Each copies the two fields too. Without that, an edit to the template never reaches a Service that exists.
  • Generated output. Regenerate the CRD in the chart and the API reference page.
  • Tests. Cover the render and the update of each Service.
## Summary `ServiceTemplate` accepts `type` and `annotations`. Add `loadBalancerSourceRanges` and `loadBalancerClass` to it. Then `gateway.service` and `leafnodes.service` can state which clients a load balancer accepts and which implementation serves it. ## Problem A `NatsCluster` with `gateway.service.type` set to LoadBalancer gets a load balancer that accepts what the platform accepts by default. The observation comes from EKS Auto Mode with Kubernetes 1.36 and nats-operator 0.1.1. An internal load balancer created this way accepted connections from VPCs peered with the Kubernetes cluster's VPC. That default matters most for a gateway without TLS. The install page says that under `--allow-gateway-without-tls` "any peer that reaches the gateway port joins the supercluster". For such a gateway the network is the only admission, and the template cannot narrow it. An annotation does not close the gap on every platform. The [EKS Auto Mode load balancer documentation](https://docs.aws.amazon.com/eks/latest/userguide/auto-configure-nlb.html) directs you from the `service.beta.kubernetes.io/load-balancer-source-ranges` annotation to `spec.loadBalancerSourceRanges`. The same page directs you from the `service.beta.kubernetes.io/aws-load-balancer-type` annotation to `spec.loadBalancerClass`. ## Proposed fields The table lists the two fields to add to `ServiceTemplate` in `api/cluster/v1beta1/natscluster_types.go`. | Field | Type | Sets on the Service | Validation | |---|---|---|---| | `loadBalancerSourceRanges` | list of CIDR strings | `spec.loadBalancerSourceRanges` | Refused unless `type` is LoadBalancer. | | `loadBalancerClass` | string | `spec.loadBalancerClass` | Refused unless `type` is LoadBalancer. Refused when it changes. | Kubernetes rejects a change to `spec.loadBalancerClass`. The API describes the field with "Once set, it can not be changed". A transition rule on the `NatsCluster` reports that refusal when you apply the manifest. A gateway that uses both fields looks like this: ```yaml gateway: service: type: LoadBalancer loadBalancerClass: eks.amazonaws.com/nlb loadBalancerSourceRanges: - 10.20.0.0/16 - 2001:db8:20::/56 annotations: service.beta.kubernetes.io/aws-load-balancer-scheme: internal ``` ## Controller changes The cluster controller renders and updates each Service in separate places, and both need the fields. - **Render.** `gatewayService` in `internal/natscluster/objects.go` and `leafnodesService` in `internal/natscluster/leafnodes.go` copy the two fields from the template into the Service. - **Update.** `applyShared` in `internal/natscluster/controller.go` and `applyLeafnodes` in `internal/natscluster/leafnodes.go` update an existing Service field by field. Each copies the two fields too. Without that, an edit to the template never reaches a Service that exists. - **Generated output.** Regenerate the CRD in the chart and the API reference page. - **Tests.** Cover the render and the update of each Service.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
mikluko/nats-operator#11
No description provided.