\documentclass[a4paper,11pt]{article} \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} \usepackage{geometry} \usepackage{hyperref} \usepackage{graphicx} \usepackage{longtable} \usepackage{textcomp} \geometry{margin=2.5cm} \title{Service-Portal Architektur} \author{schooltech.ch} \date{\today} \begin{document} \maketitle \section{Zielsetzung} Ziel ist der Aufbau eines zentralen Login- und Navigations-Portals für mehrere unabhängige Web-Services, die in Docker-Containern betrieben werden. Benutzer authentifizieren sich einmal zentral und können anschließend zwischen Services wechseln, die jeweils unter eigenen Subdomains bereitgestellt werden. \section{Architekturübersicht (final)} \subsection{Domänenstruktur} \begin{itemize} \item \texttt{server.schooltech.ch} – Login- und Navigations-Portal (SPA) \item \texttt{.server.schooltech.ch} – einzelne Services (Docker Container) \end{itemize} \subsection{High-Level Architektur} \begin{verbatim} Internet | | HTTPS (*.server.schooltech.ch) v +---------------------+ | Nginx ReverseProxy | | TLS, Auth, Routing | +---------------------+ | | | +--> Service Container (abc) | abc.server.schooltech.ch | +--> Portal / Auth Service server.schooltech.ch \end{verbatim} \subsection{Zentrale Prinzipien} \begin{itemize} \item Ein Einstiegspunkt (Nginx) \item Zentrale Authentifikation (auth\_request) \item Services kennen kein Login \item Keine iFrames, kein Subpath-Rewrite \item Services laufen auf Root-Pfad (\texttt{/}) \end{itemize} \section{Authentifikation (Variante A: auth\_request)} \subsection{Prinzip} Nginx prüft jeden Request zu einem Service mittels \texttt{auth\_request} gegen den Auth-Service. Der Auth-Service entscheidet ausschließlich anhand der Session (Cookie). \subsection{Ablauf} \begin{enumerate} \item Benutzer loggt sich am Portal ein \item Portal setzt Session-Cookie: \begin{verbatim} Domain=.server.schooltech.ch Secure; HttpOnly; SameSite=None \end{verbatim} \item Benutzer ruft Service-Subdomain auf \item Nginx fragt \texttt{/internal/auth} beim Auth-Service an \item Bei Erfolg: Request wird an Service weitergeleitet \end{enumerate} \subsection{Header-Weitergabe} Optional injiziert Nginx folgende Header: \begin{itemize} \item \texttt{X-Remote-User} \item \texttt{X-User-Roles} \end{itemize} \section{Nginx Konfiguration} \subsection{Wildcard Server Block} \begin{verbatim} server { listen 443 ssl; server_name *.server.schooltech.ch; ssl_certificate /etc/letsencrypt/live/server.schooltech.ch/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/server.schooltech.ch/privkey.pem; location / { auth_request /internal/auth; proxy_pass http://$upstream; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location = /internal/auth { proxy_pass http://auth:3000/internal/auth; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header X-Original-URI $request_uri; } } \end{verbatim} \subsection{Upstream Mapping} \begin{verbatim} map $host $upstream { default portal:3000; abc.server.schooltech.ch abc:8080; xyz.server.schooltech.ch xyz:8080; } \end{verbatim} \section{Docker Compose (Übersicht)} \begin{verbatim} version: "3.9" services: nginx: image: nginx:alpine ports: - "443:443" volumes: - ./nginx:/etc/nginx/conf.d - ./certs:/etc/letsencrypt depends_on: - auth - portal networks: - internal auth: image: node:18 command: node auth.js networks: - internal portal: image: node:18 command: node portal.js networks: - internal abc: image: service-abc networks: - internal networks: internal: driver: bridge \end{verbatim} \section{UI-Konzept (Navigations-Portal)} \subsection{Funktion} \begin{itemize} \item Login \item Anzeige verfügbarer Services \item Wechsel per Full Navigation \item Kollabierbare Kopfzeile \item Floating Launcher (Bookmark) \end{itemize} \subsection{UI-Layout} \begin{verbatim} +------------------------------------------------+ | LOGO | Service A | Service B | User | +------------------------------------------------+ | | | Service Overview / Last Service / Status | | | +------------------------------------------------+ \end{verbatim} \subsection{HTML-Prototyp (Portal)} \begin{verbatim} Service Portal
Portal
Service ABC
Service XYZ
\end{verbatim} \subsection{Portal als Docker Container} Das Portal wird als eigener Container betrieben und statisch oder via Node.js ausgeliefert. Es besitzt keine direkte Kopplung zu den Services außer über URLs. \section{Zusammenfassung} Diese Architektur ermöglicht: \begin{itemize} \item saubere Trennung von Portal und Services \item zentrale Sicherheit \item einfache Erweiterbarkeit \item wartbare Reverse-Proxy-Konfiguration \end{itemize} \end{document}