Skip to content

Apache Proxy Authorization with HTTPS, Basic Auth, and ProxyPass

Pliable Pixels edited this page May 10, 2018 · 13 revisions

Author: Adam Outler

In order to provide the highest levels of security while working around software limitations with project frameworks, a few steps are required. This guide will provide a reference for establishing all common security mechanisms to operate with zmNinja.

Overview

This is a chained process. You must hit every step in this guide. Start with fresh files and don't try to reuse something you've already made. This is laid out simply.

This guide will set up the following:

  1. Redirect HTTP to HTTPS.
  2. Set up a proxy to use HTTPS encryption and convert basicauth Query String tokens from zmNinja into actionable Basic Authentication.
  3. Set up a proxy to enable Basic Auth with zmNinja.
  4. Set up hosts file to redirect the locally.
  5. Enable zmNinja to connect.

This guide expects you have

  • Apache set up and running ([apt, yum, snap, pacman, emerge, port] install apache2) on your proxy server
  • an externally accessible server, which will be referred to as MYEXTERNALSERVERDOTCOM
  • an email address, referred to as MYEMAIL
  • The IP address of your zoneminder as accessed by your proxy, referred to as LOCALZONEMINDERIPADDRESS
  • Your desired username and password refered to as USERNAME and PASSWORD respectively
  • A copy of your HTTPS key and certificate chain.

Setting up an Apache Proxy / Reverse Proxy

The basic flow is as follows

  1. App/User connects to HTTP server and is redirected to HTTPS.
  2. App/User connects to HTTPS server with encryption and the zmNinja Query String value "basicauth" is converted from a query string into a Basic Authentication header
  3. The, now properly formatted, Basic Authentication request is forwarded to the Basic Authentication V-Host. This is required because the request has already begun processing and the request cannot be modified before processing.
  4. The Basic Authentication check occurs and the request is forwarded to ZoneMinder, or rejected.

Password File

To set up a password file with apache, issue the following commands as root

export HISTCONTROL=ignore-space
htpasswd -c /etc/apache2/passwd-nospecial "USERNAME" "PASSWORD"

The export command above prevents commands prefixed with a space from being recorde in bash history. The htpasswd command will create a passwd file at /etc/apache2/passwd-nospecial. The password should contain no special characters as zmNinja does not process them with hypertext-safe characters.

HTTPS to AUTH server host

To redirect from the HTTPS Query String v-host to Basic Authenticaion v-host, an entry must be added to the hosts file. Execute the following as root, only once.

echo '127.0.0.1       zmAuthenticationServer'>>/etc/hosts

HTTPS Configuration file

In order to make setup of https easy, I keep my keys, cert-chain and configuration file in a certain directory on my server. This way root can update the certificates and Apache can access them properly. Adding all of the lines required to establish https on each v-host only happens once and becomes a single include statement per v-host. I recommend /etc/apache2/certs, but this is up to you. It's probably better that you pick some obscure folder rather than follow a guide from some guy on the internet and cookie-cutter your installation so hacking can be automated.

This is the contents of my /etc/apache2/certs/https.conf

    SSLCertificateFile /etc/apache2/certs/fullchain.cer
    SSLCertificateKeyFile /etc/apache2/certs/MYEXTERNALSERVERDOTCOM.key

Virtual Hosts

The typical method of setting up an Apache Virtual Host Server is to place one Virtual Host per file so that you can enable/disable the v-hosts individually. I am separating these here as such. However, a more practical solution will be to copy all VirtualHosts into a single file. I say more practical, because in the configuration I am using, these servers rely upon each other in a chain. If one goes down, they may as well all go down. Also, it makes it easier to take them all down with a single command instead of several.

Note: you may utilize this jenkins job to generate a .conf file quickly and easily without copy-pasta from below

HTTP Redirect v-host

This v-host rewrites the user's request to utilize https and forces all future communications to use https if HSTS is properly supported. Change the following

  • MYEXTERNALSERVERDOTCOM should be your server name "zoneminder.myserver.com"
  • MYEMAIL should be your administrative contact email address

copy and change this http vhost:

    <VirtualHost *:80>
    #Welcome to my HTTP to HTTPS redirect server!
    ServerName        MYEXTERNALSERVERDOTCOM
    ServerAdmin       MYEMAIL
    #If you're using http, you're now going to be using https from now on.
    Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
    RewriteEngine on
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [L,QSA,R=permanent]
    </VirtualHost>

