Varnish - SSL REDIRECTION AND BASIC AUTH

Varnish has proven itself to be quite brilliant and blindingly fast when it comes to caching. Quite recently I was in a situation where varnish was used as a frontend with nginx serving out a webapp and node serving out API services. The requirements for varnish were to honour cache headers churned out by the application, redirect all incoming requests to https and have basic auth in place.

Now varnish doesn't redirect SSL out of the box nor does it have a straight forward way of putting basic auth in place. In order to handle SSL redirection, this is the most promising solution I've found. The solution involves using the vcl_error module to detect a request via the vcl_recv module and perform a redirection with the proper HTTP code.

Address SSL Redirection

In the vcl_recv segment, right at the beginning put the following condition
sub vcl_recv {
    # SSL redirection
    if ( req.http.host ~ "^(?i)(www\.)?.*(\.<domain>)" && req.http.X-Forwarded-Proto !~ "(?i)https" ) {
        set req.http.x-Redir-Url = "https://" + req.http.host + req.url;
        error 750 req.http.x-Redir-Url;
    }
    ...
    return (lookup);
}
In the vcl_error segment, define the error and operation
sub vcl_error {
    if (obj.status == 750) {
        set obj.http.Location = obj.response;
        set obj.status = 302;
    }
    ...
    return (deliver);
}

This means any request coming for http://www.<domain> or http://<domain> would be captured under error code 750 and as a part of error handling redirected to the SSL listener with HTTP status 302. Much detailed examples of redirection can be found at Redirect In VCL

address Basic Auth

Scenario 1: All incoming requests should pass through Basic Auth.

Generate Base64 Basic Auth via command line.

$ echo -n "user:password" | base64

In the vcl_recv, after the SSL redirection include the following logic
sub vcl_recv {
    if ( req.http.Authorization !~ "Basic dXNlcjpwYXNzd29yZA==" #user:password
    ) {
        error 401 "Restricted";
    }
    ...
    return (lookup);
}

Scenario 2: All incoming requests except a defined ACL should pass through Basic Auth.

At the beginning of the vcl define an ACL with the host IPs allowed without basic auth.
acl localhost {
    "localhost";
    "127.0.0.1";
}
Modify the vcl_recv as below
sub vcl_recv {
    if ( client.ip !~ localhost && req.http.Authorization !~ "Basic dXNlcjpwYXNzd29yZA==" #user:password
    ) {
        error 401 "Restricted";
    }
    ...
    return (lookup);
}

Scenario 3: All incoming requests except for a few specific requests should pass through Basic Auth.

Modify the vcl_recv as below
sub vcl_recv {
    if ( req.url !~ "/version" && req.http.Authorization !~ "Basic dXNlcjpwYXNzd29yZA==" #user:password
    ) {
        error 401 "Restricted";
    }
    ...
    return (lookup);
}