Problem/Motivation

In an attempt to make authcache with anonymous sessions (SESS cookie present on anonymous access) work with fastly, I started to face several different issues, quite a bit were discussed on this issue and its evolved into an ongoing discussions on a best practice to use an upstream reverse proxy (CDN or something else.). The site is an ecommerce site.

Proposed resolution

I created the following module: https://www.drupal.org/project/authcache_upstream

Following its configuration recipe should allow any upstream (fastly, varnish, nginx) to work nicely with authcache.

Remaining tasks

- Something I found out is that it makes it slightly hardish to make this work properly with mixed http/https sessions, I don't think there's much way around it and the suggested contributed module attempts to cope a bit with this particular case, but I am simply favouring forcing HTTPS.
- There's also an ongoing discussion on the issue, if the cookie should be present in the module, but after adding slightly more logic to the contributed module, maybe it's fine that it's maintained elsewhere.
- Another byproduct of this is that there's maybe the possibility of using this upstream module with another cache, like builtin on something, having two different layers of cache, this is complex and probably very use case specific, but worth noting it looks possible.

Fastly

A lot of references are for fastly, but only because that's the CDN I am working with right now. It really should apply to any reverser proxy, but if someone working on fastly finds this issue, worth looking at the following:
- https://www.fastly.com/blog/best-practices-for-using-the-vary-header
- #2792955: Simplify the module by removing unnecessary and conflicting logic

Comments

hanoii created an issue. See original summary.

znerol’s picture

This is more or less what the Authcache Varnish module does, so you might want to study that (and also the VCL).

The big problem with something like Vary: X-Authcache-Roles is that the respective header needs to be on the request. I.e., if the X-Authcache-Roles header is not on every request, then there is nothing to vary... Hence, it is necessary to somehow add the custom request header server-side. That's the exact reason for the non-trivial vcl.

hanoii’s picture

Status: Active » Needs review
StatusFileSize
new1.02 KB
hanoii’s picture

Well, not exactly, at least I think so. In the way this patch adds it, which is the same of what you do in

authcache_authcache_account_exclude().

If authcache is busted, it means that no "caching is being done", so the no-cache headers are also being set, so in those cases, it's fine not to have anything to vary on, because you are also sending the no-cache header, so there's nothing to attempt to vary on.

Or am I understanding this in the wrong way?

I tried it on a setup, So I am getting and varying on x-authcache-roles, on anon with sessions. The minute I log in with a different role in which no x-authcache-roles is set, I am still getting the proper logged in page. I think because an empty Vary it's still a valid Vary combination.

hanoii’s picture

I edited the previous comment with more info, sorry i didn't add another comment, just in cased you missed it. Thanks for getting back so quickly (before I got to submit the patch:).

znerol’s picture

If you want to Vary on an custom X-Authcache-Roles header, then that header needs to be on the request (browser->server) not on the response (server->browser). This patch adds X-Authcache-Roles to the response. This is hardly of any use.

hanoii’s picture

I am pretty sure it's the other way around.

That's why the vary is set server side by Drupal and your module.

The "Vary" header field in a response describes what parts of a
request message, aside from the method, Host header field, and
request target, might influence the origin

See
- https://tools.ietf.org/html/rfc7231#section-7.1.4
- https://www.fastly.com/blog/best-practices-for-using-the-vary-header
- https://varvy.com/mobile/vary-user-agent.html

znerol’s picture

