Kong + Konga: Reverse Proxy und SSL Endpoint

Nachdem mir Kong – zusammen mit der Oberfläche Konga – ja direkt sehr interessant vorgekommen ist, „musste“ ich den jetzt unbedingt mal selber ausprobieren. Da ich ja bisher einen Apache als Reverse Proxy für meine diversen „öffentlich“ verfügbaren Services betreibe, lag es nahe, Kong als Ersatz für diesen einzusetzen. Das habe ich nun Schritt für Schritt (Service für Service) getan.

Fazit vorab: Alles läuft noch bzw. wieder – ich bin sehr angetan aber (noch) nicht restlos begeistert.

Grundsätzlich geht es bei Kong immer um folgende Elemente:

  1. Es wird ein Service definiert: Dieser besteht im Kern aus einer internen URL, unter der der Service für Kong erreichbar ist (Upstream). Also z.B. http://meine-wordpress-installation.local/abde/.
  2. Damit ein Service „nach außen“ erreichbar ist, definiert man Routen. Diese besteht im Kern aus der externen URL, über die der Service ansprechbar sein soll. Also z.B. https://nerdblog.steinkopf.net. Ein Service kann auch mehrere Routen haben.
  3. Sowohl an Services, als auch an Routen, als auch global kann man Plugins „hängen“. Diese Plugins können – dann im jeweiligen Kontext – vielfältige Aufgaben erledigen: Von der Authentifizierung und Autorisierung über Request-Transformationen (z.B. Ersetzungen – s.u.) bis hin zu Logging. Eine Liste findet man im Kong Hub. Nicht alle sind kostenlos verfügbar, aber viele 🙂

Ein Eindruck der Konga-Oberfläche.

Hier die interessantesten Beispiele, was ich bei meiner Umstellung auf Kong „erlebt“ habe:

Installation von Kong+Konga mit docker-compose

…war recht einfach. Das Compose-File habe ich mir von hier übernommen und angepasst. Wie es bei mir nun in etwa aussieht, kann man im Anhang sehen (s.u.).

1. Beispiel: WordPress

Meine WordPress-Installation war der „größte Brocken“ – auch schon damals mit dem Apache Reverse Proxy.

Folgende Aspekte spiel(t)en eine Rolle:

1.1 Google Fonts etc.

Schon hier habe ich beschreiben, worum es geht: Die Google-Fonts (und alles was da so dazu gehört…) sollen aus Datenschutzgründen nicht vom User-Browser direkt geladen werden, sondern über meinen Server. Dies soll aber nur von Nutzern der Seite verwendet werden können und nicht beliebig im Internet verlinkbar (=kein „Hotlinking“):

Hinweis: In allen Beispielen habe ich vor die jeweilige Domain ein XX- eingefügt, weil sonst genau der hier beschriebene Ersetzungsmechanismus (s.u.) auch bei der Anzeige (= beim Ausspielen) dieser Beispiele zuschlagen würde.

Umleitung der Requests

