Can I use Squid to upgrade client TLS connections? - ssl

I'm trying to allow legacy systems (CentOS 5.x) to continue making connections to services which will shortly allow only TLS v1.1 or TLS v1.2 connections (Salesforce, various payment gateways, etc.)
I have installed Squid 3.5 on a Centos 7 server in a docker container, and am trying to configure squid to bump the SSL connections. My thought was that since squid acts as a MITM and opens one connection to the client and one to the target server that it would negotiate a TLS 1.2 connection to the target, while the client was connecting with SSLv3 or TLS 1.0.
Am I totally off-base here, or is this something that should be possible? If Squid can't do this, are there other proxies which can?
My current squid configuration looks like this:
access_log /var/log/squid/access.log
cache_log /var/log/squid/cache.log
cache_store_log none
cache deny all
http_access allow all
http_port 3128 ssl-bump cert=/etc/squid/ssl_cert/myCA.pem generate-host-certificates=on version=1
ssl_bump stare all
ssl_bump bump all

I was able to get this working by only bumping at step1, and not peeking or staring. The final configuration that I used (with comments) is below:
sslcrtd_program /usr/lib64/squid/ssl_crtd -s /var/lib/ssl_db -M 4MB
# Write access and cache logs to disk immediately using the stdio module.
access_log stdio:/var/log/squid/access.log
cache_log /var/log/squid/cache.log
# Define ACLs related to ssl-bump steps.
acl step1 at_step SslBump1
acl step2 at_step SslBump2
acl step3 at_step SslBump3
# The purpose of this instance is not to cache, so disable that.
cache_store_log none
cache deny all
# Set up http_port configuration. All clients will be explicitly specifying
# use of this proxy instance, so https_port interception is not needed.
http_access allow all
http_port 3128 ssl-bump cert=/etc/squid/certs/squid.pem \
generate-host-certificates=on version=1
# Bump immediately at step 1. Peeking or staring at steps one or two will cause
# part or all of the TLS HELLO message to be duplicated from the client to the
# server; this includes the TLS version in use, and the purpose of this proxy
# is to upgrade TLS connections.
ssl_bump bump step1 all

Related

Is there a way to use a forwarding proxy as a backend (including authentication) in HAProxy?

