kumahq / kuma

🐻 The multi-zone service mesh for containers, Kubernetes and VMs. Built with Envoy. CNCF Sandbox Project.
https://kuma.io/install
Apache License 2.0
3.64k stars 331 forks source link

MeshGateway /_rules API: provide matchers for toRules (to know which rules apply to which listeners) #9589

Open kleinfreund opened 7 months ago

kleinfreund commented 7 months ago

Description

In the /_rules API for MeshGateway, we get, among other things, the rules of MeshHTTPRoutes that apply to the MeshGateway. Currently, this is missing the matchers for which tags a toRule applies. We need this so we can filter out rules that don’t apply to a given listener.

Old content In truth however, depending on the `spec.to[]` targetRefs, those rules may only apply to a subset of the MeshGateway’s listeners (or even none of them). For example, if a `spec.to[]` targetRef has a `hostnames` field and there is a listener with a hostname _not_ intersecting with it, the targetRef’s rules don’t apply to that listener. Currently, it’s not transparent on the `/_rules` API response which rules apply to which listeners. To build the kind of UI we want in https://github.com/kumahq/kuma-gui/issues/2208, we need to know this or determine it ourselves. Should the `/_rules` API response somehow identify which listeners its toRules of type MeshHTTPRoute (and possibly others) apply to? As far as I can tell, at least hostnames influence this and possibly tags: - `hostname` on `listeners[]` of MeshGateway and `hostnames` on `spec.to[]` of MeshHTTPRoute need to match - `tags` on `listeners[]` of MeshGateway and `tags` on `spec.to[]` of MeshHTTPRoute need to match **Note on matching hostnames**: Since hostnames can contain wildcard segments (e.g. `*.example.org`), implementing the logic for this in the UI isn’t just the relatively straightforward check for whether the values intersect (or are full wildcards in which case they always intersect). We’d have to match hostnames from top-level domain down to "N-level" domain to determine a match.
lahabana commented 7 months ago

Just added a test case to show the problem: https://github.com/kumahq/kuma/pull/9610

We can see all matchers are empty but they should have entries to differentiate rules that apply to all listeners and the ones that apply to just listener: foo

kleinfreund commented 7 months ago

For my own reference, here’s what I applied (same result: matchers are always empty):

YAMLs ```yaml apiVersion: kuma.io/v1alpha1 kind: MeshGateway mesh: default metadata: name: demo-app namespace: kuma-system labels: kuma.io/mesh: default spec: selectors: - match: kuma.io/service: demo-app_gateway conf: listeners: - port: 80 protocol: HTTP tags: listener: listener-0 - port: 81 hostname: bar.com protocol: HTTP tags: listener: listener-1 --- apiVersion: kuma.io/v1alpha1 kind: MeshHTTPRoute metadata: name: demo-app-1 namespace: kuma-system labels: kuma.io/mesh: default spec: targetRef: kind: MeshGateway name: demo-app to: - targetRef: kind: Mesh rules: - matches: - path: value: "/" type: PathPrefix default: backendRefs: - kind: MeshService name: demo-app_kuma-demo_svc_5000 --- apiVersion: kuma.io/v1alpha1 kind: MeshHTTPRoute metadata: name: demo-app-2 namespace: kuma-system labels: kuma.io/mesh: default spec: targetRef: kind: MeshGateway name: demo-app tags: listener: listener-0 to: - targetRef: kind: Mesh rules: - matches: - path: value: "/api" type: PathPrefix default: backendRefs: - kind: MeshService name: demo-app_kuma-demo_svc_5000 --- apiVersion: kuma.io/v1alpha1 kind: MeshHTTPRoute metadata: name: demo-app-3 namespace: kuma-system labels: kuma.io/mesh: default spec: targetRef: kind: MeshGateway name: demo-app tags: listener: listener-2 to: - targetRef: kind: Mesh hostnames: - foo.com rules: - matches: - path: value: "/test" type: PathPrefix default: backendRefs: - kind: MeshService name: demo-app_kuma-demo_svc_5000 ```
kleinfreund commented 6 months ago

@lahabana Will this make it into 2.7.x?

kleinfreund commented 6 months ago

I was talking with @michaelbeaumont some more about this.

It looks like matchers: [] is expected here because we always deal with to[].targetRef.kind: Mesh and never MeshServiceSubset with tags here. It seems like what we want instead (to be able to relate toRules to matching listeners by tags) is a structure similar to fromRules where the matching listener is "identified" by hostname, port, and tags.

From @michaelbeaumont:

"rules": [
  {
   "fromRules": [],
   "toRules": {
    "inbound": {
        "tags": {..},
        "port": 80,
    },
    "rules": [
    {
     "conf": {
      "rules": [
       {
        "matches": [
         {
          "headers": [
           {
            "type": "Exact",
            "name": "foo",
            "value": "baz"
....

I don’t know how matchers are populated and maybe there’s still something missing here.

lahabana commented 6 months ago

Hmm isn't this similar to how we do matching on specific MeshHTTPRoutes?

kleinfreund commented 6 months ago

To write down the possible API change we just discussed:

Change the toRules structure from an array of rules to an object with a rules property which is the array of rules of the current structure. This would allow for adding more data on the toRules object like an inbound object (in other words: this would mirror the structure of fromRules).

github-actions[bot] commented 2 months ago

This issue was inactive for 90 days. It will be reviewed in the next triage meeting and might be closed. If you think this issue is still relevant, please comment on it or attend the next triage meeting.

michaelbeaumont commented 2 months ago

@lobkovilya is this addressed by https://github.com/kumahq/kuma/pull/10726?

lobkovilya commented 2 months ago

@michaelbeaumont @lahabana if I understand the problem correctly it's not addressed by https://github.com/kumahq/kuma/pull/10726. According to the MADR we'll add toResourceRules field which is an array of ResourceRules and doesn't imply per-listener mapping.

I guess in case of Gateway, we'd want something like:

resource:
  mesh: default
  name: gw-1
  type: MeshGateway
rules:
  toResourceRules: [] # array of ResourceRules
  toResourceRulesPerListener:
    - inbound: {}
      toResourceRule: [] # array of ResourceRules