Dazu habe ich die entsprechenden Google-URLs als Kong-Service definiert (z.B. https://XX-fonts.gstatic.com. Dann eine Route https://nerdblog.steinkopf.net/fonts.gstatic.com dazu. Läuft.

Referer-Blocking

Wie schon mit dem Apache Proxy möchte ich hier Zugriffe aber nur erlauben, wenn als Referrer meine eigene Site übertragen wird. Das ist keine echte Sicherheit – verhindert aber wirksam, dass die URLs einfach woanders eingebaut werden (Hotlinking).

Im Kong-Umfeld habe ich dafür nichts Passendes gefunden. Daher habe ich „mal schnell“ ein eigenes Kong-Plugin geschrieben. Es heißt ja auf der Kong-Web-Seite, die Plugins seien eine der wesentlichen Stärken von Kong und recht einfach zu implementieren:

Kong Plugin kong-referer-restriction:

Das war wirklich nicht aufwändig und nun existiert es und hat einen einzigen Konfig-Parameter: „allowed referer patterns“, mit dem man (als Lua-Pattern) einstellt, welcher Referer-Header akzeptiert wird. z.B: ^https://nerdblog.steinkopf.net/. Andere (oder ein fehlender) Referer führt zu HTTP Code 403 Forbidden.

1.2 Übersetzung der internen Links in den Antworten

In den Ausgelieferten HTML- und CSS-Responses kommen Links auf den internen Server vor. Dies hatte ich im Apache Reverse Proxy mit mod_substitute gelöst (siehe Kommentar hier). Ich weiß nicht, ob es dafür eine bessere Lösung innerhalb von WordPress gibt – ich habe jedenfalls nie eine gefunden.

Auch hierfür habe ich bei Kong nichts Hilfreiches gefunden. Daher auch hier ein eigenes Plugin von mir:

Kong Plugin kong-response-string-replace

Das war auch nicht wirklich aufwändig und jetzt kann man damit einfache Ersetzungen definieren:

  • Im Body: Regeln der Form PATTERN###REPLACE.
    • z.B. https%:%/%/internal%-server%.local%:8888###https://external-server.my.tld
  • und im Header: Regeln der Form HEADERNAME:PATTERN###REPLACE
    • z.B. Set-Cookie:internal%-server%.local###external-server.my.tld

Sie ersetzen das gesuchte Lua-Pattern (vor den drei ###) durch die Ersetzung (nach den drei ###). Es gilt die Lua-Syntax für Patterns und Ersetzungen.

Außerdem kann im Plugin über den Parameter content_types eingestellt werden, bei welchen Content-Types bzw. URLs die Ersetzung überhaupt stattfinden soll.

Weiteres im Readme auf der Plugin-Seite.

Konfiguration des Kong Plugin kong-response-string-replace in Konga.

2. SSL-Zertifikate von Let’s Encrypt

Kong kann SSL-Terminierung durchführung und Zertifikale speichern, sie aber nicht selber automatisch bei Let’s-Encrypt holen bzw. verlängern. Dies passiert (z.B.) über den „kong-certbot-agent“ (auf docker hub). Dies ist ein Fork, wo ich noch hoffe, dass meine Korrekturen im Pull-Request angenommen werden.

Im compose-File gibt es dazu einen Service-Abschnitt (siehe Anhang).

Die Umgebungsvariable DOMAINS enthält die Liste der zu erstellenden bzw. zu verifizierenden Domains. Damit die Let’s-Encrypt-Verifizierung klappt, muss eine Kong-Route /.well-known/acme-challenge existieren, welche Requests auf den Kong-Certbot-Agent leitet.

2. Weiterleitung von HTTP auf HTTPS

Auch hier ein Plugin (kong-http-to-https-redirect), das von mir erweitert wurde um die Möglichkeit, Ausnahmen zu definieren. Ich habe es als globales Plugin installiert und /.well-known/acme-challenge als Ausnahme. Nun antwortet es auf alle via HTTP hereinkommenen Requests mit 301 Moved Permanently – zusammen mit der auf https umgeschriebenen URL in der Antwort-Location.

3. Logging

Das mache ich über das bestehende Kong-Plugin „tcp-log“, welches die Logs per „gelf“ an mein graylog schickt. Mehr dazu hier demnächst 🙂

4. Security-Header

Diverse SSL-Checker geben einem ja Hinweise, durch welche HTTP-Header in den Responses die Sicherheit der SSL-Webseite zu erhöhen ist. Diese Hinweise lassen sich mit dem vorhandenen Plugin „response transformer“ leicht umsetzen. Es fügt HTTP-Header in den Antworten hinzu – aber nur dann, wenn sie nicht schon (vom Upstream-Service selber) gesetzt wurden. Bei mir sind das z.B. diese:

Strict-Transport-Security: max-age=63072000; preload 
Content-Security-Policy: frame-ancestors 'none' 
X-Frame-Options: DENY 
X-Content-Type-Options: nosniff 
X-XSS-Protection: 1; mode=block 

5. Backup

Natürlich muss auch Kong ge-backup-t werden – also die Konfiguration. Folgende Möglichkeiten nutze ich:

Kong-Backup mit postgres dump

Da Kong alles in einer Datenbank speichert (Postgres oder Kassandra), ist die naheliegende Idee, die gewählte Datenbank zu sichern. Ich habe mich für Postgres entschieden, also mache ich das mit dem Postgres-Standard-Tool pg_dumpall:

#!/bin/bash

eval $(docker-machine env docker-prod)
machinefile="$(dirname $0)/.which-docker-machine"
if [ -r $machinefile ] ; then
    eval $(docker-machine env $(cat $machinefile))
fi

dumpfile_compr=/opt/dockervolumes/kong-ext/postgres-backup/dumpall.pgsql.bz2
docker-compose -f $(dirname $0)/docker-compose.yml exec -T kong-database pg_dumpall -c -U kong | bzip2 >$dumpfile_compr

# check if ok:
if ! bzip2 -dc $dumpfile_compr | tail -3 | grep -q 'dump complete' ; then
    echo >&2 "pg backup failed:"
    bzip2 -dc $dumpfile_compr | tail >&2
    exit 1
fi

exit 0

P.S. Dieser umständliche Check am Ende, ob alles geklappt hat, kommt daher, dass pg_dumpall keinen aussagefähigen Exit-Code liefert – sondern immer 0 🙁

Kong-Backup mit skull-island in JSON

Eine andere Möglichkeit ist, via API alles abzurufen und zu sichern. Dies geht mit skull-island:

skull-island \
    --synch-basic-auth-creds \
    --username kong-ext-api-user \
    --password 'blablabla' \
    --url "$kongurl" \
    backup

Dies hat z.B. den Vorteil, dass man diesen Dump auch gut versioniert speichern kann.
Wiederherstellen geht mit skull-island synchronize.

Allerdings habe ich den Verdacht, dass in diesem Dump nicht alles drin ist, es scheinen Objekt-Typen zu fehlen – einen Restore habe ich noch nicht versucht. Daher verlasse ich mich noch nicht alleine auf dieses Tool.

Kong Backup via kong-config-manager

Ein ähnliches Prinzip verfolgt kong-config-manager. Hier muss man (siehe readme) zunächst in einem JSON-Config-File den (oder die) Server definieren, von denen man die Config verwalten möchte:

root@martiniesrv:/opt/compose# cat /opt/dockervolumes/kong-ext/kong-backup-kcm/kcm-config.json {
  "main": {
    "host": "http://gin-ed4u.steinkopf.net/kong-ext"
  }
}

Nun erstellt kcm dump einen (scheinbar) vollständigen Dump der Kong-Konfiguration. Ich lasse mir das nun nächtlich per Cron dumpen und in ein git-Repo einchecken:

destdir=/opt/dockervolumes/kong-ext/kong-backup-kcm

set -e

cd $destdir

kcm dump

git -C "$destdir" add .
git -C "$destdir" commit -q -m "latest dumped kong changes by backup_kong_kcm.sh" || true
git -C "$destdir" push
Kong-Backup via Snapshot in Konga

Nicht wirklich ein Backup, aber doch hier erwähnenwert ist die Möglichkeit via Konga automatische Snapshots

  • anzulegen,
  • anzuschauen und
  • auf Klick wiederherzustellen.

Fazit

Was mir gefällt:

  • Einfache, stukturierte Konfiguration. Was bisher „durcheinander“ in verschiedenen Apache-Konfig-Files liegt, ist nun alles auf homogene Weise angelegt. Die Plugins spielen dabei tatsächlich eine wichtige Rolle.
  • Schnelle Änderungen durch wenige Klicks. Auch neue SSL-Domains lassen sich dabei sehr einfach anlegen und registrieren.
  • Sehr schnell im Betrieb. Keine messbaren Verzögerungen. Auch die Oberfläche reagiert sehr schnell.
  • Logging passt gut zu zentralem Log-Gedanken via Logging-Server. Auch hier wird nun alles strukturiert und homogen.

Was mir nicht so gefällt:

  • Konfiguration via grafische Oberfläche. Das ist mir oft doch noch zu unübersichtlich und man kann z.B. keine Kommentare hinterlassen.
  • Kein Diff von Änderungen. Versehentliche Änderungen bleiben unbemerkt, wenn sie nicht vom Monitoring aufgedeckt werden. Das Dump-Tool kong-config-manager könnte hier die Lösung sein, dazu brauche ich aber noch etwas mehr Erfahrung im Umgang damit.

Anhang: docker-compose.yml

5 thoughts on “Kong + Konga: Reverse Proxy und SSL Endpoint

  1. Hello Dirik,

    Hope that you are doing well today.

    I recently started to try and use Kong and found that one of the best ways to get going was to use docker-compose for which I now have a version that brings up Kong, Konga, and Postgres but now want to see if I can get a letsencrypt container to fire up as well.

    I am just using a freshly installed Debian 10 sever with Docker and Docker-Compose as an API server and will not have a web server on this machine.

    This research led me to your GitLab posting:

    https://gitlab.steinkopf.net/snippets/7

    The problem that I am having is that after changing the email & domains in the letsencrypt section after which I try to bring it up with „docker-compose up“ for testing, I am getting some errors that seem to be the Postgresql and certbot parts.

    Can you please let me know if you had to do any other preparations or modifications to get this docker-compose.yml to work for you?

    Do I need some other containers running as well?

    I also cleaned out all of the images and containers in my Docker setup so as to have a fresh and clean starting point.

    Any help that you could provide would be greatly appreciated.

    1. I don’t remember if I has to do any preparations at the first startup. I think you should do you startup in seperate steps:

      1. setup + start kong – watch logging until everything runs fine
      2. setup + start konga – watch logging until everything runs fine
      3. setup + start letsencrypt/kong-certbot-agent

      Then you could be a bit more precise about what your error messages are.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert