-
Notifications
You must be signed in to change notification settings - Fork 593
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
Add SNI match criteria to routes #863
Conversation
f971d12
to
2e7417f
Compare
Revised, now more or less complete, with tests. Questions and/or points of interest arose!
|
Forgot to mark this ready the other day. IMO main question is whether we'd want to defer this until we can add an override annotation or some other means of explicitly providing SNI values in the event that the automatic default doesn't work. That allow users to handle the "support SNI-incapable clients" (provide the empty string to disable automatic population from the rule hostname) and wildcard case (non-ideal, but allows you to provide a value where you'd otherwise have none). As-is, this works well when clients support SNI (most do) and rules have absolute hostnames. Unsure how common wildcard host rules are, but the fallback behavior isn't terrible (you simply don't get SNI info for them, and would be in the same situation as you are without this change--mTLS requests a client cert when it may not need it). Especially if there are other review concerns, given the planned 1.0 release timeframe, adding |
05094ce
to
7827825
Compare
Force-pushed to fold in-progress commits into the main commit, with a separate commit for the override annotation.
Minor point to note during review: we kinda allow you to specify TLS info on a single Ingress only while omitting it from other Ingresses with a hostname covered by that certificate, which in turn configures Kong to present that certificate for the omitted routes (Kong does not bind certificates to routes at all; they have their own SNI configuration, and we de-duplicate TLS info to create it). You cannot do the same and get SNI match criteria, as that's conditioned on having TLS info present. That maybe doesn't matter so much for what we do, but does raise some questions: I'm unsure how the router behaves if you provide SNI match criteria on a route that's dual-stack HTTP+HTTPS, and if doing so actually makes the router not match for HTTP requests (they won't have SNI ever, because they don't have TLS), that's arguably a core bug, but a significant enough one that it'd probably block this feature. Hopefully this isn't the case, but it's major enough that I want to check. |
Hope is a fickle thing, and my fears were correct. See Kong/kong#6425 for why this is now donotmerge. Assuming larger core changes are farther out, we'll probably want to do an initial controller release that only has the annotation/manual SNI configuration. Manual configuration does not actually work around the core issue, but it does allow you to choose which routes are affected. |
7827825
to
5a027e8
Compare
Force-pushed to pull in latest next and clean up the WIP commits. Latest adds KongIngress support, so this should be good to go. It does neuter automatic SNI criteria handling for the time being: while I think this is a useful quality of life feature, Kong/kong#6425 precludes it. We'd still want to add a flag to gate it once that issue is fixed, however, as older Kong versions will still include the router bug. |
bea9ddc
to
0407f8c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Several nits attached.
I recommend that we hold this PR back until #869 gets in, and then add an E2E test for this case. This functionality clearly deserves an E2E test case I think.
Commenting on all the items raised outside context because I'm trying to address two competing goals with the inline comments: when I'm working through a review, it's currently useful for me to resolve inline comments as I fix them locally, because that marks them "done" and I don't try and pay attention to them still when I've already written a commit locally, and can focus on those I haven't yet addressed. At the same time, this makes it annoying to try and then respond to them inline, because the contents are hidden. Alas, I must choose one or the other, and working on a set of responses in an non-contextual comment works well enough for me while I'm stuck on a small screen because pandemic workspaces 🤷♀️
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code looks good. I do think that this scenario requires proper integration testing, though:
This PR introduces a significant change to KIC's behavior that will be a critical part of the setup for users relying on SNI/mTLS. From the discussion around this PR it's pretty clear that we plan further changes to this functionality. I think that such changes pose a significant regression risk for users.
One of the purposes of the E2E test is that this functionality won't regress, either because of a change on our side, or on Kong core's. There are multiple moving parts involved in SNI-based (and possibly mTLS-enabled) proxying. Therefore, I'm convinced that we need to guarantee stability of this functionality, and that an E2E test case is the easiest way to achieve that, given the complexity of this feature.
Example of a test that I consider necessary here:
- Define multiple SNI-enabled routes, some of these routes requiring a client certificate and some not
- Connect to Kong trying to access certain routes with various certificates, and ensure that mTLS works as intended in those cases.
Howso? I'd argue that without the originally proposed, and now removed modification, that it doesn't. Annotations/KongIngress fields that set Kong route fields aren't novel; we already have six of them, and this new annotation/field uses the same implementation pattern as the rest. The only unusual thing about it is that it does perform a validation and sanitization step to strip spaces and reject invalid SNI hostnames that we know Kong will reject. That's not entirely novel either: we do the same thing for when translating While validation is arguably the most complex part, it's not very complex: it checks the hostname string against a regular expression using regexp and, if it observes an invalid hostname, logs it along with the attached route without setting the Kong route
How do you want to handle this in light of the last point in my previous comment? I understand the desire to do this in general, but in this case there's an extra complication: we know that the current core behavior is already broken. It's not completely broken (HTTPS requests that include SNI in the client handshake do indeed route correctly), but the core team has already acknowledged that the issue is real and that they are writing a fix for it. While that's in progress, we won't know the full scope of the change until it's done and merged, and we know that any E2E test we write now will have to change to accommodate the new behavior and possible changes to the existing HTTPS behavior. I'm not trying to say that we shouldn't do it ever, I'm trying to say that it's hard to do now, and that we can acknowledge those external complexities and commit to returning to it later, which is why I said as much in #929. |
https://gist.github.com/rainest/493ccad267ad7e641d37b51dff3d1089 provides an example test that checks this with the current proposed changes in #869. However, it relies on magic values for the verification commands, and we should not include it as such. E.g.
To take advantage of |
The test logic looks good to me.
I fully agree. I am fine with either doing something like this in IFS=: read sut_hostname sut_port <<< "$SUT_HTTPS_HOST"
# now $sut_hostname and $sut_port yield the host and port or patching the test machinery to break up |
Went with the suggested string mangling route. Not ideal, but difficulty with mostly string-based operation in the existing bash-based system is the rationale for #939, so we may as well stick with that for now since the transformation from the existing value exposed in the test infrastructure isn't that complicated. Noticed a minor block in that this is targeted at next, but we haven't merged main into next in a while and only main has the E2E tests. We should be fine to go ahead and do that, as only this and #859 (which is old enough that it'd probably need some merge work anyway) are currently open against next, but I didn't want to go ahead and do that unilaterally. a200315 adds the modified test into a branch that cherry-picks the E2E stuff only; it passes, so we should be good to go after the main->next merge. There are still some minor cleanup tasks after because of manifest changes. My changes to the base manifests don't conflict with anything, but the generated versions in this branch do conflict with main. We don't care about generated stuff really, so to bring this in line with post-merge next, it will need:
That looks good to me locally. |
35f1fff
to
e2f55ed
Compare
Add SNI match criteria to Kong routes when the source Ingress has a TLS rule with hostnames.
Add an Ingress annotation and KongIngress functionality for setting route SNI match criteria. Although the controller adds SNI criteria automatically for Ingresses that contain rules with hostnames and have TLS information, there are some scenarios that require setting SNI manually: * You wish to strip SNI match criteria from the route, in order to support SNI-incapable clients. SNI annotation processing is unusual to accommodate this: providing a "konghq.com/snis: ''" annotation is distinct from not providing the annotation at all, and instructs the controller to strip SNI information that it'd normally add automatically. * You use wildcard hostnames in your rules. Kong does not allow wildcard match criteria as of 2.1, and as such you must enumerate the specific SNI matches you want when using a wildcard hostname. * You wish to use a completely different SNI match criteria that does not match your rule hostnames at all. This is highly atypical, and should only be done if you know exactly why you need to do it.
Disable automatic SNI criteria addition by commenting out the code that adds it. This is a useful convenience feature, but would cause breakage because of Kong/kong#6425 Once that issue is fixed, we should re-enable this functionality, but gate it with a flag, to avoid issues with older Kong versions.
Use SNI (rather than sni) throughout, and prefix which version is unsafe rather than which version is safe.
e2f55ed
to
ebd5c52
Compare
@@ -0,0 +1,7 @@ | |||
#!/bin/bash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also add test cases verifying that:
- https requests to example.com and example.net present appropriate certificates - stackoverflow - hopefully our test environment has openssl installed
- https requests to example.com/bar and example.net/foo yield 404
- http requests to example.com/foo and example.net/bar yield 404
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added 404 check. The router doesn't actually handle choosing what certificate to present, and will happily SNI route even if the certificate doesn't actually match. You wouldn't do that in practice (the test YAML seeks to present a realistic configuration even though there are parts of it we don't care about), but as far as the proxy implementation is concerned, they're not actually coupled together.
Given that presenting the correct certificate isn't actually in scope for what the route SNI property does and that there's no good way to extract the certificate hostname (both curl and s_client will only present that in human-readable verbose output--neither has a dedicated "return CN only" tool), I think the 404 test should be sufficient here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see. I have just realized that the current test (in this PR) does not verify the functionality changed by this PR.
We need a test that ensures that, if there is an Ingress
resource with a konghq.com/snis
annotation, then it won't match if a request comes with a different SNI. I wrote baf06f6 to fix that. Lines 14-15 fail for KIC without this PR, but pass for KIC with this PR. (This commit also adds further 404 cases that I asked for in a previous comment in this thread).
Could we cherry-pick one test commit as explained in #863 (comment) ? Then the PR is ready to go 👍 |
What this PR does / why we need it:
Add SNI match criteria to Kong routes when the source Ingress has a TLS rule with hostnames.
Which issue this PR fixes
fixes internal case FTI-1881. Looks like we didn't create a GH issue for that yet. Whoops.
Special notes for your reviewer:
This change always adds this configuration if possible from the Ingress object. This introduces two possible issues:
As-is, practical testing indicates this works as expected. This remains a WIP because it lacks unit tests and does not attempt to account for the edge cases above.