+++ b/authcache.module
@@ -92,6 +92,18 @@ function authcache_module_implements_alter(&$implementations, $hook) {
+    drupal_add_http_header('X-Authcache-Roles', implode(', ', array_keys($authcache_roles)));

Your patch adds an X-Authcache-Roles response header. This is completely useless wrt to a custom Vary header.

The Vary response header holds a list of request headers. Request headers do originate on the user-agent, not on the server. There is no way to enforce a custom header in the browser, except when using JavaScript XHR.

hanoii’s picture

you are so very right. I got this wrong. Thanks for pushing the explanation. It should be a cookie with the authcache roles then with some transformation in the vcl t convert that into a custom request header. I will see what the varnish module does but I believe at least the cookie should be present regardless of the backend module cache.

znerol’s picture

Note that fastly seems to allow user supplied VCL. However, it seems that they are using a customized version of Varnish 2. The Authcache Varnish module ships with VCL for Varnish 3 and 4.

Maybe it is possible to port the relevant bits to fastly VCL. E.g., the docs about Authenticating before returning a request describe a similar mechanism as the one Authcache Varnish uses to retrieve the authcache key.

I do not find any indication whether or not they support ESI, but that's optional anyway.

hanoii’s picture

Title: X-Authcache-Roles so that it can be used as a better vary » X-Authcache-Key information on a cookie so that it can be used as a better vary

Thanks! I just looked properly on the varnish module, and you are right that they are doing something similar, however, the logic is complex and really applies to something more out of the box, but it's just too custom for implementing it on mostly any cdn as reverse proxy as they normally have their own things and limitations.

I think fastly does support ESI but I am not very interested at the moment as we are sorting the dynamic bits of the page on our own, so I don't really need it. What I would like to have, is something general and relatively simple that I could use with fastly (and really any other reverse proxy for that matter).

The authcache_varnish module generates a callback to get the key, it's a bit too troublesome, as the key, imho, could be simply sent on a cookie and then transformed on the cache side.

I noticed a lot of checks that happen on

authcache_varnish_request_validate().

Are those really necessary, is showing the cache key to the outside world any security flaw? It doesn't look like that at a first thought.

So doing something in the like of:

  if (authcache_account_allows_caching()) {
    // Set the key on a cookie so that it can be used by cache proxies transformations
    setcookie('Drupal.authcache.key', authcache_key(), authcache_key_lifetime());
  }

  // Add Vary header. (this is really optional, it could potentially not be added on the module as it can be configured with proper $conf[] variables, or even entirely on the cache side.
  // drupal_add_http_header('Vary', 'X-Authcache-Key');

I think having that for regardless of the backend (as in the main authcache module) would help.

I can do this on a custom module of my own I just think it's a nice addition to authcache, if you agree and unless you have a strong security concern on leaking the authcache key to the outside world, I can submit a patch with this approach.

Only having this information in the cookie, allows to do what fastly explains on the Vary: Cookie section.

Basically it's:

1. transforming the cookie value into a custom http request header
2. adding the custom header to the vary so that the cache use it
3. remove the vary header before sending the response back to the browser.

There in fastly there are other bits that's done although I wouldn't do all of that.

The above vcl is a very short addendum to fastly and probably any other varnish configuration, so it gets really simple unless I am missing something else out.

znerol’s picture

There is nothing wrong with exposing the cache-key to the outside world. In fact the Authcache Boost backend does exactly that.

It would be definitely great if you could put together a special backend module in the spirit of Authcache Varnish or Authcache Boost with a sample configuration ready to be deployed. I think it would be better to create a new project for that (cf. Authcache Boost), such that the module can be maintained independently of the main Authcache project (by people which are familiar with and do have access to Fastly services).

hanoii’s picture

Title: X-Authcache-Key information on a cookie so that it can be used as a better vary » Add authcache key cookie to the builtin cache so that it can be used by upstreams proxies

I think I am starting to understand what I really want to do and how/where to do it and there was a bit of confusion on this issue as how I understood the design of authcache, still definitely not following everything but getting there. Caching is definitely a complex subject.

The main thing I notice is that i wasn't clear in what I was really going for. I don't want to create a new backend for fastly, because it's really not needed. I underestand now that what the varnish module does is leaving the storing of the cache pages entirely to varnish and that's why it has that many logic.

However what I like is to still use the builtin cache, which works very good, but also use fastly for its cdn and a second caching layer.

They could even have different configuration as far as ttl goes and all.

The only thing I see needing for this is to have the builtin cache expose the key in a cookie so that it can be used by fastly. And eventually any other varnish upstream or any other really. I wonder if there might be extra things needed for this to work properly, but I am not quite sure.

I thought this was meant to be globally, like my attempt with X-Authcache-Roles before, but I now see it has to be done within the builtin cache.

I do wonder where is the proper place to add such a cookie. I mean simply adding a cookie that holds the key.

Would adding it in

authcache_builtin_authcache_backend_key_set()

be enough, or that's only for when the key changes?

If so, where else do I need to add it and is there a proper way of adding such a cookie?

I see boost use autcache_add_cookie, is that what I should be using?

hanoii’s picture

On second thoughts, doing an simplish authcache_fastly, or even and authcache_cookie or authcache_generic could be simple and not a bad idea, although adding it to builtin could be harmless/useful and help me in building this other posible module.

hanoii’s picture

Status: Needs review » Needs work

Have a look at https://www.drupal.org/sandbox/hanoii/2786375 if you can.

Basically is mostly we discussed here. A dumb backend simply exposing a cookie and a general recipe that can be replicated on serveral upstream reverse proxies.

I still wonder if something so simple shouldn't be on authcache core.

Like adding the cookie regardless of the backend, and maybe having a blank or dummy backend you can enable.

I will see if I come up with some useful authcache_debug info addition, although not sure if possible.

znerol’s picture

Have a look at https://www.drupal.org/sandbox/hanoii/2786375 if you can.

Wow! Congratulations. I cannot comment on the VCL, I'm not familiar with fastly dialect. Regarding the PHP part, I suggest adding the httponly directive to the cookie in order to make it inaccessible from JavaScript. Also why do you check for the cookie when you actually want to use a custom request header? I'd expect that something similar (or identical) to authcache_varnish_boot(), but maybe I did misread something.

I still wonder if something so simple shouldn't be on authcache core.

Frankly, I'm really torn on this. It is true that the Drupal/Authcache part is really simple. But in my opinion there is nothing wrong with minimalistic modules - more features will creep in over time anyway. I guess the bigger challenge for users is to set up the reverse proxy software/service, so the size of the PHP part might be not so relevant when trying to take a decision on whether or not this should be a separate project.

Maybe it helps to switch perspective and try to figure out which variant is best for site builders.

Authcache can be quite complex to set-up. One of the design goals was to make it possible to easily swap backends in order to simplify the development/staging/production workflow and also to better support adapting sites to growing needs. Developers may work with the builtin backend while production runs on Varnish. Also when traffic grows, sites can switch from builtin SQL backed cache to whatever they fancy. I guess a fastly integration module might fit into this picture really well.

I feel that the current content of the sandbox tries to be two things: A simple generic backend for reverse proxies (which must be carefully configured though) and at the same time an example on how to integrate fastly. I argue that it would be more useful for site builders if it did one thing only and if it did that without any compromise (and maybe even with nearly zero configuration). I think it would also be easier to add new/more advanced/fastly specific features if that module would be a separate project moving at its own pace.

Also maybe there is a chance that they accept an authcache integration patch over at the fastly project?

hanoii’s picture

Also why do you check for the cookie when you actually want to use a custom request header?

The custom request header is nearly transparent, and I wanted to make it so that it works the same regardless of that. By using cookie it also allows me to debug the module better than the header. Was planning on making it httponly, although I thought maybe the key is eventually useful to be accesible through JS?

I feel that the current content of the sandbox tries to be two things: A simple generic backend for reverse proxies (which must be carefully configured though) and at the same time an example on how to integrate fastly.

It is two things, but to be honest, is really the former, a generic one.

With this, if I were to set up a local varnish, I wouldn't use the varnish backend, I would use this module and add the vcl property.

All of the fastly references is because I am using fastly for it. And I am also using the fastly module, but it's not a fastly integration. I do provide a fastly vcl example, but even that is tricky, because it depends on a fastly vcl template with specific tags. The minute they change anything on those tags, the boilerplate my change.[1]

With the ever growing list of CDNs and its different caching techniques, something like this makes it really standard.

I cannot comment on the VCL, I'm not familiar with fastly dialect.

Besides the fastly.vcl, I will also add a varnish.vcl, which will be basically the vcl example on the project page. It's not fastly dialect, it's simple varnish dialect. The recipe in the project page works the same for any reverse proxy.

By adding this into core (just setting and maintaining the cookie) you are allow to do this generic setup, and you get one more benefit, which is that you can also do so regardless of the backend you use. So you can set a builtin cache, and also use fastly with the same recipe. In that case you would have two different caches working at the same time. It's odd, but allows you to do nifty things. I'd reconsider. It's just so simple that it's almost a pity not to do it. And adding a cookie is really backend agnostic. You can use it or not, but it's there.

I am still working out a few issues with mixed http/https sessions, and yes, sorting it out with fastly, but the beauty of this cdn is that it's making you respect a standard to vary on the Vary header, so whatever you do, works the same for anything else.

Will soon to submit another patch for the cookies part on authcache.

[1]: https://docs.fastly.com/guides/vcl/mixing-and-matching-fastly-vcl-with-c...

znerol’s picture

In that case you would have two different caches working at the same time. It's odd, but allows you to do nifty things. I'd reconsider. It's just so simple that it's almost a pity not to do it.

Having two server side page level cache layers is a bad idea IHMO and will lead to weird effects (e.g., see #2771847: Module doesn't negate internal page cache over at fastly), especially if you add purging / expire or stuff like geoip / device detection to the mix.

And adding a cookie is really backend agnostic. You can use it or not, but it's there.

It only would make sense to add the cookie if the majority of use cases / deployments rely on that. I do not think that this is currently the case. Managing the authcache key is clearly backend specific and thus should be done in the backend module, not in core.

How about an Authcache CDN module which tries to integrate with any CDN service?

hanoii’s picture

Fair enough.

The Authcache CDN is really Authcache upstream, my (probably poor) choice of name is only because CDN is not really the case. The upstream module can be used with a local varnish, a local nginx, anything really as long as you are allow to modify with headers and Vary.

Will continue shaping out this module and release it as such.

Thanks a lot for the ongoing discussions. As you said is a complex subject :).

wim leers’s picture

Very interesting stuff here! Sent this issue link to Fabian Franz and my colleague Josh Waihi. Josh has worked on something almost identical: https://github.com/fiasco/authcache-acquia.

znerol’s picture

Nice. I like the idea with the signature. I suggest including the session id as well into the HMAC. Otherwise you only have to capture a key and the signature once and then reuse it with another session.

hanoii’s picture

Issue summary: View changes

@Wim Leers glad and happy you find the issue interesting!!

Updated the issue summary a bit, still working on it but I think it's pretty stable atm.

hanoii’s picture

Issue summary: View changes
hanoii’s picture

Title: Add authcache key cookie to the builtin cache so that it can be used by upstreams proxies » Add authcache key cookie so that it can be used by upstreams proxies
Issue summary: View changes
hanoii’s picture

Issue summary: View changes
hanoii’s picture

Status: Needs work » Closed (won't fix)

And I guess we can close this issue

znerol’s picture

Thanks a lot! I've added a link to the Authcache project page.