Getting "Secure Pages" like behavior behind Varnish or AWS ELBs

Torenware's picture

I have a site that has both a large anonymous-use and logged-in participant usage. In an older version, the client used Secure Pages to get some pages into SSL, but to force most traffic back into regular HTTP if the page did not require it.

How best to implement this with Varnish or AWS?

This is not an uncommon use case, but I've had problems getting this kind of behavior behind a Varnish server, and will need to get this kind of behavior on AWS behind elastic load balancers (AWS ELB).

What are the options for implementing this in a reverse proxy cache kind of way? I'm looking into the Cache Control module (on the assumption this is even relevant), and am also looking for tested VCL recipes for Varnish, and set up hints for both Apache and nginx.

What are people doing to get SSL to play nice in these kinds of set-ups?

Comments

Can you give more details on

dalin's picture

Can you give more details on what your problem is? In theory you should need no extra tricks. HTTPS requests will bypass Varnish (since that's on port 443) and go straight to the webserver. The webserver can then redirect back to HTTP/80 if HTTPS is not required.

If you want to redirect the other way (HTTP->HTTPS), then there needs to be a pre-existing reason to bypass Varnish (a session cookie, NO_CACHE cookie, or something else in the HTTP headers that you can write a rule in Varnish for).

--
Dave Hansen-Lange
Technical Manager
Advomatic LLC
Great White North Office
Canada

Also -- what kind of rule do I need to write in VCL?

Torenware's picture

If you want to redirect the other way (HTTP->HTTPS), then there needs to be a pre-existing reason to bypass Varnish (a session cookie, NO_CACHE cookie, or something else in the HTTP headers that you can write a rule in Varnish for).

Like a lot of folks who use Varnish, I've mostly copied recipies for this when I needed it to do something squirrelly :-) VCL is mostly greek to me, until now, anyway. Even if I can do regular expressions with the best of 'em.

What kind of rule needs get written to make Varnish do a simple pass through?

Two problems -- sessions and "forward back"

Torenware's picture

Thanks, Dave.

First, under Varnish and Drupal 7:

As you correctly point out, http is under Varnish, and https talks directly to the web server (Apache in this case).

The biggest problem I've seen is that in my current configuration, if the user logs in under http, they are not logged in under https and visa versa. I'm not sure what needs to be in place to make sure that there is a single log in.

The second is that I'm not always getting the "bounce back" behavior that Secure Pages supports, i.e., if the front page is not a "secured" URL and "/user" is, when someone at https://THESITE/user clicks on the "Home" link, they end up at https://THESITE/ rather than http://THESITE/.

Under AWS:

Everything is going to be behind an elastic load balancer (ELB). We haven't set this up yet to try it, but if there is any guidance you or anybody else can give, much obliged.

Torenware's picture

It turns out (not surprisingly) that the Varnish advice here is very good; the bounce-back problem relates to some setting changs that are needed for SecurePages, but appears to be a new requirement for Drupal 7:

Set $conf['https'] = TRUE; in settings.php.

Set your VCL to always pass when it sees session cookies

gchaix's picture

I use securepages and Varnish extensively. The only time I see users being not-logged-in after a securepages redirect to HTTP is when Varnish is serving up a cached anonymous user page. If you make sure the VCL is doing a return pass whenever there is a Drupal session cookie, your users should stay logged in regardless of HTTP/HTTPS.

What syntax will do that?

Torenware's picture

I'm using syntax from your blog post linked from the Varnish module project page; thanks for that.

I assume you are referring to an "if" clause inside of sub vcl_recv.

What syntax would make sure I was capturing "whenever there is a Drupal session cookie" in Varnish 2.1.x?

Sorry ... missed that you

gchaix's picture

Sorry ... missed that you were waiting on a reply.

Varnish is blissfully unaware of HTTPS connections. There is no config at all in Varnish regarding SSL because all SSL traffic in my setups bypass Varnish entirely.

HTTP -> Varnish -> Apache:80
HTTPS -> Nginx -> Apache:443

Securepages is happy because the HTTPS connections are coming all they way through to the backend(s) on 443. Varnish doesn't do anything at all with HTTPS connections, since all HTTPS connections go through Nginx for SSL termination and then go straight to the backend(s).

What syntax would make sure I

gchaix's picture

What syntax would make sure I was capturing "whenever there is a Drupal session cookie" in Varnish 2.1.x?

In vcl_recv:

    ## Don't cache Drupal logged-in user sessions
    if (req.http.Cookie ~ "(NO_CACHE|DRUPAL_UID)") {
        return (pass);
    }

And here's what we use:   #

dalin's picture

And here's what we use:

  # Remove all cookies that Drupal doesn't need to know about. ANY remaining
  # cookie will cause the request to pass-through to Apache. For the most part
  # we always set the NO_CACHE cookie after any POST request, disabling the
  # Varnish cache temporarily. The session cookie allows all authenticated users
  # to pass through as long as they're logged in.
  if (req.http.Cookie) {
    set req.http.Cookie = ";" req.http.Cookie;
    set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
    set req.http.Cookie = regsuball(req.http.Cookie, ";(S?SESS[a-z0-9]+|NO_CACHE|session_api_session|LOGGED_IN|(?:CHOCOLATECHIP|OATMEAL)(?:SSL)?)=", "; \1=");
    set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

    if (req.http.Cookie == "") {
      # If there are no remaining cookies, remove the cookie header. If there
      # aren't any cookie headers, Varnish's default behavior will be to cache
      # the page.
      unset req.http.Cookie;
    }
    else {
      # If there is any cookies left (a session or NO_CACHE cookie), do not
      # cache the page. Pass it on to Apache directly.
      return (pass);
    }
  }

--
Dave Hansen-Lange
Technical Manager
Advomatic LLC
Great White North Office
Canada

For the record, my drupal.vcl file

Torenware's picture

Here's the relevant section of my .vcl file:

sub vcl_recv {
  // Remove has_js and Google Analytics * cookies.
  set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(
[a-z]+|has_js)=[^;]*", "");
  // Remove a ";" prefix, if present.
  set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
  // Remove empty cookies.
  if (req.http.Cookie ~ "^\s*$") {
    unset req.http.Cookie;
  }

  # Site still uses some static files out of /files, cache them
  if (req.url ~ "^sites/default/files/*") {
    unset req.http.Cookie;
  }
  # enable caching of theme files (can’t enable globally due to update.php problem above)
  if (req.url ~ "^/sites/all") {
    unset req.http.Cookie;
  }

  # Drupal js/css doesn’t need cookies, cache them
  if (req.url ~ "^/modules/.*.(js|css)\?") {
    unset req.http.Cookie;
  }

  ## Pass cron jobs
  if (req.url ~ "cron.php") {
    return (pass);
  }
}

SSL Offloading

skwashd's picture

[Deleted dupe]

SSL Offloading

skwashd's picture

It sounds like you need to configure Drupal to handle SSL offloading. There is a great blog post from Lullabot on SSL offloading with Drupal. You just need to adapt the load balancer side of things to get it working with Amazon's ELB.

Not currently, but we will on AWS

Torenware's picture

The configuration I describe above passes HTTP to Varnish, but has Apache handle HTTPS directly.

But on our AWS deploys, SSL occurs at the level of the ELB, and yeah, we'll need to do what Lullabot describes in the post you cite.

The problem is securepages

Fabianx's picture

The biggest problem with securepages is that it needs some core patches to function properly.

Else partial http/https sessions are not supported.

I just had that problem with a recent site launch.

After I had https = TRUE in settings.php and the 3 core patches linked from securepages module in, it directly worked.

Varnish is _no_ problem at all as all pages will always give the redirect and varnish caches the redirect for anonymous users and it also works directly for logged in users obviously.

( I was using slightly changed lullabot config).

AWS ELB is transparent to the webserver and not caching at all, so also no problems here.

The only challenge with AWS ELB is to setup the correct x-forwarded-for header to the normal https setting in Apache so that Drupal knows that it now is "HTTPS".

Let me check ...

Here is the line:

SetEnvIf X-Forwarded-Proto ".*https.*" HTTPS=on

That does the trick.

Hope that helps!

Best Wishes,

Fabian