1. The problem I’m having:
Hello,
I’m trying to reverse proxy to an internal application that we can’t adjust because we no longer have the source code but I’d like to make it “more secure”.
I ran an sslscan against this internal admin application and got a list of supported ciphers:
PORT STATE SERVICE
443/tcp open https
| ssl-enum-ciphers:
| TLSv1.2:
| ciphers:
| TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
| TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
| TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
| compressors:
| NULL
| cipher preference: server
| warnings:
| Forward Secrecy not supported by any cipher
|_ least strength: A
In addition this service is configured with a certificate that has a fair few years left on it, but no longer accurate for the DNS record routing to the service, so using tls_insecure_skip_verify. I have no capabilities to change this TLS configuration, ciphers nor common name so trying to use caddy to front it.
When I configure this upstream as a reverse_proxy target in caddy I get a handshake failure as seen in the log below:
2. Error messages and/or full log output:
2024/12/08 19:43:01.012 DEBUG tls.handshake default certificate selection results {"identifier": "localhost", "subjects": ["localhost"], "managed": true, "issuer_key": "local", "hash": "c1d216bb54aa7e632da630b0921dc5ebc7f3a0c577da261791e5901c32b9442b"}
2024/12/08 19:43:01.012 DEBUG tls.handshake matched certificate in cache {"remote_ip": "::1", "remote_port": "33260", "subjects": ["localhost"], "managed": true, "expiration": "2024/12/09 07:42:56.000", "hash": "c1d216bb54aa7e632da630b0921dc5ebc7f3a0c577da261791e5901c32b9442b"}
2024/12/08 19:43:01.017 DEBUG http.handlers.reverse_proxy selected upstream {"dial": "admin.localdomain:443", "total_upstreams": 1}
2024/12/08 19:43:01.022 DEBUG http.handlers.reverse_proxy upstream roundtrip {"upstream": "admin.localdomain:443", "duration": 0.005285108, "request": {"remote_ip": "::1", "remote_port": "33260", "client_ip": "::1", "proto": "HTTP/2.0", "method": "GET", "host": "localhost", "uri": "/", "headers": {"Accept": ["*/*"], "X-Forwarded-For": ["::1"], "X-Forwarded-Proto": ["https"], "X-Forwarded-Host": ["localhost"], "User-Agent": ["curl/8.5.0"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "localhost"}}, "error": "remote error: tls: handshake failure"}
2024/12/08 19:43:01.022 ERROR http.log.error remote error: tls: handshake failure {"request": {"remote_ip": "::1", "remote_port": "33260", "client_ip": "::1", "proto": "HTTP/2.0", "method": "GET", "host": "localhost", "uri": "/", "headers": {"User-Agent": ["curl/8.5.0"], "Accept": ["*/*"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "server_name": "localhost"}}, "duration": 0.005529867, "status": 502, "err_id": "kcjc1kqit", "err_trace": "reverseproxy.statusError (reverseproxy.go:1269)"}
I am guessing it’s a cipher mismatch but I can’t be sure!
3. Caddy version:
Caddy 2.8.4
4. How I installed and ran Caddy:
Official Docker image (caddy:2.8.4)
a. System environment:
Docker
b. Command:
docker run --rm --network=host docker:2.8.4
c. Service/unit/compose file:
n/a
d. My complete Caddy config:
{
log {
output stderr
level DEBUG
format console
}
}
localhost:443 {
tls internal
reverse_proxy https://admin.localdomain {
transport http {
tls_insecure_skip_verify
}
header_up Host admin.localdomain
}
}
5. Links to relevant resources:
tcpdump/wireshark view of the TLS ClientHello initiated by Caddy when a request lands on the frontend via curl.