-
-
Notifications
You must be signed in to change notification settings - Fork 271
Apache Proxy Authorization with HTTPS, Basic Auth, and ProxyPass
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.
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:
- Redirect HTTP to HTTPS.
- Set up a proxy to use HTTPS encryption and convert basicauth Query String tokens from zmNinja into actionable Basic Authentication.
- Set up a proxy to enable Basic Auth with zmNinja.
- Set up hosts file to redirect the locally.
- 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.
The basic flow is as follows
- App/User connects to HTTP server and is redirected to HTTPS.
- 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
- 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.
- The Basic Authentication check occurs and the request is forwarded to ZoneMinder, or rejected.
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.
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
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
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
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>
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>
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>
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.
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.
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.