I am quite new to HAProxy and want to achieve the following setup / packet flow:
Client -> HAProxy (as reverse proxy) -> Forwarding Proxy (HAProxy, IIS, Squid...) -> Internet -> server.example.com
I would like to have encrypted connections with TLS/SSL from the Client -> HAProxy and from HAProxy -> server.example.com
This means, that the forwarding proxy needs to support the HTTP CONNECT method, to establish a TCP tunnel and transmits packets without trying to interpret them. Over this TCP port I should be able to send bytes to server.example.com - TLS/SSL encrypted, so HTTPS.
Furthermore it could be, that authentication against the forwarding proxy is needed e.g. HTTP Basic authentication.
The software stack of my test setup is as follows:
Client Firefox 76.0.1
HA-Proxy version 1.6.3 2015/12/25
Squid Cache: Version 3.5.27
I have setup this HAProxy configuration:
global
# Standard settings
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
user haproxy
group haproxy
daemon
# Tuning
maxconn 2000
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
ssl-default-bind-options no-sslv3
# Ensure a secure enough DH paramset
tune.ssl.default-dh-param 2048
defaults
log global
mode http
option httplog
option dontlognull
# Redispatch 503 errors on backends, reducing the number of 503 reaching clients
option redispatch
# We want to stall clients for as long as possible, before giving
# up with 503:
timeout connect 5m
# Clients must be acceptably responsive
timeout client 1m
# Server not as much...
timeout server 5m
# HTTPS server
frontend https-in
bind :443 ssl crt-ignore-err all crt /etc/haproxy/ssl/certkey.pem
# Don't serve HTTP directly, but redirect to same URL in https
redirect scheme https code 301 if !{ ssl_fc }
default_backend backend-proxy
backend backend-proxy
# Create the Authorization / Proxy-Authorization header value
# echo -n "user:password" | base64
http-request add-header Proxy-Authorization "Basic dXNlcjpwYXNzd29yZA=="
# We need to use the CONNECT method
http-request set-method CONNECT
# The proxyserver needs to know the full server name
http-request set-path server.example.com:443
server proxy 192.168.1.1:8080
In my test setup I use a Squid server as a forwarding proxy with the following configuration:
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 443 # https
acl CONNECT method CONNECT
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localhost manager
http_access deny manager
http_access allow localhost
auth_param basic program /usr/lib/squid3/basic_ncsa_auth /etc/squid/squid-passwd
acl basic_client proxy_auth REQUIRED
http_access deny !basic_client
http_access allow basic_client
http_access deny all
http_port 8080
coredump_dir /var/spool/squid
Using the Squid forwarding proxy in a regular browser on the same subnet including authentication works fine.
So when the first request comes in from the Client at the HAProxy it gets forwarded via the backend backend-proxy to the Forward Proxy (Squid). The CONNECT succeeds, as I see in the Squid log.
1591166403.966 60146 192.168.1.10 TCP_TUNNEL/200 39 CONNECT server.example.com:443 test HIER_DIRECT/6.7.8.9 -
(IP addresses were replaced with generic values)
The HAProxy log shows, that the correct backend is used:
Jun 3 08:39:57 localhost haproxy[3547]: 192.168.1.20:39398 [03/Jun/2020:08:38:56.855] https-in~ backend-proxy/proxy 154/0/13/209/60375 200 39 - - ---- 0/0/0/0/0 0/0 "GET /someurl HTTP/1.1"
(IP addresses were replaced with generic values)
So far so good. But I am unable to establish a successful communication to server.example.com from my Client. I think I have to use a second/other backend, which will not mangle the requests any more (exchange method and path) but instead use the given TCP port from the forwarding proxy to transmit the request.
How can I save the 'state' of the communication to my backend / proxy server in HAProxy, so the request could be resend to another backend?
How to extract and use the TCP port from the response of the Forwarding Proxy?
Is there a way to check, if the TCP tunnel on the Forwarding Proxy is still opened or do I need to request it using CONNECT every time before I want to use it?
EDIT:
I solved the situation by using stunnel as an intermediary to handle the TCP tunnel creation with CONNECT against the Forwarding Proxy.
If you have an upstream HTTP proxy (like squid) (not a socks proxy) and you want to have haproxy accept connections and open the tunnel thru the upstream proxy (such that the haproxy clients do not support doing so themselves via http/CONNECT method) on behalf of the clients, then this functionality does not exist in haproxy today.
I crated a branch that does this via server keyword proxy-tunnel.
The below example config will behave such that clients of haproxy that connect to port 20025 (haproxy) will result in haproxy establishing a http/CONNECT tunnel via the upstream proxy 172.16.0.99:50443 to 172.16.0.2:2023:
listen SMTP-20025
bind 0.0.0.0:20025
server TEST_SERVERVIA_PROXY 172.16.0.2:2023 proxy-tunnel 172.16.0.99:50443

HAProxy with SSL passthrough to multiple domains with multiple backends

