Security hlavičky s AWS CloudFront (1)

Martin Nuc
zonky-developers
Published in
3 min readMay 3, 2018

V Zonky používáme AWS CloudFront (CF) jako CDN. Do nedávna zde byl problém nastavit nejrůznější http hlavičky. V tomto článku zkusím popsat naší zkušenost s tzv. Lambda@Edge, které lze k nastavení http hlaviček na CloudFront použít.

Jaké hlavičky nás to vlastně zajímají? Převážně bezpečnostní typu Content-Security-Policy, Referrer-Policy, ale také hlavičky pro nastavení cache prohlížeče (např. pro index.html). Samotný CloudFront umožňuje nastavit pouze hlavičky pro nastavení cachování. Pokud chceme více, je třeba zvolit jiné řešení.

Bylo nebylo…

Začněme tím, jak Zonky vypadalo, když funkce Lambda@Edge ještě nebyly dostupné.

Náš CloudFront používá několik zdrojů. Aplikaci po částech přepisujeme z AngularJS do EmberJS. Máme tedy jeden S3 bucket pro statické assety (obrázky, fonty apod.), další S3 bucket pro část v AngularJS a zbytek požadavků směřuje na instance s node.js, které se starají o server side rendering EmberJS.

Abychom mohli nastavit http hlavičky pro obsah z S3 bucketů, dali jsme před CloudFront HAProxy, která různé hlavičky přidávala na základě routované URL.

Bohužel jsme tím v té době přišli o HTTP/2, které CloudFront podporuje, ale HAProxy až od verze 1.8. Zároveň byla HAProxy další prvek v infrastruktuře, kde se potencionálně mohlo něco pokazit. Ačkoliv po více než roce a půl používání musím říct, že se jedná o velice stabilní software.

S čím přišel Amazon?

Na začátku roku 2017 představil Amazon funkce Lambda@Edge. Jedná se Lambda funkce, kterými můžete v CloudFront modifikovat jednotlivé http požadavky. Protože se funkce vykonává nad každým requestem, Amazon omezuje maximální dobu běhu funkce na 5 ms.

Funkci lze přiřadit pro každý cache behavior v nastavení CloudFront distribuce. Pro každý cache behavior jsou k dispozici celkem 4 sloty:

  • Viewer request — příchozí požadavek na CF
  • Origin request — příchozí požadavek na origin (S3, Elastic Beanstalk…)
  • Origin Response — odpověď originu
  • Viewer response — odpověď CF, zde přidáváme http hlavičky

CloudFront je distribuovaný po celém světě, ale Lambda funkce patří vždy do určitého regionu. Aby Amazon minimalizoval latenci při jejich provolávání, tak se funkce po přiřazení k CloudFront distribuci zreplikuje do všech regionů.

Jak tedy modifikovat hlavičky?

Samotné použití je velice jednoduché. Při http požadavku CloudFront funkci provolá a v ní je přístup k objektu s requestem a s response. Response objekt můžete volně modifikovat a na konci ho jen předáte při volání callbacku.

exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const response = event.Records[0].cf.response;
const requestHeaders = request.headers;
const responseHeaders = response.headers;

callback(null, response);
};

Je třeba dodržet strukturu objektu event.Records[0].cf.response.headers. Klíčem je vždy název hlavičky malými písmeny. Hodnota je pak objekt s názvem hlavičky bez ohledu na velikost písma a samotnou hodnotou hlavičky:

'x-frame-options': {
key: 'X-Frame-Options',
value: 'DENY'
}

Závěrem

Funkce Lambda@Edge používáme na produkčních prostředích třetím měsícem a zatím prakticky bez problémů 🤞. Jednou se nám stalo, že padal server side rendering pro určitou URL a díky CloudFront Custom Error Pages se nedopatřením zobrazovala maintenance stránka. Ta byla načítána z bucketu s assets a díky Lambda funkci dostala hlavičky pro cachování. Když jsme pak chybu odstranili, maintenance stránka se stále zobrazovala právě kvůli cachovacím hlavičkám. Nejedná se ale o chybu Lambda@Edge jako takových.

V dalším díle se budeme věnovat automatizaci nasazení funkcí, testování a jejich monitoringu.

--

--

Martin Nuc
zonky-developers

Software engineer at Productboard interested in frontend development, home automation, VR - in general technology enthusiast riding electric unicycle in Prague