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

VirtualService matcher WithoutHeaders not matching when header is missing #50988

Closed
2 tasks done
Sodman opened this issue May 10, 2024 · 2 comments
Closed
2 tasks done

Comments

@Sodman
Copy link
Contributor

Sodman commented May 10, 2024

Is this the right place to submit this?

  • This is not a security vulnerability or a crashing bug
  • This is not a question about how to use Istio

Bug Description

When using the withoutHeaders matcher on a http route within a VirtuallService, the header must be present for it to match, which is misleading - not sure if this is a bug or perhaps docs clarification issue.

On the docs page for virtual service there's a field under HTTPMatchRequest named withoutHeaders. The description is:

withoutHeader has the same syntax with the header, but has opposite meaning. If a header is matched with a matching rule among withoutHeader, the traffic becomes not matched one.

I would have assumed that this is essentially the inverse of the "header" matcher. i.e. if I have a header matcher which matches one header with a specific value:

  http:
  - match:
    - headers:
        version:
          exact: v1

I would assume that a withoutHeaders should match the inverse:

  http:
  - match:
    - withoutHeaders:
        version:
          exact: v1

However, the latter only matches when the header "version" is present AND does not match the given value. My intuition here would be that if the header does not match OR is not present at all, it should be considered a match.

Full example VirtualService using bookinfo example:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews-traffic-split-v1-v2-v3
  namespace: bookinfo
spec:
  exportTo:
  - .
  gateways:
  - mesh
  hosts:
  - reviews.bookinfo.svc.cluster.local
  http:
  - match:
    - headers:
        version:
          exact: v1
    name: v1-explicit
    route:
    - destination:
        host: reviews.bookinfo.svc.cluster.local
        port:
          number: 9080
        subset: v1
  - match:
    - withoutHeaders:
        version:
          exact: v1
    name: v3-catchall-default
    route:
    - destination:
        host: reviews.bookinfo.svc.cluster.local
        port:
          number: 9080
        subset: v3

Using the standard example DestinationRule which splits reviews by 'version' label:

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: reviews-destination
  namespace: bookinfo
spec:
  host: reviews.bookinfo.svc.cluster.local
  subsets:
  - labels:
      version: v1
    name: v1
  - labels:
      version: v2
    name: v2
  - labels:
      version: v3
    name: v3

When I make a curl from productpage in the bookinfo namespace, I see when I pass the v1 header, it works as expected with the header matching:

/ $ curl -H "version: v1" reviews.bookinfo.svc.cluster.local:9080/reviews/1
{"id": "1","podname": "reviews-v1-ddf8c7659-29vn7","clustername": "null","reviews": [{  "reviewer": "Reviewer1",  "text": "An extremely entertaining play by Shakespeare. The slapstick humour is refreshing!"},{  "reviewer": "Reviewer2",  "text": "Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare."}]}/ $

But when I curl without any header at all, I get a 404:

/ $ curl reviews.bookinfo.svc.cluster.local:9080/reviews/1 -v
*   Trying 10.43.190.226:9080...
* Connected to reviews.bookinfo.svc.cluster.local (10.43.190.226) port 9080 (#0)
> GET /reviews/1 HTTP/1.1
> Host: reviews.bookinfo.svc.cluster.local:9080
> User-Agent: curl/7.76.1-DEV
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< date: Fri, 10 May 2024 17:00:05 GMT
< server: envoy
< content-length: 0
<
* Connection #0 to host reviews.bookinfo.svc.cluster.local left intact

Note that if I include the header and use any value other than 'v1', I do get matched as expected:

/ $ curl -H "version: anything-else" reviews.bookinfo.svc.cluster.local:9080/reviews/1
{"id": "1","podname": "reviews-v3-77f796db6-fxlfx","clustername": "null","reviews": [{  "reviewer": "Reviewer1",  "text": "An extremely entertaining play by Shakespeare. The slapstick humour is refreshing!", "rating": {"stars": 5, "color": "red"}},{  "reviewer": "Reviewer2",  "text": "Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare.", "rating": {"stars": 4, "color": "red"}}]}/ $

Should the request which does not contain the header match on the route where that header is included in the withoutHeaders matcher?

Version

$ istioctl version
client version: 1.21.0
control plane version: 1.21.0
data plane version: 1.21.0 (6 proxies)

Additional Information

No response

@howardjohn
Copy link
Member

Looks like this might already be fixed in 1.22 but not backported #49606

@Sodman
Copy link
Contributor Author

Sodman commented May 10, 2024

Oh that's great! I don't have any urgency around this one so can just wait for 1.22, no need for a backport imho. Happy to close this one out!

@Sodman Sodman closed this as completed May 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants