In all my previous Varnish 3.x configs, I’ve always used blacklisting as the way of handling Cookies. You explicitly tell which cookies you want to remove in vcl_recv
, all others remain. But just as security measures, whitelisting is always better than blacklisting.
Even if you fully manage your site and all code, you may not have full control over 3rd party (client-side) advertisers that use tracking cookies. And those cookies may, even if you don’t approve of the method, be placed under your domain. So the next request to your site suddenly includes (random) tracking cookies, unique for each visitor, and it destroys the caching in vcl_hash
.
Please note this guide is focused on Varnish 3.x. Varnish 4.x will have the Cookie VMOD available by default, no custom compiles required!
Blacklisting / Removing cookies in Varnish
This is the common method of removing cookies in vcl_recv
.
set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", "");
And you would repeat that line 1, 10 or 100 times, depending on what cookies you want to remove.
Implementing a whitelist of allowed cookies
In order to use a whitelisting approach, you can use the libvmod-cookie VMOD for Varnish 3.x. It allows more fine-grained control over what cookies are preserved and which ones get removed.
In order to use the VMOD, you need to compile it from source. And to compile the VMOD from source, you also need the Varnish source files somewhere on your system. You can still keep the RPM packages from Varnish installed, but the source is needed to compile the VMOD against it.
Preparing the Varnish source
In this guide, I’ll use Varnish 3.0.6 as the base-version to compile against. Download the source and run make
to build the binary files, but no not make install
as you want to keep the packages from the upstream Varnish repo intact.
$ cd /usr/local/src $ wget "https://repo.varnish-cache.org/source/varnish-3.0.6.tar.gz" $ tar xzvf varnish-3.0.6.tar.gz $ cd varnish-3.0.6 $ ./configure $ make
Now you have the Varnish source and a built binary available in /usr/local/src/varnish-3.0.6
. We’ll use this to compile the VMOD against.
Download and install the libvmod-cookie varnish module
Next, download and compile the libvmod-cookie
module.
$ cd /usr/local/src $ wget "https://github.com/lkarsten/libvmod-cookie/tarball/3.0" $ tar xzvf 3.0 $ cd lkarsten-libvmod-cookie-fe38614 $ ./configure VARNISHSRC=/usr/local/src/varnish-3.0.6 VMODDIR=/usr/lib64/varnish/vmods/ $ make && make install
The result is a vmod module installed in /usr/lib64/varnish/vmods/
.
$ ls -alh /usr/lib64/varnish/vmods/ -rwxr-xr-x 1 root root 955 Dec 21 21:28 libvmod_cookie.la -rwxr-xr-x 1 root root 42K Dec 21 21:28 libvmod_cookie.so -rwxr-xr-x 1 root root 16K Oct 16 16:30 libvmod_std.so
The libvmod_std
is the standard library included by Varnish. The libvmod_cookie
is the new binary module, and you can include the vmod in your VCL code now.
import cookie; vcl_recv { ... }
Whitelisting cookies using filter_except() in libvmod-cookie
And now that the VMOD module is installed and ready for use, you can use the powerful filter_except()
function call to pass a comma-separated list of cookies to allow, all others will be removed.
vcl_recv { # Let the module parse the "Cookie:" header from the client cookie.parse(req.http.cookie); # Filter all except these cookies from it cookie.filter_except("cookie1,cookie2"); # Set the "Cookie:" header to the parsed/filtered value, removing all unnecessary cookies set req.http.cookie = cookie.get_string(); }
Any other cookie besides cookie1 and cookie2 will be removed from the Cookie:
header now.
To debug this and to test what cookies are removed and which ones remain, look at my post about seeing which cookies get stripped in the VCL.
Next up: figuring out how to pass regex’s along. ;-)
Caveats
A few things to keep in mind;
- VMODs are compiled, so it’s better to make packages out of them
- Since VMODs are compiled against a specific version, they need to match the Varnish version. (so varnish 3.0.5 from RPM/Yum repos and VMODs compiled with 3.0.6 source can mean troubles)
- For automating this at scale, you need the VMODs in your own repository
- The filter_except() call accepts strings, not regex’s – to match against regex’s, you would need to loop all values
To be continued!