Support Cloudflare Authenticated Origin Pulls
After adding support for custom certificates in #1531, Could you please consider adding support for Cloudflare’s Authenticated Origin Pulls.
This would allow Kamal deployed applications to restrict access to requests coming only through Cloudflare by verifying the client certificate provided by Cloudflare.
This is particularly important when using Cloudflare WAF, as it prevents attackers from bypassing the WAF and accessing the origin directly.
Cloudflare’s Authenticated Origin Pulls is using mTLS.
This means mTLS support would be needed in kamal-proxy. There is a discussion here about adding it, including a workaround of using another reverse proxy as a kamal accessory in the meantime for mTLS in front of kamal-proxy: https://github.com/basecamp/kamal-proxy/discussions/120
There was also another feature request for that in kamal before: https://github.com/basecamp/kamal/issues/1484
There is support for custom certificates, it would be nice if in a similar manner a trusted_certificate_pem for mTLS could be configured. In the case of Cloudflare Authenticated Origin Pulls this would then be the Cloudflare hostname client certificate.
# config could look like this:
ssl:
certificate_pem: CERTIFICATE_PEM # exists
private_key_pem: PRIVATE_KEY_PEM # exists
trusted_certificate_pem: TRUSTED_CERTIFCATE_PEM # new
verify_client: on # allow: on | off | optional | optional_no_ca
Naming similar to e.g. nginx config naming for mTLS, note also the options for different mTLS levels verify_client. The escaped client certificate would usually then be sent upstream from the proxy in an HTTP header like ssl-client-cert.
A low hanging fruit would be to add security header check first, so that in the absence of the header the proxy would return 404 (same as with invalid host). Then in Cloudflare we can just add the header to all requests to authenticate them.
A low hanging fruit would be to add security header check first, so that in the absence of the header the proxy would return 404 (same as with invalid host). Then in Cloudflare we can just add the header to all requests to authenticate them.
Such a HTTP header check is already possible to do in the application itself, as HTTP headers are just forwarded, so not necessarily needed to be done by kamal-proxy.
However in the case of mTLS however the TLS connection is terminated by kamal-proxy, and thus this cannot be added just in the application and is a feature that is only possible in the component that terminates the TLS connection.
Such a HTTP header check is already possible to do in the application itself
We want to pretend the host is not served by the server, unless it's a Cloudflare request. When you get a request for unknown host normally the client receives "not found" response from the proxy itself. Your suggestion won't work, because the mere fact of the app responding "I'm not here" discloses the existence of the host.
Such a HTTP header check is already possible to do in the application itself
We want to pretend the host is not served by the server, unless it's a Cloudflare request. When you get a request for unknown host normally the client receives "not found" response from the proxy itself. Your suggestion won't work, because the mere fact of the app responding "I'm not here" discloses the existence of the host.
If you really want to go down this path of "hiding" then you can just imitate a common HTTP 404 response from your application and make it look exactly like some common proxies would respond. In the end it is still just a HTTP response that you can fully define, if you generate that from the proxy or the application does not make a difference and can look exactly the same. The existence of the host is already disclosed by answering in the TCP handshake and then in the TLS handshake.
In the mTLS case, instead of "hiding", the TLS handshake would already be terminated if the client certificate is not trusted, thus providing real authentication.
I don't think "imitating" proxy responses is a good idea at all. You would have to make both the content and the headers match, which would be very fragile and risky. There's no need to build anything like this when we can have this feature in the proxy.