Skip to content
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

Webhook: Validate unique port, protocol, and hostname per listener #847

Closed
robscott opened this issue Sep 1, 2021 · 14 comments · Fixed by #1457
Closed

Webhook: Validate unique port, protocol, and hostname per listener #847

robscott opened this issue Sep 1, 2021 · 14 comments · Fixed by #1457
Assignees
Labels
area/webhook good first issue Denotes an issue ready for a new contributor, according to the "help wanted" guidelines. help wanted Denotes an issue that needs help from a contributor. Must meet "help wanted" guidelines. lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness.
Milestone

Comments

@robscott
Copy link
Member

robscott commented Sep 1, 2021

What would you like to be added:
The validating webhook should ensure that port, protocol, and hostname are unique among Gateway listeners. For example, 2 listeners for foo.com would be valid if they were on different ports or protocols, but not if port and protocol were also identical.

Why this is needed:
To provide a better user experience.

@hbagdi hbagdi added good first issue Denotes an issue ready for a new contributor, according to the "help wanted" guidelines. help wanted Denotes an issue that needs help from a contributor. Must meet "help wanted" guidelines. labels Sep 3, 2021
@bishtsaurabh5
Copy link
Contributor

/assign

@bishtsaurabh5
Copy link
Contributor

@robscott I am thinking of generating a hash based on the (Hostname + Port +Protocol) and then store them in a map where key is hash of the listener array and value is the index and if the key is already present then log all the indexes in the errors . Do you have views ?

@k8s-triage-robot
Copy link

The Kubernetes project currently lacks enough contributors to adequately respond to all issues and PRs.

This bot triages issues and PRs according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Mark this issue or PR as fresh with /remove-lifecycle stale
  • Mark this issue or PR as rotten with /lifecycle rotten
  • Close this issue or PR with /close
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/lifecycle stale

@k8s-ci-robot k8s-ci-robot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Dec 6, 2021
@hbagdi
Copy link
Contributor

hbagdi commented Dec 6, 2021

/lifecycle frozen

@k8s-ci-robot k8s-ci-robot added lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness. and removed lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. labels Dec 6, 2021
@gyohuangxin
Copy link
Member

@robscott @bishtsaurabh5 May I know if this feature is still required based on the current design? If so, I'd like to continue to implement this.

@robscott
Copy link
Member Author

Hey @gyohuangxin, thanks for checking! This is still unimplemented and would be a nice addition to https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/validation/gateway.go. Let me know if you're still interested in implementing this.

@akankshakumari393
Copy link
Member

Hey i would like to contribute if no one is working on it.

@gyohuangxin
Copy link
Member

@robscott Thanks! I'd like to contribute on this.
@akankshakumari393 Sorry! I'm working on this, but any reviews and comments are welcome :)

@gyohuangxin
Copy link
Member

/assign

@gyohuangxin
Copy link
Member

I meet an issue when implementing this feature. My method is to add a function in https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1beta1/validation/gateway.go, which will create a Kubernetes client via "sigs.k8s.io/controller-runtime/pkg/client" to get gateways resource list at cluster scope, here is the example code:

func listGateway() (*v1beta1.GatewayList, error) {

	cfg, err := config.GetConfig()
	if err != nil {
		klog.Errorf("Error loading Kubernetes config: %v", err)
	}
	cl, err := client.New(cfg, client.Options{})
	if err != nil {
		klog.Errorf("Failed to create new Kubernetes client: %v", err)
	}

	v1beta1.AddToScheme(cl.Scheme())

	gatewayList := &v1beta1.GatewayList{}
	err = cl.List(context.Background(), gatewayList, &client.ListOptions{})
	if err != nil {
		return nil, err
	}

	return gatewayList, nil
}

func validateUniquePort(listeners []gatewayv1b1.Listener, path *field.Path) field.ErrorList {
	var errs field.ErrorList

	gatewayList, err := listGateway()
	if err != nil {
		klog.Errorf("Failed to list gateways: %v", err)
	}
	klog.Infof("Gateways resources: %v", gatewayList)

	return errs
}

However, it doesn't work because the user "system:serviceaccount:gateway-system:default" used by webhook server is forbidden to list "gateway" resource at cluster scope.

I1012 14:51:51.693874       1 request.go:1073] Response Body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"gateways.gateway.networking.k8s.io is forbidden: User \"system:serviceaccount:gateway-system:default\" cannot list resource \"gateways\" in API group \"gateway.networking.k8s.io\" at the cluster scope","reason":"Forbidden","details":{"group":"gateway.networking.k8s.io","kind":"gateways"},"code":403}
E1012 15:44:42.933257       1 gateway.go:132] Failed to list gateways: gateways.gateway.networking.k8s.io is forbidden: User "system:serviceaccount:gateway-system:default" cannot list resource "gateways" in API group "gateway.networking.k8s.io" at the cluster scope
I1012 15:44:42.933278       1 gateway.go:134] Listing gateways resources: <nil>

@robscott Do you have any ideas?

@robscott
Copy link
Member Author

Hey @gyohuangxin, sorry for the confusion here! This was actually intended to be smaller in scope than that. Instead of ensuring that a Listener's port, protocol, and hostname are unique across all Gateways, we want to make sure that they are unique within each individual Gateway. A quick example:

What we're trying to prevent with this validation:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  name: example-gateway
spec:
  gatewayClassName: example-gateway-class
  listeners:
  - name: http
    protocol: HTTP
    port: 80
  - name: other-http
    protocol: HTTP
    port: 80

What we don't care about:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  name: example-gateway
spec:
  gatewayClassName: example-gateway-class
  listeners:
  - name: http
    protocol: HTTP
    port: 80
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  name: example-gateway2
spec:
  gatewayClassName: example-gateway-class
  listeners:
  - name: http
    protocol: HTTP
    port: 80

@gyohuangxin
Copy link
Member

@robscott Understand, thanks for clarifying!

@dprotaso
Copy link
Contributor

dprotaso commented Feb 7, 2023

we want to make sure that they are unique within each individual Gateway. A quick example:

This seems fairly limited in my opinion. What about other properties in the listeners?

Looking at the discussion (#1248) we could have many certificates (HTTP01) for services in a cluster. If there are multiple controllers updating the gateway listener resource that'll lead to conflicts and churn.

In theory a way to coordinate this could be by adding multiple listeners but with the same protocol/port and hostname but with a different name and tls configuration

ie.

apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  name: example-gateway
spec:
  gatewayClassName: example-gateway-class
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    tls: 
      certificateRefs: [some-cert]
  - name: https-2
    protocol: HTTPS
    port: 443
    tls: 
      certificateRefs: [another-cert]

Alternatively maybe we should ensure merging of distinct Gateways resources is part of the core functionality.

@dprotaso
Copy link
Contributor

dprotaso commented Feb 8, 2023

Actually I realize the listeners would have unique hostname's when setting tls - so my comment isn't applicable.

@shaneutt shaneutt added this to the v0.7.0 milestone Mar 8, 2023
@shaneutt shaneutt moved this to In Progress in Gateway API: The Road to GA Mar 8, 2023
@github-project-automation github-project-automation bot moved this from In Progress to Done in Gateway API: The Road to GA Apr 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/webhook good first issue Denotes an issue ready for a new contributor, according to the "help wanted" guidelines. help wanted Denotes an issue that needs help from a contributor. Must meet "help wanted" guidelines. lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness.
Projects
No open projects
9 participants