Architektur-Konzept eines (einfachen und sicheren) CMS-Systems (Entwurf)

 

geposted von lars am 19. Januar 2025

Wer eine Webseite im Internet betreibt, für den gibt es bei der Auswahl des passenden Content Management Systems (CMS) die Qual der Wahl. Es gibt bspw. Typo3. Es gibt das Django-CMS. Solche, ich nenne sie mal CMS-Systeme für den Heimgebrauch, haben aber einige eklatante Design-Schwächen in Sachen Sicherheit. Oder es gibt Enterprise-CMS-Systeme, die schon an eine gute Architektur heranreichen, aber i.d.R. für die "Dackelzüchter-Homepage" wenig erschwinglich sind.

Insofern habe ich mir mal etwas Gedanken über die generelle Architektur gemacht. Und die ist beileibe nicht schwer umsetzbar. Der einzige Haken: Man benötigt mindestens 2 getrennte Server. Die Programmiersprache und die verwendeten Technologien spielen dabei eine untergeordnete Rolle.

Und so könnte eine Architektur eines CMS-Systems (oder einer beliebigen anderen Webseite mit dynamischen Inhalten ausschauen):

Es muss einmal zwingend unterschieden werden zwischen der Publish-Umgebung (also dem Teil, der in der DMZ steht und potentiell von außen angreifbar ist. Oder anders gesagt: Das Frontend!) und der Author-Umgebung (das Backend mit administrativen Zugang).

Und jetzt kommen einige wesentliche Punkte, auf die beim Design geachtet werden sollte:

  • "Source of Truth" (also Quelle der Wahrheit) muss das Backend sein, das niemals und unter keinen Umständen direkt aus dem Internet erreichbar sein darf.
  • Das Frontend sollte skalierbar sein (also durchaus parallel auf mehreren Publish-Instanzen laufen können)
  • Alle Änderungen aus dem Backend in Richtung Frontend dürfen nur in eine Richtung erfolgen. Also auch und insbesondere Firewall-technisch gilt hier das Push-Prinzip von Backend -> Frontend. Also fällt ein synchroner ACKnowledge von den Publishern weg.
  • Da die Frontends durchaus dynamische Inhalte (wie bspw. Formulare, Kunden-Logins, ...) ausliefern können, ist logischerweise eine weitere Pufferzone in Form eines Reverse-Proxy-Servers zu implementieren, der aber der Einfachheit halber durchaus auf demselben Server laufen kann wie die Applikation.
  • Bei einer Umgebung mit mehreren Publishern besteht potentiell ein Sync-Problem: Hier gibt es mehrere Ansätze:
  1. Bei nur geringen Datenmengen ist auch im Frontend eine zentrale (relationale) Datenbank empfehlenswert.
  2. Wenn mit einem dezentralen Ansatz gearbeitet wird, könnte man einen Primary PUBLISHER für die Schreibzugriffe festlegen, der dann das Quorum für die sekundären Publsiher freigibt. Also in etwa so (mit noch einigen Logikfehlern):
    PUBLISHER1 (ist PRIMARY)
    PUBLISHER2 (ist SECONDARY)
    PUBLISHERx (ist SECONDARY)

    Zunächst erfolgt also die Replikation vom Autorensystem, der dann die zurückgegebenen Checksummen auf Gültigkeit prüft. Zusätzlich wird vom Autorensystem ein Quorum-Status mitgegeben (z.B. quorum-check für den primären PUBLISHER und quorum-wait für den sekundären PUBLISHER).

    Beim ersten Aufruf der entsprechenden Seite wird dann auf dem primären PUBLISHER mit dem Status "quorum-check" ebenfalls der Status "quorum-check" auf allen sekundären PUBLISHERN gesetzt. Wenn das auf allen SECONDARIES bestätigt wurde, kann auf dem PRIMARY das "quorum-ok" gesetzt werden und die Seite wäre auf PUBLISHER1 online.

    Damit es aber nicht zu "Site-Flapping" kommt, wären folgende Prüfungen zusätzlich auf den sekundären PUBLISHERN vorzunehmen:
    Beim Status "quroum-wait" (wenn der SECONDARY Publisher bspw. wieder online kommt) muss das Quorum auf ALLEN anderen Publishern geprüft werden. Wenn ein Publisher im Status "quorum-ok" ist, ist das Quorum auch auf "quorum-ok" zu setzen und die Seite anzuzeigen.

    Beim Status "quorum-check", muss noch der Status auf dem PRIMARY geprüft werden. Erst dann kann das Quorum auf "quorum-ok" gesetzt werden und die Seite angezeigt werden. Falls der PRIMARY-Check in einen Timeout läuft, würde der SECONDARY zum (temporären) PRIMARY und setzt das "quorum-check" auf den übrigen SECONDARIES und danach auf sich selber das "quorum-ok". Dann kann auch in diesem Fall (PRIMARY offline) die Seite angezeigt werden.
     
  3. ...
  • Die Architektur sähe also zusammenfassend so aus:
    INTERNTET (DMZ): Reverse Proxy <- PUBLSIHER1 mit lokaler Datenbank (RZ1) <- LAN: AUTHOR1 (RZ1) <- Datenbank-Cluster
                                      PUBLISHER2 mit lokaler Datenbank (RZ1) <- LAN: AUTHOR2 (RZ2)
                                      PUBLISHER3 mit lokaler Datenbank (RZ2)
                                      PUBLISHER4 mit lokaler Datenbank (RZ2)