HTTPS Query String Rewrite v-Host

This v-host applies HTTPS so the transferred values are encrypted and free from coffee-shop Joe's peering eyes. If zmNinja sends a Query String with "basicauth=token", the token portion is placed into the "Authentication:" header of the request to the authentication v-host.

You will need to change

  • MYEXTERNALSERVERDOTCOM should be your server name "zoneminder.myserver.com"
  • MYEMAIL should be your administrative contact email address

Copy and change this https vhost:

    <VirtualHost *:443>
    #Welcome to my HTTPS server, all internet traffic is encrypted to here.
    ServerName        MYEXTERNALSERVERDOTCOM
    ServerAdmin       MYEMAIL

    #Authentication from Zoneinder config. Search query string for &basicauth=value
    #put "value" int a variable called "QS_TOKEN".
    RewriteEngine on
    RewriteCond %{QUERY_STRING} (?:^|&)basicauth=([^&]+)
    RewriteRule (.*) - [E=QS_TOKEN:%1]
    #If environmental variable QS_TOKEN is set, add a Basic Auth header to our next request.
    RequestHeader set Authorization: "Basic %{QS_TOKEN}e" env=QS_TOKEN

    #Drop encryption and communicate internally using the (possibly) basic auth'd request if it was set.
    ProxyPass        / http://zmAuthenticationServer/
    ProxyPassReverse / http://zmAuthenticationServer/

    #Use these values for the https server
    include /etc/apache2/certs/https.conf
    Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
    </VirtualHost>

Authentication V-Host

This V-Host performs the basic authentication required to prevent unauthorized access to the server. You will need to change

  • MYEMAIL to your email
  • LOCALZONEMINDERIPADDRESS to your zoneminder IP.

Copy and change this authentication v-host

    <VirtualHost 127.0.0.1:80>
    #Welcome to my authentication server. You will be authorized and zoneminder will be accessed here.
    #In order to make this setup work, the server needs to recognize itself as "zmAuthenticationServer".
    #This is accomplished by placing the following line within /etc/hosts.
    #127.0.0.1        zmAuthenticationServer
    ServerName        zmAuthenticationServer
    ServerAdmin       MYEMAIL
    ProxyPass        / http://LOCALZONEMINDERIPADDRESS/
    ProxyPassReverse / http://LOCALZONEMINDERIPADDRESS/
    DirectoryIndex index.php

    #Authentication Locations
    #Create htaccess with the following:
    #sudo htpasswd -c /etc/apache2/passwd-nospecial <MYUSERNAME>; sudo chown www-data:www-data /etc/apache2/passwd-nospecial username;
    #Password cannot contain special characters as ZMNinja will not encode them properly.
    <Location />
      AuthType Basic
      AuthName "Authentication Required"
      AuthUserFile "/etc/apache2/passwd-nospecial"
      Require valid-user
      Order allow,deny
      Allow from all
    </Location>
    </VirtualHost>

Testing

From any machine which is not the proxy server, perform the following tests to ensure everything is operating properly. You must know your proxy server IP, and it will be identified below as PROXYSERVERIP

Test overall operations

curl -u USERNAME:PASSWORD https://MYEXTERNALSERVERDOTCOM 2>&1 |grep ZoneMinder

Result should contain "ZoneMinder Login"

Test the http redirect server

curl http://MYEXTERNALSERVERDOTCOM

Result should include a 301 "moved permanently" message.

Test the https server

curl https://MYEXTERNALSERVERDOTCOM

Result should include a "Unauthorized" message

Test the basic auth proxy external access rejection

curl -kH 'Host: zmAuthenticationServer' http://PROXYSERVERIP

Result should not include the words "zoneminder". If you are viewing the HTML of the zoneminder page, something is wrong.

zmNinja Configuration

Enable "Append basic auth tokens in images" option in zmNinja->Developer Settings and save. What this does is that image URLs will append a "basicauth" token parameter with your basic authentication credentials. This token can then be parsed by Apache and inserted as a valid Authorization header. Don't enable this option if you are not using HTTPS because the request-URI will be transmitted without encryption and it will contain your basic auth credentials, encoded in base64, which is trivial to decode.

Conclusion

Please ask for help in the ZM forum. If this page requires work, please come back and update it. it is my hope that this will be helpful and make zmNinja more accessible for everyone.