Such a long title for a post. If you want to protect a page or an entire website with HTTP authentication, but also want to whitelist a few fixed IPs (for instance: office or VPN IPs), you can combine both authentication mechanismes in Apache via .htaccess
files.
The full example goes like this.
AuthName "User + Pass required" AuthUserFile /path/to/your/htpasswd AuthType Basic Require valid-user Order Deny,Allow Deny from all # Normal whitelist would just add Allow directives Allow from 12.34.12.34 Allow from 12.34.12.35 # But if your site is behind Varnish, all connections will appear # to come from the Varnish IP, most likely 127.0.0.1 # or the IP from the host itself. # # So we set the X-Forwarded-For header in Varnish, and filter # on that header in Apache's htaccess / Directory access control. # # Allow from an IP in the X-Forwarded-For header (Varnish?) SetEnvIf X-Forwarded-For ^12\.34\.12\.34 env_allow_1 Allow from env=env_allow_1 # Allow from another IP in the X-Forwarded-For header SetEnvIf X-Forwarded-For ^12\.34\.12\.35 env_allow_2 Allow from env=env_allow_2 # Either the HTTP authentication needs to be correct, or the custom # environment that allowed the X-Forwarded-For header Satisfy Any
And when we break this time even more, it’ll show 2 clear methods.
HTTP authentication in .htaccess
The first part is the HTTP authentication, usernames and passwords, for Apache. You can set this in your Apache vhost config, or in an .htaccess
file in the directory you want to secure.
AuthName "User + Pass required" AuthUserFile /path/to/your/htpasswd AuthType Basic Require valid-user Order Deny,Allow Deny from all
This sets the AuthUserFile
to the path where the usernames/passwords are stored. If there’s no such file yet, you can create one with the htpasswd
tool at the CLI.
$ htpasswd -c /path/to/your/htpasswd $username
Replace $username
with what you want as a username. You’ll be prompted for a password for that user. If you want to append a username/password to an existing file, or want to modify the password of a user in an existing file, use the same CLI command without the -c
parameter.
$ htpasswd /path/to/your/htpasswd $username
And you’re set: your HTTP authentication password file exists.
IP Whitelisting with X-Forwarded-For
Normal IP whitelisting for this scenario would be done like this.
Allow from 10.0.1.1 Allow from 10.0.1.2 ...
But this uses the IP of the client connecting to Apache, which in the case of a reverse proxy config (like Nginx or Varnish), would nearly always be 127.0.0.1 or the IP of the connecting proxy. Not the client’s IP (unless you would be running a transparant proxy). We can retrieve that via the X-Forwarded-For, if it’s set in the Varnish configs.
To check if your Varnish config has this enabled, search for the line that says something like this.
... set req.http.X-Forwarded-For = client.ip; ...
It can exist in many variants, but the set req.http.X-Forwarded-For
is always the same. If it’s missing, add it at the top of the vcl_recv
routine. If that doesn’t work, have a look at my Varnish configs for some ideas.
Now, the Apache bit. You can perform a check on HTTP headers and allow or deny authentication based on that.
SetEnvIf X-Forwarded-For ^12\.34\.12\.35 env_allow_1 Allow from env=env_allow_1 Satisfy Any
The above example will set an environment variable called env_allow_1
, if the X-Forwarded-For
HTTP header matches the regex ^12\.34\.12\.35
, which in human words means as much as “the X-Forwarded-For header must start with 12.23.12.35". If that’s the case, the environment variable env_allow_1
will be set.
The Allow from
code allows you to check for environment variables, to allow or deny access.