Reverse proxy configuration with frontend authentication for applications who needs local apache configuration

GOAL

Typical usage is a web application who normally needs an Apache authentication BUT placed behind a reverse proxy who handles itself authentication/authorization

If you need to define REMOTE_USER system variable on a proxied virtual host (backend) :

1° You need first to define a dedicated header on the front-end virtual host (the one which forwards the requests to the backend).
2° You need then to configure the backend virtual host to transform the dedicated header to the REMOTE_USER system variable.

User –>
Front-End : Forward + add custom header –>
Backend : use custom header to create system variable REMOTE_USER

Note this system variable REMOTE_USER can never be modified. It works in this case because it was not defined before on the backend

FRONT END VIRTUAL HOST

<VirtualHost *:443>
    ServerName frontend.onemrva.priv
    <Location />
        AuthName "Application Access"
        AuthType XXXXX (Basic, Digest, Kerberos, ...)
        ...
        Require valid-user
        # ------------------------------
        # Pass headers to backend
        # X-APP-USER = username as you want to be passed to backend (here created from APP_USER variable
        # X-REAL-USER   = original username as authentified in frontend for audit/log
        # ------------------------------
        RequestHeader set X-APP-USER "%{APP_USER}e"
        RequestHeader set X-REAL-USER "%{REMOTE_USER}s"
    </Location>
    # --------------------------------
    # Reverse Proxy to webapp  backend
    # --------------------------------
    SSLProxyEngine On
    SSLProxyVerify none
    SSLProxyCheckPeerCN Off
    SSLProxyCheckPeerName Off
    ProxyPreserveHost On

    ProxyPass / https://127.0.0.1:8443/
    ProxyPassReverse / https://127.0.0.1:8443/

The key instruction is

RequestHeader set X-APP-USER "%{APP_USER}e"

It defines X-APP-USER (which will become REMOTE_USER on backen) from APP_USER variable.

This APP_USER variable should of course be defined somewhere before in the authentication/authorization phase.

Note in this example, the backend server is defined on https://127.0.0.1:8443/ It’s necessary to make it listen on an alternate TCP port (8443 here) if both backend and frontend runs on the same machine

BACKEND VIRTUAL HOST

#Listen only on localhost to restrict access
Listen 127.0.0.1:8443

<VirtualHost 127.0.0.1:8443>
    ServerName webapp.onemrva.priv

    # Define custom log format including X-APP-USERS-USER and X-REAL-USER
    LogFormat "%h %l %u %t \"%r\" %>s %b X-APP-USER:%{X-APP-USER}i X-REAL-USER:%{X-REAL-USER}i REMOTE_USER:%{REMOTE_USER}e" webapp_custom

    # Logs
    ErrorLog logs/webapp-8443-error.log
    CustomLog logs/webapp-8443-access.log webapp_custom

    # Enable SSL
    SSLEngine On
    SSLCertificateFile /etc/pki/tls/certs/webapp.onemrva.priv.crt
    SSLCertificateKeyFile /etc/pki/tls/private/webapp.onemrva.priv.key

    # -----------------------------------------------
    # Set REMOTE_USER from frontend header X-APP-USER
    # -----------------------------------------------
    SetEnvIf X-NAGIOS-USER (.+) REMOTE_USER=$1

    DocumentRoot "/var/www/html/webapp"

    <Directory "/var/www/html/webapp">
        Options None
        AllowOverride All
        Require ip 127.0.0.1
    </Directory>
</VirtualHost>

the key instruction is

SetEnvIf X-NAGIOS-USER (.+) REMOTE_USER=$1


Additional info on this config

  • Localhost on port 8443 (127.0.0.1:8443) is defined for this Vhost on TCP 8443 : listening on another port is necessary when both frontend and backend runs on the same machine
  • LogFormat : Custom log format to displays both “used application username” and “real username as received by the frontend”. In this example it’s called webapp_custom
  • This webapp_custom is used while defining log file location
  • Require ip 127.0.0.1 in <Directory> definition is a second security to be sure it can only be served through the frontend