[TUTORIAL] Using a reverse proxy to limit PBS exposition to API endpoints only

meyergru

Well-Known Member
Jan 28, 2023
243
145
48
www.congenio.de
It always bugged me that when there is no possibility of having a VPN to a remote PBS server, you will have to expose the web UI as a whole.

I even did a feature request to create an "API-only" frontend to PBS to limit the attack surface, see: https://bugzilla.proxmox.com/show_bug.cgi?id=7010

I have this running for a while now. I found that neither Caddy nor Nginx were really suitable, because they lack one critical feature that HAproxy has, namely: "option http-server-close".

If you do not have that option, the setup works partially, but on the server side, you will get log entries with "TASK ERROR: connection error: not connected". That does not happen with HAproxy.

You only need to install HAproxy on PBS via "apt install haproxy" and then create /etc/haproxy.cfg like so:

Code:
global
        maxconn 5000
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin
        stats timeout 30s
        user haproxy
        group haproxy
        daemon
        nbthread 6
#       hard-stop-after 15m
        tune.ssl.default-dh-param 4096
        nokqueue

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # See: [URL]https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate[/URL]
        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-CDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

# Parameter
    timeout client  3600s
    timeout server  3600s


# PBS proxy
frontend pbs_tcp
    bind :::18007 name :::18007 ssl crt /etc/haproxy/proxy.pem verify none
    mode http
    option httplog
    option http-server-close
    option forwardfor
    acl https ssl_fc
    http-request set-header X-Forwarded-Proto http if !https
    http-request set-header X-Forwarded-Proto https if https
#   timeout client 30000

    # Probe direkt beantworten
    acl path_probe path_beg /probe
    http-request return status 200 content-type "text/plain" string "alive" if path_probe

    # Nur /api2 Requests an Backend weiterleiten
    acl path_api2 path_beg /api2 //api2
    use_backend pbs_backend if path_api2

    # Alle anderen Requests ablehnen
    http-request return status 500 unless path_api2 or path_probe


backend pbs_backend
    mode http
    server      pbs 127.0.0.1:8007 ssl verify none

Of course you will have to copy your existing PBS cert via "cat /etc/proxmox-backup/proxy.{pem,key} >/etc/haproxy/proxy.pem", because HAproxy likes the cert and the key in one file.

This will allow only /api2, //api2 and /probe for monitoring purposes on a different port (18007). Any other path will result in an HTTP 500 error.

AFAIK, the API does not allow for any other authorisation type than tokens, so no usernames can be probed and even fingerprinting is limited to the bare minimum should the port be detected.
 
Last edited:
  • Like
Reactions: Johannes S