Blog Tenya.me

some blog : )

Varnish HTTP Authentication

| Comments

Sometimes we need restrict access to site that cached by Varnish with basic HTTP authentication.

Basic method is enable it on backend (Apache, nginx, lighttpd or other web-server). But after the first correct request, it will be cached on Varnish and all other clients requests would be without authentication.
Solution for this situation is pass all request with authentication to backend with next statement:

Pass authorization to backend
1
2
3
4
if (req.http.Authorization || req.http.Authenticate)
{
  return (pass);
}

As we remember, caching still required for this site. So, statement above is not suitable for our conditions.

Good workaround is to check HTTP authentication at the Varnish.
Well then do it in VCL.

On vcl_recv section we will check a authorization header and invoke a 401 error if header is not present:

Pass authorization to backend
1
2
3
4
if (! req.http.Authorization ~ "Basic Zm9vOmJhcgo=")
{
  error 401 "Restricted";
}

where Zm9vOmJhcgo= is a base64 encoded string of “http-user:http-password”. In this example it is a foo:bar.
To get encoded string you may use base64 console command:

base64 encode
1
$ echo -n "foo:bar" | base64

or use some other tool.

Next, on vcl_error section we need to create a error handler for 401 code:

Handler for 401 code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if (obj.status == 401) {
  set obj.http.Content-Type = "text/html; charset=utf-8";
  set obj.http.WWW-Authenticate = "Basic realm=Secured";
  synthetic {" 

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">

 <HTML>
 <HEAD>
 <TITLE>Error</TITLE>
 <META HTTP-EQUIV='Content-Type' CONTENT='text/html;'>
 </HEAD>
 <BODY><H1>401 Unauthorized (varnish)</H1></BODY>
 </HTML>
 "};
  return (deliver);
}

Adding this both snippets to your VCL enables HTTP authorization on Varnish and caching still present, so you are able to develop or debug your site.

Multiple users and password can be set with && statement on header check:

Multiple users and passwords
1
2
3
4
5
if (! req.http.Authorization ~ "Basic Zm9vOmJhcgo=" # foo:bar
&& ! req.http.Authorization ~ "Basic bG9yZW06aXBzdW0K" # lorem:ipsum
) {
  error 401 "Restricted";
}

Comments