-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Passing auth result (client identity) to backend #794
Comments
@myidpt I'm not sure that this an Envoy specific question exactly. It seems like you need to write a filter to set some header based on some parameters of the client connection. Unless you are asking to specify some format that we would perform automatically for all requests? Can you expand please? |
I think it would be good to automatically set the client identity for all requests that did mTLS. But it also works for us if we use a filter to achieve the goal. |
I'm open to setting a header by default, but:
Can you propose something? |
@lookuptable @lizan @wlu2016 |
|
Thinking more about this, does it make more sense for us to have our own filter to do header injection? This allows us to do Istio specific sanitization (e.g. ignore non-URI identities in the |
I am skeptical that we are going to find a common header to fit this use case, and will probably need to make one up like the other x-envoy headers. However, since you already have your mixer filter, you could probably just do it there if you want specific functionality. |
we should give this a more generic name, x-service-account will be better than x-istio-service-account. We should also consider a consistent story passing other auth info to the backend like email address, group, issuer, etc. We have been using jwt token or json object to convey these info in the past. Since this is not an urgent feature, lets prepare a design to cover all these scenarios first. |
I think there is utility in making this generic to Envoy. In advanced deployments having an edge proxy forward details about the TLS negotiation to backends can be useful x-forwarded-proto is an example of doing this but it doesn't help with mutual auth. Theres some doc with HAProxy which is still pretty generic but it doesn't cover SANs and I wouldn't suggest we adopt their nomenclature. I think x-forwarded-client-cert-**** fits better with whats already present. If Envoy was going to pick up generic header rewriting capabilities then I think we could use that. Don't think we need to use x-envoy given that there's already a rough convention for x-forwarded-*. @htuch - thoughts? |
One issue to think about if we add fixed support into Envoy is how we handle multi-level proxying. XFF gets appended as you go, so you would have to be able to do something similar with the client cert info and make sure you keep all headers in sync (e.g. every proxy would have to insert all headers). By generic header rewriting capabilities are you talking about something like https://support.citrix.com/article/CTX114461 (but obviously in the Envoy config and some way of getting at Envoy internal fields like the SSL cert name by label)? BTW, looks like XFF and friends are now in the |
I think side-car proxies might be the exception to XFF appending rules, there's not much use to the extra appending if the proxy is logically part of the receiving application. Beyond that I think appending is the desired behavior though it clearly becomes tricky when were talking about appending details about things which are auth related. There is potential for the ultimate receiver to have confusion unless we're careful about the details. Maybe instead of separate headers for parts of the cert we have just one header and a format inside it? E.g. X-Forwarded-Client-Cert: name=X; SAN=A; SAN=B; hash=1fd445e2 and then folks get to configure which of the fields in that format are filled out. This would allow normal header concatenation rules to apply while keeping the correlation with hops clear. |
Envoy isn't just used as a side-car though, so we need to support a number of different topologies, including classical multi-level proxies. I like the idea of combining into a single XFCC. If I understand your proposal correctly, there is an extensible list of key/values for the client cert which are semi-colon separated, and then each level of proxy is able to either append a header or use a comma separator (per RFC 7230) to add additional cert info. It will also be necessary for the "frontline" Envoy instance to be configured to scrub, rather than append to, the XFCC header. |
Thanks @louiscryan and @htuch. I think according to https://tools.ietf.org/html/rfc7230#section-3.2.2, we should always concatenate the info of additional certs to the end of the XFCC field, separated by comma. When conveying the authentication results such as cert info, we need to think about the security risks. What if a non-frontline Envoy instance receives traffic from a malicious user, and that user injects fake auth results into XFCC? Maybe to prevent this, we should only trust the XFCC from clients that is authenticated through mTLS. Otherwise, the client XFCC header should be scrubbed. |
We should apply the same scrubbing that we use for other "trusted" headers already. If we do that, we won't have any issues. |
What would be the practical use for multiple XFCC values? Even with tiered proxies and service mesh, backend is only interested in the client's SSL certificate and not that of middle proxies that handled the traffic. IMHO, we should create XF* headers only at the "frontline". |
This is mostly just future proofing. It's probably fine to just do XFCC for frontline in a typical service mesh or Envoy deployment today. Maybe one day some backend wants to verify the certs used by intermediary proxies are all of a certain vintage or provenance in some very large deployment. I think it makes sense though to think about how this could be extended if we're defining an implicit standard here and not box ourselves in if an Envoy configuration wants this one day, all things being equal. Earlier design iterations would imply only frontline XF* ever. We can just implement it for frontline today. |
I agree with htuch@. Maybe micro-services need to control quota, do logging or even authz based on the intermediary services? For example:
|
Please keep in mind that the biggest issue with XF* headers (and the reason behind It's a security nightmare, unless you control the whole perimeter. IMHO, we should consider using |
I don't have a strong preference on whether to make up a new header called XFCC or to use Forwarded, but I agree we should optionally support append like we currently do for XFF. For reference, the current trusting/scrubbing behavior in the HTTP connection manager is controlled by the "use_remote_address" option and is used here: I would suggest that we expand this into an enum of various scrub/append/set settings as per @myidpt depending on what we need. Once the remote address is determined, Envoy then decides whether a request is internal or external, and then does additional scrubbing if external. Note that the internal vs. external logic is currently fairly simplistic (what was needed for Lyft) and may need to be expanded a bit with options depending on other use cases. |
@PiotrSikora (Please correct me if I'm wrong) So as I understand, the advantage of using So we can add To me, XFCC makes sense only when it is conveyed through mTLS. I'm not sure if it makes sense for non-mTLS connections because if the receiver never authenticates the sender, how can it trust the auth result header? So I suggest that the receiver only trusts the XFCC header sent through mTLS connections. (PS: just to think aloud, if we want to trust each chunk of XFCC header (each part separated by comma) through non-mTLS connections, maybe each XFCC chunk can contain a special value And I think the proxy should be able to be configured with the 4 options I mentioned. It's orthogonal to the security concern, right? |
Folks, just chiming in here with a use case as this sounds like a feature we also need for a couple of systems. Specifically what we would like is, when receiving a mTLS request, have the ability to extract the CN, the DN and, less importantly, the SANs on the inbound client certificate, and then remap them onto a header that is propagated to the downstream cluster. Personally I don't much care if its It might also be worth considering what nginx does here [1], as its pretty extensive how they break apart the myriad of things available in the client certificate. Does anyone need all that? It's not clear - perhaps a subset would be enough. [1] http://nginx.org/en/docs/http/ngx_http_ssl_module.html#var_ssl_client_verify |
@myidpt @PiotrSikora how should we move the ball forward on this one? The actual implementation here is not difficult. We just need to decide on which header to use and the various semantics. Can the two of you do a final proposal and we can get some +1s on it and then implement? |
@PiotrSikora as I haven't heard from you, please comment on the following proposal: For the security nature of the client cert info, I think it is better to choose the dedicated header (XFCC) for forwarding auth result, so that it is decoupled from other forwarded info, thus can be controlled more strictly. XFCC format Envoy implementation
The default value is "sanitize". Added according to feedback Envoy config will also have a "set_current_client_cert_details" field in HTTP connection manager. Now it supports values: TODO: Add a key in the XFCC element and configuration to enforce security based on the identity of the CA (client cert issuer). |
@myidpt +1 from me. @timperrett can you look at ^. @louiscryan @htuch @PiotrSikora ? |
+1 from me with a few suggestions
w.r.t to the modes I wonder if we need all this control. forward_only seems odd as it would omit a locally used credential while forwarding a remote certs details. I wonder if it's useful for Envoy instead to always append a marker value if no cert was present on the local hop even if a cert was used on a downstream hop. E.g X-Forwarded-Client-Cert: SAN=....; none; none would imply that the two most immediate proxy hops did not use a client cert |
|
@PiotrSikora what do you mean exactly? We do implicitly have this support today via the poorly named "use_remote_address" field, and in fact we implement trusted downstreams with Envoy in Lyft today via mTLS for our POP edge proxies. In this case, we trust the downtream proxy to have correctly set XFF, etc. |
@mattklein123 ah, sorry, I've missed that... but unless I'm misreading it, listener either trusts all accepted connections or none of them, correct? |
@louiscryan
|
|
@myidpt SPKI value doesn't change when certs are rotated (at least, it shouldn't). |
@PiotrSikora |
@myidpt that, I don't know... It might not... But |
Yes, basically. How else could it work though? As @myidpt points out it really needs mTLS to be trusted. The current implementation doesn't enforce that, and IMO I don't think we should make that required since people have different types of deployments. I would rather get rid of "use_remote_address" and make it much more explicit what is done with XFF, etc. like we are discussing here for XFCC. I just put a note on the v2 API about this cc @htuch |
@PiotrSikora |
@PiotrSikora I think this can be useful for enforcing strong security, and we can consider it as a TODO. I think the implementation may not be very trivial here, such as how to configure passing the public key of which CA (there can be multiple CAs in the certificate chain), and how to get the public key of the CA and pass it to the HTTP connection manager. |
@myidpt @louiscryan @PiotrSikora I think we are pretty much converged here in terms of control options. As long as we have the ability to specify what fields get populated in XFCC we can always add more fields later. So I the only remaining question is whether to use XFCC or Forwarded as the header name? Can we resolve that today? I don't personally care that much, though I think I would vote for XFCC just to be very explicit about what we are doing. |
I vote for The basic idea is to decouple the security-related headers from the non-security headers, so that special rules can be applied to them. Because we introduce |
@louiscryan @PiotrSikora @mattklein123 @htuch |
@myidpt this looks good for the most part. One question: what's the rational for choosing the CN or the SAN(s)? I'm guessing the working assumption is that the latter is a superset of the former? Is that part of the spec? Whilst I don't think it would break our usage, just want to make sure we're making a valid assumption, as im not sure there is any requirement from a cert perspective for SANs to be a super set including the CN. |
I am fine with proceeding with XFCC, we can always support config to use Forwarded later if/when it gets some traction. |
@timperrett |
@myidpt OK. I think we are closed on the design here. Feel free to implement. Looking forward to landing this! :) |
Cool, thanks everyone! I will start implementing it :) |
@myidpt just so i'm not polling and annoying you, what's a rough ETA for this feature? Many thanks in advance! |
@timperrett |
@myidpt any news on this good sir? |
Working on implementing integration tests. Will send the PR out today or tomorrow. |
When mTLS is enabled, Sever side Envoy needs to send the client identity to the backend through HTTP header, so that backend can do its own check/processing based on the client identity.
Questions:
What HTTP header do we use?
How do we support this for non-HTTP requests (This is a stretch goal)?
The text was updated successfully, but these errors were encountered: