In this week’s episode of Two-Minute Tech Tuesday, we'll talk about basic authentication, and how to use Varnish as an authentication gateway to handle that basic authentication.
You may know basic authentication from the following username and password prompt:
But in fact, it's the result of an unauthorized request that results in a response containing a 401 Unauthorized status code and a WWW-Authenticate response header containing the Basic keyword to indicate that the server requires basic authentication.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Restricted area"
Content-Type: text/html; charset=utf-8
Content-Length: 252
Connection: keep-alive
The way to tackle this is by adding the Authorization request header including the Basic keyword, and then the payload. The payload, in fact, is nothing more than a base64 encoded string containing the username, a colon separator, and a password. In this case, that's admin as the username and secret as the password.
While base64 encoding is not really that secure, as long as you use HTTPS to transmit the payload, you'll be fine. However, Varnish won't cache if it sees an Authorization request header. This is part of the built-in VCL behavior. As soon as the Authorization header is spotted, Varnish will bypass the cache by issuing a return(pass) in the VCL code.
sub vcl_recv {
if (req.http.Authorization || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
}
}
A way of circumventing this standard behavior is by writing your own VCL code and intercepting the Authorization header and matching it to the value that you would expect.
You can then choose to return a synthetic 401 if the password and the username don't match the expected value, which will trigger the vcl_synth subroutine, allowing you to intercept whatever response comes in and check if it has a 401 status code.
If it does, you can add the WWW-Authenticate response header and use the Basic keyword to initialize the basic authentication.
While easy to get started, after a while, this method will become a burden to maintain all the usernames and passwords. Every time a change happens, you need to change the VCL and it's there in plain text, so it's not that secure.
A better way would be to recycle the .htpasswd file that is generated by Apache. This is a lot more secure to operate, and you can then leverage vmod_basicauth, an open-source Varnish module that handles these files. Here's the VCL code you need to get it working:
The first thing you need to do is import the basicauth VMOD. Then, in vcl_recv, you can then again intercept the request. Use basicauth.match() as a function where the first argument is the password file containing all the data, and the second argument is the header you want to inspect — in this case, the "Authorization" header.
Join us next week for another Two-Minute Tuesday topic, presented to you in 2 minutes or less!