sozu-proxy / sozu

Sōzu HTTP reverse proxy, configurable at runtime, fast and safe, built in Rust. It is awesome!
https://www.sozu.io/
GNU Affero General Public License v3.0
3.13k stars 194 forks source link

Client Certificate Authentication #663

Open moschroe opened 3 years ago

moschroe commented 3 years ago

Are there plans to handle client certificates? This might be used to offload/centralise authentication and even take routing decisions. I have mulled it over a bit and came up with the following points:

For handling downstream servers/signalling auth to them, I thought of the following scenarios:

Since sozu currently has an unencrypted connection to the backend anyway, trusting the proxy to set some headers according to DN/CN/whatever does not sound to be a big leap.

Time allowing, I'd be willing to take this on. I have already looked at how the various config messages flow to get the necessary information from one part to the other.

moschroe commented 3 years ago

Also looked into the rustls dependency. Upgrading just one version to 0.17.0 would provide a necessary API change where the ClientCertVerifier does get an Option<&webpki::DNSName> everywhere so usable trust roots could be determined.

Geal commented 3 years ago

that would be interesting. Note that I'm also planning to add encrypted connections to the backend

moschroe commented 3 years ago

I have configuration (from parsing to propagating the value through the application) and verification completed. It is almost a copy of the server cert handling process (from the architectural POV), so optimisations are surely possible.

Now the more interesting problem remains: To enable the modification of headers and making the knowledge of client cert attributes accessible at the right places. And more generally: Inspecting and modifying headers.

Any suggestions architecture-wise?

Geal commented 3 years ago

Since the client certificate will be checked during the handshake, it can be passed to the HTTP implementation in the upgrade() method, then added through the added_request_headers method. For inspecting and replacing headers, you can take a look at the Forwarded header handling.

Could you do this work starting from the 0.12 branch instead of master? New features with breaking API changes aee happening there

Geal commented 3 years ago

The upgrade method: https://github.com/sozu-proxy/sozu/blob/0.12/lib/src/https_rustls/session.rs#L182 Generating headers: https://github.com/sozu-proxy/sozu/blob/0.12/lib/src/protocol/http/mod.rs#L1591 Deleting a known header from the request: https://github.com/sozu-proxy/sozu/blob/0.12/lib/src/protocol/http/parser/mod.rs#L615 (let's do a static header name first, then we'll see to make it configurable)

moschroe commented 3 years ago

So I hacked a preliminary implementation, feel free to check it out: https://github.com/moschroe/sozu/tree/feature_clientauth The history is a complete mess but I tried to provide sensible commit messages, if you look at those last commits it should be clear how I implemented it. I'll clean it up some time this week

Geal commented 3 years ago

ok, I took a look, a few things:

Currently I think that's a lot of code to add, that would benefit from other planned features (like better header edition, pluggable routing, or SNI based routing), so could you wait on this for a bit?

moschroe commented 3 years ago

I have no pressing need for this and will gladly wait for less churn in the codebase :)

moschroe commented 2 years ago

I have resumed development on client TLS auth and the new way to have an SNI-specific server configuration for rustls (see https://github.com/rustls/rustls/issues/859#issuecomment-984714438) involves changing how a ServerConnection is created.

My current plan is to handle this within TlsHandshake as much as possible, so the remaining code can continue to work with a ServerConnection as before.