HTTPS-Ausfall von 4 Hosts am 6.6.2018

Posted by luto on Wednesday, June 6, 2018

Magie ist kompliziert - aber halt auch cool. Auf Uberspace 7 setzen wir auf ein klein wenig Magie, um Let’s Encrypt Zertifikate für alle eure Domains zu holen. Das klappt auch voll gut! … meistens.

tldr-intermezzo: HTTPS für User-Domains (also alle relevanten) ist vom 6.6.2018 4 bis circa 8 Uhr auf 4 Hosts (whipple, taylor, kojima und klemola) ausgefallen. Es handelte sich dabei um einen einmaligen Fehler und kein generelles Problem. Fürs Warum und zukünftige Gegenmaßnahmen, einfach weiterlesen.

“error: ngx_http_lua_module required” oder:Wie war das nochmal mit Lua und nginx?

Mit der eingangs erwähnten auto-ssl-Magie läuft in unserem nginx/openresty nicht nur Config, sondern auch Lua-Code. Dieser hat eine Hand voll Lua-Modulen als Dependencies. Wenn der nginx initial gestartet wird, landen all diese Module im RAM und verbleiben für die Laufzeit des Prozesses auch dort. Im Falle eines Reloads werden die Worker-Prozesse des nginx neugestartet, woraufhin sie sich die notwendigen Module neu laden. Der Master bleibt unangetastet, gibt aber natürlich Meta-Informationen an die Worker weiter.

Wenn nun ein nginx-Update ausgerollt wird ändern sich ggf. die Module auf der Festplatte. Da sie aber in RAM liegen, ist das erstmal egal – bis zu einem Reload. Dann laden die Worker ihre Module neu, sind verwirrt und krach-bumms-dependencysalat:

2018/06/06 03:47:13 [error] 7586#7586: *5636697 lua entry thread aborted: runtime error: /usr/local/openresty/lualib/resty/core/base.lua:23: ngx_http_lua_module 0.10.13+ required
stack traceback:
coroutine 0:
        [C]: in function 'require'
        .../local/openresty/luajit/share/lua/5.1/resty/auto-ssl.lua:88: in function 'ssl_certificate'
        ssl_certificate_by_lua:2: in function <ssl_certificate_by_lua:1>, context: ssl_certificate_by_lua*, client: 2a00:d0c0:200:0:b9:1a:9c:57, server: [::]:443

Unschön, aber einfach durch einen einfachen Restart fixbar.

Updates!

In eurem und unseren Sinne rollen wir regelmäßig OS-Updates aus. Da uns das oben geschilderte nginx-Problem bekannt ist, bekommen alle nginxe anschließend einen Restart: HTTPS da ➡️ ihr glücklich ➡️ wir glücklich. Genauso haben wir auch am Abend des 5.6. Updates gemacht.

Ein Kollege hat - ein paar Tage zuvor - einem Testhosts Updates verpasst, den nicht eintretenden Weltuntergang abgewartet und dann schließlich am 5.6. mit dem passenden Ansible-Playbook auf alle Hosts ausgerollt und wie beschrieben den nginx durchgetreten. Monitoring war still, Hosts wirkten gesund und Twitter hatte auch keine Beschwerden zu verzeichnen.

Durch ein unabhängiges Problem mit dem .NET-Repository von Microsoft haben es die Updates allerdings nur auf vier Hosts geschafft: whipple, taylor, kojima und klemola. Genau die vier Ausfallkandidaten.

der tödliche Reload

Aufmerksame Leserinnen können sich nach dem länglichen Intro schon denken, was passiert ist: der nginx-Restart wurde nicht wie geplant ausgeführt und irgendetwas(TM) hat einen Reload getriggert. Gemerkt hat das leider niemand sodass die vier Hosts einfach mal weitergelaufen sind – bis um kurz vor vier Uhr früh.

Genau dann läuft das cron.daily und darin ein Logrotate was für einen – Trommelwirbel – nginx Reload sorgt:

Jun 06 03:47:01 taylor.uberspace.de anacron[20891]: Job `cron.daily' started
Jun 06 03:47:01 taylor.uberspace.de run-parts(/etc/cron.daily)[7429]: starting logrotate
Jun 06 03:47:05 taylor.uberspace.de uberspace-generate-nginx-config[7542]: generating config for pumuckl
Jun 06 03:47:05 taylor.uberspace.de uberspace-generate-nginx-config[7542]: generating config for blargh
(...)
Jun 06 03:47:05 taylor.uberspace.de systemd[1]: Reloaded HTTPS-Frontend (NGINX HTTP and reverse proxy server).

Anschließend war der Webserver nicht mehr motiviert weitere Anfragen für User-Domains (nicht jedoch die taylor.uberspace.de-Domain!) zu beantworten. Da zufällig keiner unserer privaten Uberspaces betroffen war, haben wir das dann auch erst durch Useranfragen gemerkt und dann durch eine pauschale Runde nginx-Restarts behoben.

aber habt ihr denn kein Monitoring?!

Doch, doch, natürlich. Aber leider nur für die taylor.uberspace.de-Domain. Domains, die durch User hinzugefügt werden testen wir vor jedem Deployment und nach jedem Commit automatisiert in unserem GitLab; jedoch nicht mehr auf jedem einzelnen Produktivsystem. So wurden wir erst duch Useranfragen auf das Problem aufmerksam.

Die Zukunft(TM)

Dieser Fehler hat auf 4 Hosts für eine Downtime auf von circa 7 Stunden verursacht. Auch wenn diese Großteils vor in Europa üblichen Wachzeiten war, ist das natürlich inakzeptabel.

Wir haben initial mehrere Maßnahmen getroffen, um solche Fehler in Zukunft zu vermeiden oder zumindst schneller zu bemerken:

  1. Wir werden die technischen Hürden überkommen müssen und ein Monitoring für produktive User-Domains bauen. Dieses hätte uns in diesem Fall aufgeweckt, sodass die Downtime nur Minuten, statt Stunden, betragen hätte.
  2. OS-Updates werden künftig wie normale Uberspace-Updates über GitLab ausgeführt. So ist sichergestellt, dass ein fehlgeschlagenes Update auffällt, klar ist wann Updates gelaufen sind und Logs bleiben nachvollziehbar.

Einer unserer Leitsätze lautet: Haben wir etwas richtig gemacht oder haben wir etwas dazu gelernt? In diesem Fall bitten wir die betroffenen User um Entschuldigung und haben etwas dazu gelernt.