Generating CSP and HPKP headers in Ansible template

2016-12-18 00:00:00 +0000

Content Security Policy headers can grow very long and as such are error prone if edited manually. One way to resolve that is generating them using a template language from a clean YAML structure, for example using Ansible. The Ansible setup for CSP and HPKP headers is relatively simple, especially if you compare it with the nightmarish IPSec configuration generator I wrote (but which works in production nonetheless). The whole CSP configuration sits in group variable file in YAML format (group_vars/all). Note how special CSP origins (‘none’) are placed in double quotes to ensure proper rendering by Ansible, and how the single keyword option (upgrade-insecure-requests) is assigned an empty list to render as the target keyword only:

csp: "default-src": - "'none'" "img-src": - - https://* - https://* - "script-src": - - - - - https://* - https://* - "'unsafe-inline'" "style-src": - - - "'unsafe-inline'" "font-src": - "frame-src": - https://* - https://* - https://* - https://* "upgrade-insecure-requests": -

Then the template to output the Nginx header is quite simple:

add_header Content-Security-Policy "";

Same story for HTTP Public Key Pins (HPKP) header. First, the YAML configuration in the same group_vars/all file:


And the template (actually, the same file as above, just split for clarity):

add_header Public-Key-Pins '; max-age=3600';

The final output after Ansible task is run will be these machine-but-not-human-readable headers:

add_header Content-Security-Policy " script-src https://* https://* 'unsafe-inline'; img-src https://* https://*; default-src 'none'; frame-src https://* https://* https://* https://*; style-src 'unsafe-inline'; upgrade-insecure-requests ; font-src;";

add_header Public-Key-Pins ‘pin-sha256=”G5Yh5Mo/24pSh64SB3fhj0L5FZpnp4xjEg/INNDt9t8=”; pin-sha256=”TRi1sP2dt38aFrLNgr+zmllBN3tlzm0B/Hb4JZxrGvk=”; pin-sha256=”YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=”; pin-sha256=”sRHdihwgkaib1P1gxX8HFszlD+7/gTfNvuAybgLPNis=”; pin-sha256=”C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=”; pin-sha256=”Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=”; ; max-age=3600’; </code>