Wednesday, December 14, 2016

Nodejs Express enabling HSTS and cookie secure attribute


To enable HSTS (adds Strict-Transport-Security header to the response) for Node + Express using Helmet, this should be sufficient to add to your app.js:

var hsts = require('hsts')

app.use(hsts({
  maxAge: 15552000  // 180 days in seconds
}))

But a few things didn't work for me. First of all I had to add the force: true attribute. Also I was using an older version of HSTS ([0.14.0 instead of current latest release 2.0.0), so the maxAge was not in seconds but in milliseconds. It says in the README at github but I hadn't checked the version we were using...

To enable the 'secure' attribute for cookies (so they are only sent over HTTPs), I added the cookie-session module. But there is an issue with the secure flag. See the code below for more details.

Below is a full viewcounter.js application that shows the result for enabling hsts and secure cookes. Note also the comments in the code.

Start it with: node viewcounterhelmet.js

viewcounterhelmet.js:

var cookieSession = require('cookie-session')
var helmet = require('helmet');
var express = require('express')

var app = express()

app.use(helmet());
// Works, makes in response show Cache-Control, Pragma, Expires: app.use(helmet.noCache());
var oneYearInSeconds = 31536000;
app.use(helmet.hsts({
  maxAge: oneYearInSeconds,
  includeSubDomains: true,
  force: true
}));

var expiryDate = Date.now() + 60 * 60 * 1000; // 1 hour in milliseconds
app.use(cookieSession({
  name: 'session',
  secret: '10dfaf09-cf6f-43a9-b40b-4eaacbcceb8a',
  maxAge: expiryDate,
  // Not setting secure attr does not show it Secure
  // secure : true, // Set to true and no cookies at all in response. Created ticket for this for v1.2.0
  // secure : false, // Set to false it indeed doesn't show the Secure value with the cookie; it does show the cookies
  secureProxy: true, // Since this is running behind a proxy. But deprecated when using 2.0.0-alpha! Says to use secure option but that stops passing on cookies. When set to true, the cookie is set to Secure. If commented out, cookie not set to Secure
  httpOnly: true  // Don't allow javascript to access the cookie
}))

app.get('/', function (req, res, next) {
  // Update something in the session, needed for a cookie to appear
  req.session.views = (req.session.views || 0) + 1

  // Write response
  res.end(req.session.views + ' views')
})

app.listen(3000)

So when issuing the following curl command, this is the result:

vagrant$ curl -c - -v http://localhost:3000/
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:3000
> Accept: */*
< HTTP/1.1 200 OK
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Download-Options: noopen
< X-XSS-Protection: 1; mode=block
< Surrogate-Control: no-store
< Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate
< Pragma: no-cache
< Expires: 0
< Strict-Transport-Security: max-age=31536; includeSubDomains
* Added cookie session="eyJ2aWV3cyI6MX0=" for domain localhost, path /, expire 2961374488
< Set-Cookie: session=eyJ2aWV3cyI6MX0=; path=/; expires=Sun, 04 Nov 2063 04:01:28 GMT; secure; httponly
* Added cookie session.sig="DJaPtrG-tmTnVr33fOWXqWGnVlw" for domain localhost, path /, expire 2961374488
< Set-Cookie: session.sig=DJaPtrG-tmTnVr33fOWXqWGnVlw; path=/; expires=Sun, 04 Nov 2063 04:01:28 GMT; secure; httponly
< Date: Fri, 02 Dec 2016 13:30:45 GMT
< Connection: keep-alive
< Content-Length: 7
<
* Connection #0 to host localhost left intact
1 views# Netscape HTTP Cookie File
# http://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_localhost     FALSE   /       TRUE    2961374488      session eyJ2aWV3cyI6MX0=
#HttpOnly_localhost     FALSE   /       TRUE    2961374488      session.sig     DJaPtrG-tmTnVr33fOWXqWGnVlw

Notice the Strict-Transport-Security header and the set cookies with the 'secure' attribute set.

But when setting secure:true (also for the currently latest version 1.2.0), this is the result:

vagrant$ curl -c - -v http://localhost:3000/
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:3000
> Accept: */*
< HTTP/1.1 200 OK
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Download-Options: noopen
< X-XSS-Protection: 1; mode=block
< Surrogate-Control: no-store
< Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate
< Pragma: no-cache
< Expires: 0
< Strict-Transport-Security: max-age=31536; includeSubDomains
< Date: Tue, 13 Dec 2016 11:27:37 GMT
< Connection: keep-alive
< Content-Length: 7
* Connection #0 to host localhost left intact

So no cookies anymore, while they should be there!  Reported issue here.

Versions used:
  • node js: 6.7.0
  • express: 4.13.30
  • cookie-session: 1.2.0
  • helmet: 0.14.0




Saturday, December 3, 2016

Kubernetes Software Components Architecture Diagram

For a recent innovative project we were able to work with Kubernetes 1.3 as tool for automating deployment, scaling, and management of containerized applications. In our case (micro)services.


A lot of documentation is available, but I was missing an as-complete-as-possible architecture picture of all components within k8s. Or sometimes the link between certain components was not shown, or a related but very relevant component for the system was missing (e.g. Flannel). Below is the result of this: a full components architecture diagram of all components in Kubernetes. It was hard to fit everything in, but I think I have everything for the level of detail I wanted to capture.

The following components can be found in the diagram: kubectl, etcd, master node, worker node, controller manager, scheduler, etcd-watch, API server, Docker, kubeproxy, deployments, container, pod, service, kubelet, label selectors, config maps, secrets, daemon sets, jobs, flannel (for subnet), client app accessing the services.

Let me know in the comments if I'm missing anything! 😊


Inspiration for this diagram came from (amongst other things):