I need to setup a load balancer for all our applications.
At the moment all our applications are clustered (2-node appservers, and 1 apache on each node as well) and we do not have a LB so we just point our DNS alias to the first webserver of each node, making the second node useless (have to manually do a DNS switch in case of a failure of node1, and we don't have load balanced https queries).
Each application uses SSL with a specific domain & SSL certificate. we cannot accept to decrypt SSL and send unencrypted traffic to the backends as the LB might be located in another country etc. so we need to use passthrough.
Before anything, i just wanted to know if this is actually possible in HAProxy or not ?
I am talking about ~50 different applications. Our LB configuration would have to be HA so i guess we'll use something like keepalived with a shared VIP for HAProxy itself.
The setup would look like this i suppose :
domain-a.com-' '-> backend_dom_a -> 1.1.1.1 (app node1 dom a)
| | 1.1.1.2 (app node2 dom a)
domain-b.com-' '-> backend_dom_b -> 2.1.1.1 (app node1 dom b)
| | 2.1.1.2 (app node2 dom b)
domain-c.com-' '-> backend_dom_c -> 3.1.1.1 (app node1 dom c)
| | 3.1.1.2 (app node2 dom c)
domain-N.com-' '-> backend_dom_N -> 4.1.1.1 (app node1 dom N)
| | 4.1.1.2 (app node2 dom N)
+-> haproxy -+
Thanks for your support, best regards
FYI i'm using this configuration that works like a charm.
i have replaced the values in the files to hide our domains & hostnames, and limited the numbers of urls/backends but we have about 50 running now with the load balancer forwarding requests to many apache servers (and each apache forwards requests to tomcat servers behind)
feel free if you have any question
we use balance source to ensure session stickyness
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
daemon
user haproxy
group haproxy
log /dev/log local6 notice
log /dev/log local5 info
maxconn 50000
#chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
mode tcp
option tcplog
log global
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
#---------------------------------------------------------------------
# dedicated stats page
#---------------------------------------------------------------------
listen stats
mode http
bind :22222
stats enable
stats uri /haproxy?stats
stats realm Haproxy\ Statistics
stats auth <mylogin>:<mypass>
stats refresh 30s
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend main_https_listen
bind <ip address>:443
mode tcp
option tcplog
log global
tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
#---------------------------------------------------------------------
# Common HAProxy nodes configuration
#---------------------------------------------------------------------
# -------------------------------
# ACLs
# -------------------------------
acl acl_SIT_AT35073 req.ssl_sni -i <app_url1>.my.domain.net # SIT_AT35073 is just an internal code we use, but you can use any alias
acl acl_SIT_AT34305 req.ssl_sni -i <app_url2>.my.domain.net
acl acl_SIT_AT28548 req.ssl_sni -i <app_urlN>.my.domain.net
# -------------------------------
# Conditions
# -------------------------------
use_backend backend_SIT_AT35073 if acl_SIT_AT35073 # same here
use_backend backend_SIT_AT34305 if acl_SIT_AT34305
use_backend backend_SIT_AT28548 if acl_SIT_AT28548
#---------------------------------------------------------------------
# Backends
#---------------------------------------------------------------------
# APP 1
backend backend_SIT_AT35073
description APPNAME1
mode tcp
balance source
option ssl-hello-chk
server server_SIT_AT35073_1 <apache_server1>.my.domain.net:443 check
server server_SIT_AT35073_2 <apache_server2>.my.domain.net:443 check
# APP 2
backend backend_SIT_AT34305
description APPNAME2
mode tcp
balance source
option ssl-hello-chk
server server_SIT_AT34305_1 <apache_server3>.my.domain.net:443 check
server server_SIT_AT34305_2 <apache_server4>.my.domain.net:443 check
# APP N
backend backend_SIT_AT28548
description APPNAMEN
mode tcp
balance source
option ssl-hello-chk
server server_SIT_AT28548_1 <apache_server5>.my.domain.net:443 check
server server_SIT_AT28548_2 <apache_server6>.my.domain.net:443 check
I think you have two options:
pass the traffic through to the backend by using the TCP mode in haproxy frontend and backend. This has the benefit that your backend SSL certificate is passed through. Though you lose the possibility to have one SSL termination in your site. So I present you
Have one (usual) SSL certificate, acting as termination for your site and enable SSL between your backend and haproxy instance. This gives you the advantage that you still have only one entry point but different backends with unique certificates.
The second option might look like this:
frontend f_foo
bind :443 ssl crt /path/to/bundle
mode http
log global
use_backend b2_foo
backend be_foo
mode http
timeout connect 5s
server FOO address:port ssl check crt /path/to/client/bundle force-tlsv10 verify none
The drawback is that you need a client certificate for each backend server but that should be easily automatable.
AS more of an update answer for multi domain configs I use the below for routing different domains.
in the frontend is where you bind the port and add the certs which multiple have to be on the same line afaik.
frontend https_in
bind *:443 ssl crt /link/to/cert+key-file.pem crt /link/to/cert+key-file.pem
The acl host is where you specify the domain name and which backend to use based on that domain name.
acl host_example.com hdr(host) -i example.com
use_backend BACKEND_NAME if host_example.com
The backend where you specify the server that domain is running on.
backend BACKEND_NAME
mode http
option httpclose
option forwardfor
cookie JSESSIONID prefix
server server-name server-ip:443 check ssl verify none

Realm Object Server - SSL configuration causes ROS to fail start

Ubuntu 16.04 / ROS v1.3.0
I am attempting to configure my ROS to use secure SSL connections.
If I do not make any changes to the configuration.yml - ROS is fine. I can sync and use the dashboard as I would expect.
I have obtained an SSL cert from Letsencrypt. I used the CertBot in standalone mode so that I did not have to install or configure Nginx. (My preference is to not install yet another tech/layer - keep it clean!)
I have the following certificates/key stored in this folder:
/etc/letsencrypt/live/data.mydomain.net/cert.pem
/etc/letsencrypt/live/data.mydomain.net/chain.pem
/etc/letsencrypt/live/data.mydomain.net/fullchain.pem
/etc/letsencrypt/live/data.mydomain.net/privkey.pem
As soon as I enable HTTPS in the configuration.yml I am unable to launch ROS.
There are no error messages written to:
/var/log/realm-object-server.log
Here is a copy of the proxy section of configuration.yml.
http:
## Whether or not to enable the HTTP proxy module. It enables multiplexing requests
## by forwarding incoming requests on a single port to all services.
# enable: true
## The address/interface on which the HTTP proxy module should listen. This defaults
## to 127.0.0.1. If you wish to listen on all available interfaces,
## uncomment the following line.
# listen_address: '::'
## The port that the HTTP proxy module should bind to.
# listen_port: 9080
https:
## Whether or not to enable the HTTPS proxy module. It enables multiplexing requests
## by forwarding incoming requests on a single port to all services.
## Note that even if it enabled, the HTTPS proxy will only start if supplied
## with a valid pair of certificates through certificate_path and private_key_path below.
enable: true
## The path to the certificate and private keys (in PEM format) that will be used
## to set up the HTTPS server accepting connections.
## These configuration options are MANDATORY to start the HTTPS proxy module.
certificate_path: '/etc/letsencrypt/live/data.mydomain.net/fullchain.pem'
private_key_path: '/etc/letsencrypt/live/data.mydomain.net/privkey.pem'
## The address/interface on which the HTTPS proxy module should listen. This defaults
## to 127.0.0.1. If you wish to listen on all available interfaces,
## uncomment the following line.
# listen_address: '::'
## The port that the HTTPS proxy module should bind to.
listen_port: 9443
As I mention. The issue appears to be that as soon as I configure HTTPS the ROS server fails to start. If I disable the HTTPS then the ROS server starts without issue.
The reason I believe ROS is failing to start is - if I attempt curl 127.0.0.1:9080 or curl 127.0.0.1:9443 from the terminal I get the message curl: (7) Failed to connect to 127.0.0.1 port 9443: Connection refused
I'd love to hear your ideas/thoughts/suggestions on how I can get this to work. Cheers. Ian
Thanks to user #Radu - the answer was Permissions.
The realm user did not have permission to read the .pem files.
I picked up the answer from this answer.
Https Proxy for Realm Object Server not working
#Radu - is the man!

squid sslbump works with private connection warning

I use squid 3.5 with its sslbump feature for https traffic filtering. I generated my private key and cert files with openssl. However,the browser received the warning message when i open https websites that the certificate was issued by an unknown authority. I created ssl certificates with comodo but i still got the same warning message.
Is there a way to remove this warning?
# Squid normally listens to port 3128
http_port 3128 ssl-bump cert=/var/tmp/example.com.cert key=/var/tmp/example.com.private
# Squid listen Port
cert=/var/tmp/example.com.cert
# SSL Bump Config
always_direct allow all
ssl_bump server-first all
url_rewrite_program /usr/bin/sh /var/tmp/middle_squid_wrapper.sh start -C /var/tmp/middle_squid_config.rb
# required to fix HTTPS sites (if SslBump is enabled)
acl fix_ssl_rewrite method GET
acl fix_ssl_rewrite method POST
url_rewrite_access allow fix_ssl_rewrite
url_rewrite_access deny all
You don't say what client OS you are using, but it sounds very much like you didn't import your squid certificate to the correct certificate store on the client.
When you install the certificate on a Windows client it should be imported into the Trusted Root Certificate Authorities'->'certificates folder.
The client should then trust the certificate.

How to setup SSL bumping for content adaptation

I need to setup a reverse proxy which intercepts HTTPS requests, decrypts them, performs body adaptation and finally forwards the re-encrypted request.
I'm now using Squid which provides support for eCAP plugins and ssl bumping: http://wiki.squid-cache.org/Features/SslBump
If I understood well, by configuring SSL bumping I can do exactly what I said above. However, ssl bumping is not working for now.
Here is my Squid configuration:
https_port 8080 cert=/etc/squid/cert.pem key=/etc/squid/key.pem
http_port 3128 ssl-bump cert=/etc/squid/cert.pem key=/etc/squid/key.pem dynamic_cert_mem_cache_size=4MB generate-host-certificates=on
cache_peer 52.170.25.214 parent 8080 0 no-query originserver login=PASS
#always_direct allow all
ssl_bump allow all
sslproxy_cert_error allow all
sslproxy_flags DONT_VERIFY_PEER
Client-side, when trying to send a request to https:// 127.0.0.1:8080 I'm getting the following error:
Connection reset by peer
This happens if the destination server is running HTTPS. Looks like Squid is trying to establish a simple HTTP connection instead of a HTTPS request. Indeed, server-side I'm getting a SSL23_GET_CLIENT_HELLO error.
Is there anything wrong in my configuration? Is there anything I missed in how SSL bump works?
I digged into the problem and here is what I found:
1) ssl-bump option is not needed
2) the problem was that in the following line the ssl option was missing
cache_peer 52.170.25.214 parent 8080 0 no-query originserver login=PASS **ssl**