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

[THREESCALE-1430] Avoid trying to use path-based routing when using HTTPS #938

Merged
merged 5 commits into from Oct 22, 2018

Conversation

davidor
Copy link
Contributor

@davidor davidor commented Oct 19, 2018

When APICAST_HTTPS_ env vars are used to configure SSL certs, enabling path routing does not work. The reason is that when those envs are configured, the find_service policy runs in the ssl_certificate phase which does not have access to the http method nor the path, needed for the path-based routing.

Apart from fixing the issue, this PR refactors the find_service by extracting a couple of classes and reorganizing the tests. I think that properly testing the ssl_certiticate phase without this refactor would have needed lots of duplicated tests.

Ref: https://issues.jboss.org/browse/THREESCALE-1430

I think this makes the tests clearer now. More importantly, it will
allow us to avoid duplicating tests when testing the "ssl_certificate"
phase of the "find_service" policy.
@davidor davidor requested a review from a team as a code owner October 19, 2018 14:44
@@ -0,0 +1,23 @@
local _M = {}

function _M.find_service(config_store, host)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cyclomatic complexity of function '_M.find_service' is too high (8 > 7)


local _M = {}

function _M.find_service(config_store, host)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cyclomatic complexity of function '_M.find_service' is too high (8 > 7)

end

context.service = context.service or
host_based_finder.find_service(context.configuration, context.host)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you can store just find_service in the local variable, so the JIT has it easier and does not have to check if the table changed.

But I see that because of the testing code and stubs you actually need it to be in a table. That is unfortunate.


function _M.new(...)
local self = new(...)

if configuration_store.path_routing then
ngx.log(ngx.WARN, 'apicast path routing enabled')
self.find_service = find_service_cascade
self.find_service = function(configuration, host)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function can be defined in a local variable when loading the file, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be problematic to test as you mentioned above.
This only runs when the configuration is loaded, so it should be fine.

@davidor davidor merged commit 2b48410 into master Oct 22, 2018
@davidor davidor deleted the path-based-with-ssl branch October 22, 2018 08:40
@mayorova
Copy link
Contributor

@davidor
It says "Apart from fixing the issue", but from the code it seems that it doesn't fully fix it, but instead the service finder falls back to finding service only by host, and not by host + path.

While it doesn't matter for SSL in current version, wouldn't it cause unexpected behavior for the rest of the functionality? (as, from what I understand, the found service is stored in the context)

@mikz
Copy link
Contributor

mikz commented Oct 22, 2018

@mayorova during TLS handshake there is no information about the request method, path or any other HTTP data. It is just the TLS protocol, not HTTP. So the only piece of information available is the hostname through the SNI.

Regarding the context, it makes sense that this context should not be reused for the normal request because it wasn't part of the HTTP protocol. Not sure that is the case now and it is definitely something to verify.

@mayorova
Copy link
Contributor

@mikz Yes, I understand that it's not possible to perform method/path-based matching at the TLS-handshake stage.
But if that's the case we need to:

  1. make it clear in the docs, and at some point when SSL is customizable per-service, this needs to be very clear
  2. exactly what you've said:

it makes sense that this context should not be reused for the normal request because it wasn't part of the HTTP protocol.

I'm also not sure if it's taken into account in this PR :)

@mayorova
Copy link
Contributor

@davidor Can you please have a look at the comments above?

Regarding the context, it makes sense that this context should not be reused for the normal request because it wasn't part of the HTTP protocol. Not sure that is the case now and it is definitely something to verify.

Basically, I think now Path routing might not work correctly with HTTPS (if there are >1 services with the same host).

@nmasse-itix
Copy link
Contributor

Hello,

We can agree that we cannot use Path Routing to find the matching service to find the correct TLS certificate during the TLS negociation.

However, I do not agree that we should disable Path Routing with HTTPS. We can still use the ssl_certificate phase with global policies. That way, the customer can still craft a global policy that fetch the correct certificate and have path routing.

Since finding the correct TLS certificate is quite a standard mechanism, we could also provide the global policy that implement this mechanism :

  1. extract the host from the TLS negociation via the SNI extension
  2. find the first certificate that has a SAN or CN with an exact match
  3. if not found, find the first certificate that has a SAN or CN with wildcard match
  4. if not found, offer a default configured certificate

Certificates can be supplied as a Kubernetes secret and mounted in a well-known or configured folder.

That way, we could also leverage the OpenShift Service Signing Certificates and have a fully automated HTTPS setup on OpenShift.

@mikz
Copy link
Contributor

mikz commented Nov 29, 2018

I imagine that when Path Routing is enabled, then the ssl_certificate phase should be executed for all the service configurations that match the TLS SNI.

@nmasse-itix
Copy link
Contributor

Hi @mikz, @davidor, @mayorova,

I don't want to bother you but I really need to make sure I correctly understood this PR.

The issue was that we were looking for the service by host + path when path routing was enabled and when SSL was enabled we could not find the correct service since we cannot have access to the path at this stage.

I initially understood from both the changelog and the discussions in this PR that the proposed fix was to disable Path Routing when HTTPS was in use.

I tested this PR and it seems that we implemented host-based routing for the ssl_certificate phase but still use the correct service found through the path routing for the later stages.

Can you confirm the former or the later understanding is correct ?

@mikz
Copy link
Contributor

mikz commented Dec 4, 2018

@nmasse-itix you're not bothering. We should've explained it better.

The issue was that there was a crash because we tried to use API that wasn't available in that phase of a request. We could not access the request path.

So the mitigation was to use the same technique as without path routing: just compare the service host against the SNI and pick a first one that matches. That mitigation is applied only to the ssl_certifiate phase.

After the TLS is established it is business as usual and the request path is used to find the correct service.
What it means to a customer is that all the services that share the host should have the same policies that provide a certificate in the ssl_certificate phase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants