add synced notes on IT know how
This commit is contained in:
@@ -0,0 +1,358 @@
|
||||
Hier ist eine umfassende Einführung in Argo CD – verständlich, aber fachlich fundiert.
|
||||
|
||||
---
|
||||
|
||||
## 1. Was ist Argo CD?
|
||||
|
||||
Argo CD ist ein **GitOps-Tool** für **Kubernetes**. Es sorgt dafür, dass der Zustand eines Kubernetes-Clusters immer mit dem übereinstimmt, was in einem **Git-Repository** als „Wahrheit“ definiert ist.
|
||||
|
||||
Kerneigenschaften:
|
||||
|
||||
- **Git-zentriert**: Git als Single Source of Truth (Manifest-Dateien, Helm-Charts, Kustomize, etc.)
|
||||
- **Deklarativ**: Der gewünschte Zustand (desired state) ist beschrieben, nicht programmiert
|
||||
- **Kontinuierliche Synchronisierung**: Änderungen in Git werden automatisch oder manuell im Cluster ausgerollt
|
||||
- **Visuell**: Web UI mit Übersicht über Applikationen, Health-Status, Diffs, History
|
||||
- **Mehrcluster-fähig**: Kann mehrere Kubernetes-Cluster verwalten
|
||||
|
||||
---
|
||||
|
||||
## 2. GitOps – der Kontext von Argo CD
|
||||
|
||||
Argo CD implementiert das GitOps-Konzept:
|
||||
|
||||
- **Infrastruktur & Deployments im Git** (Manifest-Dateien, Helm Values, Kustomize Overlays, etc.)
|
||||
- **Pull-basiert**: Argo CD „zieht“ den Zustand regelmäßig aus Git und gleicht ihn mit dem Cluster ab.
|
||||
- **Versioniert & auditiert**: Jede Änderung ist ein Git-Commit, inkl. History, Review, Rollback-Möglichkeit
|
||||
- **Automatisierte Drift-Erkennung**: Unterschiede zwischen Git und Cluster werden erkannt und gemeldet
|
||||
|
||||
Vorteile von GitOps mit Argo CD:
|
||||
|
||||
- Reproduzierbare Deployments
|
||||
- Besseres Change-Management (Git-Workflows, PRs)
|
||||
- Weniger manuelle „[[kubectl]] apply“-Befehle
|
||||
- Klare Trennung von Build (CI) und Deployment (CD)
|
||||
|
||||
---
|
||||
|
||||
## 3. Architektur von Argo CD
|
||||
|
||||
### 3.1 Hauptkomponenten
|
||||
|
||||
- **argocd-server**
|
||||
- Stellt die Web UI und das gRPC/REST-API bereit
|
||||
- Authentifizierung (lokale User, SSO via OIDC, etc.)
|
||||
- Kommunikation mit CLI (`argocd` CLI) und UI
|
||||
|
||||
- **argocd-repo-server**
|
||||
- Greift auf Git-Repositories zu
|
||||
- Rendert Manifeste (z.B. Helm, Kustomize, Jsonnet)
|
||||
- Führt Template-Engines und „Config Management Plugins“ aus
|
||||
|
||||
- **argocd-application-controller**
|
||||
- Herzstück des Sync-Mechanismus
|
||||
- Vergleicht desired state (Git) mit live state (Cluster)
|
||||
- Führt Syncs, Health-Checks und Rollbacks aus
|
||||
|
||||
- **argocd-redis** (optional, in vielen Installationen vorhanden)
|
||||
- Cache für Repositories und Application-Informationen
|
||||
|
||||
Diese Komponenten laufen typischerweise im Namespace `argocd` im Cluster.
|
||||
|
||||
### 3.2 Target Cluster
|
||||
|
||||
Argo CD kann:
|
||||
|
||||
- Den **Cluster, in dem es selbst läuft**, verwalten
|
||||
- **Externe Cluster** (z.B. Staging, Prod) als zusätzliche „Cluster Secrets“ anbinden
|
||||
|
||||
---
|
||||
|
||||
## 4. Zentrale Konzepte
|
||||
|
||||
### 4.1 Application
|
||||
|
||||
Die zentrale Ressource in Argo CD ist eine CRD namens **Application** (`kind: Application`).
|
||||
|
||||
Eine Application beschreibt:
|
||||
|
||||
- **Quelle (source)**: Woher kommen die Manifeste?
|
||||
- Git-Repository / Helm-Repo / Kustomize-Ordner
|
||||
- Pfad im Repo
|
||||
- ggf. Helm-Chart und Values
|
||||
- **Ziel (destination)**:
|
||||
- Zu verwaltender Kubernetes-Cluster
|
||||
- Ziel-Namespace
|
||||
- **Sync-Strategie & -Optionen**:
|
||||
- Automatische Synchronisierung (auto sync) oder manuell
|
||||
- Verhalten bei Fehlern, Prune, Self-Heal etc.
|
||||
|
||||
Ein minimaler `Application`-Beispiel (vereinfachtes YAML):
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: my-app
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/mein-org/mein-repo.git
|
||||
targetRevision: main
|
||||
path: kubernetes/my-app
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: my-app
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
```
|
||||
|
||||
### 4.2 Sync-Status & Health-Status
|
||||
|
||||
Für jede Application zeigt Argo CD zwei wesentliche Zustände:
|
||||
|
||||
- **Sync-Status**:
|
||||
- `Synced`: Cluster-Zustand entspricht Git-Zustand
|
||||
- `OutOfSync`: Unterschiede zwischen Git und Cluster
|
||||
- **Health-Status**:
|
||||
- `Healthy`: Anwendung läuft wie erwartet (z.B. alle Pods bereit)
|
||||
- `Degraded`: Fehlerzustände (CrashLoop, fehlende Ressourcen etc.)
|
||||
- `Progressing`: Deployment läuft noch, noch nicht stabil
|
||||
|
||||
Health-Checks sind ressourcentyp-spezifisch (Deployments, StatefulSets, CRDs etc.).
|
||||
|
||||
### 4.3 Drift-Erkennung
|
||||
|
||||
Argo CD vergleicht:
|
||||
|
||||
- **Desired state**: Manifeste, die aus Git gerendert wurden
|
||||
- **Live state**: Tatsächliche Ressourcen im Cluster
|
||||
|
||||
Wenn jemand manuell `kubectl apply` oder `kubectl edit` verwendet, entsteht „Drift“. Argo CD:
|
||||
|
||||
- Markiert den Status als `OutOfSync`
|
||||
- Kann bei `selfHeal: true` diese Änderungen automatisch wieder rückgängig machen (zurück auf Git-Zustand)
|
||||
|
||||
---
|
||||
|
||||
## 5. Unterstützte Werkzeuge & Formate
|
||||
|
||||
Argo CD unterstützt u.a.:
|
||||
|
||||
- **Plain YAML-Manifeste**
|
||||
- **Helm** (Charts, Values)
|
||||
- **Kustomize**
|
||||
- **Jsonnet**
|
||||
- **Ksonnet (legacy)**
|
||||
|
||||
Außerdem:
|
||||
|
||||
- **Config Management Plugins (CMP)**: Eigene Tools/Pipelines zum Manifest-Rendering integrierbar
|
||||
- **Multiple Sources**: Neuere Versionen unterstützen mehrere Quellen pro Application (z.B. App-Manifeste + separate Helm-Values)
|
||||
|
||||
---
|
||||
|
||||
## 6. Installation & erste Schritte
|
||||
|
||||
### 6.1 Installation
|
||||
|
||||
Typische Wege:
|
||||
|
||||
- **kubectl apply** eines offiziellen Install-Manifests:
|
||||
- z.B. `https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml`
|
||||
- **Helm-Chart** (empfohlen für produktivere Setups)
|
||||
- **Operator-Lösungen** in manchen Distributionen
|
||||
|
||||
Nach der Installation:
|
||||
|
||||
- Argo CD läuft im Namespace `argocd`
|
||||
- UI via `argocd-server` (LoadBalancer, Ingress oder Port-Forward)
|
||||
- Erstlogin meist über das Passwort aus dem `argocd-initial-admin-secret`
|
||||
|
||||
### 6.2 CLI
|
||||
|
||||
Das CLI-Tool `argocd` erlaubt:
|
||||
|
||||
- Login: `argocd login <server>`
|
||||
- Erstellung von Applications: `argocd app create ...`
|
||||
- Manuelles Syncen: `argocd app sync my-app`
|
||||
- Status anzeigen, Diffs, Rollbacks etc.
|
||||
|
||||
---
|
||||
|
||||
## 7. Deployment-Strategien & Sync-Policies
|
||||
|
||||
### 7.1 Manuelles vs. automatisches Syncen
|
||||
|
||||
- **Manuell**:
|
||||
- Änderungen in Git werden erkannt, aber nur als `OutOfSync` markiert
|
||||
- Deploy erfolgt erst nach `argocd app sync` (CLI/UI)
|
||||
- **Automatisch (auto sync)**:
|
||||
- Argo CD führt bei Änderungen in Git automatisch ein Sync aus
|
||||
- Option `prune` entfernt Ressourcen, die in Git gelöscht wurden
|
||||
- Option `selfHeal` korrigiert Drift im Cluster
|
||||
|
||||
### 7.2 Sync-Optionen
|
||||
|
||||
- **Sync-Wellen (Sync Waves)**:
|
||||
- Steuerung der Reihenfolge via `argocd.argoproj.io/sync-wave` Annotation
|
||||
- **Sync-Hooks**:
|
||||
- Vor-/Nachschaltbare Hooks (`PreSync`, `PostSync`, `SyncFail` etc.)
|
||||
- Realisiert mit bestimmten Kubernetes-Resourcen und Annotationen
|
||||
|
||||
---
|
||||
|
||||
## 8. Projekte (AppProjects) & Multi-Tenancy
|
||||
|
||||
Die CRD **AppProject** erlaubt die logische Gruppierung und Begrenzung von Applications.
|
||||
|
||||
Funktionen von AppProjects:
|
||||
|
||||
- Einschränkung von:
|
||||
- Erlaubten Git-Repositories
|
||||
- Erlaubten Ziel-Cluster / Namespaces
|
||||
- Erlaubten Ressourcentypen
|
||||
- Gemeinsame Policies & RBAC für eine Gruppe von Apps
|
||||
- Sinnvoll für **Multi-Tenancy**:
|
||||
- z.B. ein Project pro Team, Produkt oder Mandant
|
||||
|
||||
---
|
||||
|
||||
## 9. Sicherheit & RBAC
|
||||
|
||||
### 9.1 Authentifizierung
|
||||
|
||||
- Lokale Benutzer in Argo CD (Admin, weitere User)
|
||||
- Single Sign-On via:
|
||||
- OIDC (z.B. Keycloak, Dex, Azure AD, Okta)
|
||||
- SAML (über OIDC-Integrationen)
|
||||
- Tokens für Automatisierung (CI-Systeme, Bots)
|
||||
|
||||
### 9.2 Autorisierung (RBAC)
|
||||
|
||||
Argo CD hat ein eigenes RBAC-System:
|
||||
|
||||
- Rollen (z.B. `role:readonly`, `role:admin`, benutzerdefinierte Rollen)
|
||||
- Zuordnung von Rollen zu Subjekten (User, Gruppen)
|
||||
- Rechte auf:
|
||||
- Anwendungen (lesen, syncen, löschen)
|
||||
- Projekte
|
||||
- Cluster, Repos
|
||||
- Granulare Steuerung:
|
||||
- z.B. „Team A darf nur Apps in Project X syncen“
|
||||
|
||||
---
|
||||
|
||||
## 10. Typische Patterns: App-of-Apps & Monorepo/Multirepo
|
||||
|
||||
### 10.1 App-of-Apps Pattern
|
||||
|
||||
Ein häufiges Muster ist die **„Application of Applications“**:
|
||||
|
||||
- Eine „Root-Application“, deren Manifeste nur aus anderen `Application`-Ressourcen bestehen
|
||||
- Diese Root-App definiert alle anderen Applikationen/Umgebungen
|
||||
- Vorteile:
|
||||
- Zentrales Entry-Point
|
||||
- Environments (dev/stage/prod) als Under-Apps
|
||||
- Bessere Struktur bei vielen Services
|
||||
|
||||
### 10.2 Repository-Strukturen
|
||||
|
||||
- **Monorepo**:
|
||||
- Alle Manifeste aller Services und Environments in einem Git-Repo
|
||||
- **Multirepo**:
|
||||
- Pro Service oder Team ein eigenes Repo
|
||||
- Infrastruktur/Plattform in separaten Repos
|
||||
- Argo CD unterstützt beide Modelle – Entscheidung ist organisatorisch/architektonisch.
|
||||
|
||||
---
|
||||
|
||||
## 11. Integration in CI/CD-Pipelines
|
||||
|
||||
Argo CD übernimmt in einem klassischen Setup die **CD-Rolle**:
|
||||
|
||||
- CI-Pipeline (z.B. GitLab CI, GitHub Actions, Jenkins):
|
||||
- Buildet Container-Images
|
||||
- Pusht Images in ein Registry
|
||||
- Aktualisiert Versionsnummern/Tags in den Git-Manifesten (Deployment-Repo)
|
||||
- Argo CD:
|
||||
- Erkennt Änderungen im Git-Repo
|
||||
- Deployt diese in den Cluster
|
||||
|
||||
Dadurch entsteht eine klare Trennung:
|
||||
|
||||
- CI = Builds, Tests, Image-Erzeugung
|
||||
- CD = Versionswechsel im Git + Argo CD Sync
|
||||
|
||||
---
|
||||
|
||||
## 12. Monitoring & Observability
|
||||
|
||||
- Argo CD bietet:
|
||||
- Events & Logs (Application-Controller, Repo-Server etc.)
|
||||
- Metriken (Prometheus-Exporter) für:
|
||||
- Anzahl Apps, Sync-Status, Health
|
||||
- Dauer von Syncs
|
||||
- Fehler, Retries
|
||||
- Integration mit:
|
||||
- **Prometheus/Grafana** (Dashboards für Argo CD)
|
||||
- Alerting auf Drift, Degradation, Sync-Fehler
|
||||
|
||||
---
|
||||
|
||||
## 13. Best Practices
|
||||
|
||||
Einige bewährte Vorgehensweisen:
|
||||
|
||||
1. **Git als einzige Wahrheit**
|
||||
- Keine manuellen Änderungen via `kubectl` in produktiven Namespaces
|
||||
2. **Automatisches Syncen mit Self-Heal** (mindestens in lower Environments)
|
||||
3. **Trennung von Image-Build-Repo und Deployment-Repo**
|
||||
4. **AppProjects pro Team/Domain** zur Strukturierung und Begrenzung
|
||||
5. **RBAC sauber definieren**:
|
||||
- Admin-Rechte nur für wenige
|
||||
- Team-spezifische Rollen
|
||||
6. **Health-Konfigurationen pflegen**:
|
||||
- Custom Health Checks für eigene CRDs, falls nötig
|
||||
7. **Klare Namenskonventionen** für Applications, Projekte und Repos
|
||||
8. **App-of-Apps** für große Landschaften:
|
||||
- z.B. `cluster-bootstrap` Application, die alle anderen Apps initialisiert
|
||||
|
||||
---
|
||||
|
||||
## 14. Typische Fallstricke
|
||||
|
||||
- **Drift durch manuelle Änderungen**:
|
||||
- Ursache für OutOfSync und schwer zu reproduzierende Zustände
|
||||
- **Fehlerhafte oder komplexe Helm-/Kustomize-Setups**:
|
||||
- Render-Probleme im Repo-Server bei sehr komplexen Konfigurationen
|
||||
- **Unzureichende Rechte im Ziel-Cluster**:
|
||||
- Argo CD-Service-Account braucht passende RBAC-Rechte
|
||||
- **Netzwerk-/Firewall-Probleme**:
|
||||
- Argo CD muss das Git-Repo erreichen können (Proxy, SSL, SSH-Keys)
|
||||
- **Stateful-Migrationen**:
|
||||
- Vorsicht bei Datenbank-Migrationen im Sync-Prozess (Hook-Jobs, Migrationsphasen)
|
||||
|
||||
---
|
||||
|
||||
## 15. Argo CD vs. andere GitOps-Tools (z.B. Flux)
|
||||
|
||||
Kurzvergleich zu **Flux** (ein anderes populäres GitOps-Tool):
|
||||
|
||||
- **Argo CD**:
|
||||
- Sehr starke, moderne **UI**
|
||||
- Klare Application-Entität
|
||||
- Häufig intuitiv für Teams, die visuelle Steuerung wünschen
|
||||
- **Flux**:
|
||||
- Sehr „Kubernetes-native“, keine eigene zentrale UI (oft mit zusätzlicher UIs wie Weave GitOps)
|
||||
- Stärker über CRDs und CLI gesteuert, weniger „zentrales“ Dashboard
|
||||
|
||||
Beide implementieren GitOps; die Wahl hängt oft von:
|
||||
|
||||
- UI-Bedarf
|
||||
- Präferenzen des Teams
|
||||
- Vorhandenen Ökosystem-Komponenten
|
||||
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
Im IT-Kontext bedeutet **Ingress** allgemein:
|
||||
> „Eingehender Datenverkehr in ein System, Netzwerk oder einen Dienst.“
|
||||
|
||||
Je nach Kontext wird der Begriff etwas unterschiedlich verwendet:
|
||||
# Allgemein
|
||||
|
||||
### 1. Netzwerk / Security
|
||||
|
||||
In klassischen Netzwerken und Firewalls unterscheidet man:
|
||||
|
||||
- **Ingress-Traffic**: Datenverkehr, der **von außen nach innen** in ein Netzwerk oder System hineinkommt
|
||||
(z. B. HTTP-Anfragen aus dem Internet an Ihren Webserver).
|
||||
- **Egress-Traffic**: Datenverkehr, der **von innen nach außen** geht
|
||||
(z. B. Ihr Server ruft eine externe API im Internet auf).
|
||||
|
||||
Typische Themen rund um Ingress in diesem Kontext:
|
||||
- **Ingress-Filterung**: Regeln, die festlegen, welcher eingehende Traffic erlaubt ist (z. B. Firewall-Regeln).
|
||||
- **Ingress-Schutz**: Maßnahmen gegen Angriffe von außen (DDoS-Schutz, WAF, Rate Limiting).
|
||||
|
||||
### 2. Kubernetes (Spezialfall „Ingress“ Resource)
|
||||
|
||||
In Kubernetes ist **Ingress** ein eigener Begriff und bezeichnet eine **API-Ressource**, die regelt, wie externe Requests in den Cluster hinein zu den internen Services geleitet werden.
|
||||
|
||||
Kurz gesagt:
|
||||
- Ein **Ingress** ist eine Art **Reverse Proxy / Routing-Regel** auf Layer 7 (HTTP/HTTPS).
|
||||
- Er definiert z. B.:
|
||||
- Welche Domain (`host`) auf welchen Service zeigt
|
||||
- Welche Pfade (`/api`, `/app`) zu welchen Services geroutet werden
|
||||
- SSL/TLS-Termination (HTTPS)
|
||||
|
||||
Beispielhafte Ingress-Definition in Kubernetes:
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: my-app-ingress
|
||||
spec:
|
||||
rules:
|
||||
- host: myapp.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /api
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: my-api-service
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
Hier sorgt der Ingress dafür, dass Anfragen an `https://myapp.example.com/api` in den Cluster gehen und beim Service `my-api-service` landen.
|
||||
|
||||
---
|
||||
|
||||
Im Kubernetes-Kontext ist „Ingress“ etwas spezieller als nur „eingehender Traffic“. Es gibt drei eng zusammenhängende Dinge:
|
||||
|
||||
1. **Ingress-Ressource** (YAML-Objekt, das Routing-Regeln beschreibt)
|
||||
2. **Ingress-Controller** (Software/Pod, der diese Regeln umsetzt)
|
||||
3. **(Optional) IngressClass** (welcher Controller für welches Ingress zuständig ist)
|
||||
|
||||
Ich gehe der Reihe nach durch.
|
||||
|
||||
---
|
||||
# Kubernetes
|
||||
## 1. Warum braucht man Ingress überhaupt?
|
||||
|
||||
Ohne Ingress hast du im Wesentlichen drei Möglichkeiten, Dienste nach außen verfügbar zu machen:
|
||||
|
||||
- `ClusterIP` (Standard): nur intern im Cluster erreichbar
|
||||
- `NodePort`: öffnet einen Port auf jedem Node; eher low-level / unkomfortabel
|
||||
- `LoadBalancer`: Cloud-Loadbalancer vor einem Service (oft pro Service ein eigener LB)
|
||||
|
||||
Nachteile:
|
||||
- Viele externe IPs / Loadbalancer, wenn du viele Services hast
|
||||
- Keine zentrale Layer‑7-Logik (z. B. Routing per Hostname/URL-Pfad, TLS-Termination)
|
||||
|
||||
**Ingress** löst genau das:
|
||||
|
||||
> Ein (oder wenige) externe Einstiegspunkte, die per Hostname und Pfad auf viele interne Services routen können, inkl. HTTPS/TLS, Auth, Rate-Limiting (je nach Controller).
|
||||
|
||||
---
|
||||
|
||||
## 2. Ingress-Ressource (das YAML-Objekt)
|
||||
|
||||
Die Ingress-Ressource beschreibt **Deklarativ**, wie Anfragen von außen zu Services im Cluster geroutet werden sollen:
|
||||
|
||||
- Auf Basis von **Hostname** (`host`, z. B. `api.example.com`)
|
||||
- Auf Basis von **Pfad** (`path`, z. B. `/api`, `/app`)
|
||||
- Verknüpft mit einem **Backend-Service** (`Service` + Port)
|
||||
- Optional: **TLS**-Konfiguration (Zertifikate)
|
||||
|
||||
Beispiel:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: my-app-ingress
|
||||
namespace: default
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- myapp.example.com
|
||||
secretName: myapp-tls-secret
|
||||
rules:
|
||||
- host: myapp.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /api
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: my-api-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /app
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: my-frontend-service
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
Was hier passiert:
|
||||
|
||||
- Alle Anfragen an `https://myapp.example.com/api...` → Service `my-api-service`
|
||||
- Alle Anfragen an `https://myapp.example.com/app...` → Service `my-frontend-service`
|
||||
- TLS-Zertifikat liegt in `Secret myapp-tls-secret`
|
||||
- `ingressClassName: nginx` sagt: „Dieser Ingress ist für den Ingress-Controller mit Klasse `nginx` gedacht“
|
||||
|
||||
Wichtige Felder:
|
||||
|
||||
- `rules[].host`: auf welchen Host gilt die Regel?
|
||||
- `rules[].http.paths[].path`: URL-Pfad
|
||||
- `pathType`:
|
||||
- `Prefix` → „beginnt mit diesem Pfad“
|
||||
- `Exact` → „genau dieser Pfad“
|
||||
- (früher gab es noch `ImplementationSpecific`)
|
||||
- `backend.service.name` / `port`: zu welchem Service leiten?
|
||||
|
||||
---
|
||||
|
||||
## 3. Ingress-Controller (die „Engine“ dahinter)
|
||||
|
||||
Die YAML-Ressource alleine macht noch nichts. Es braucht einen **Ingress-Controller**:
|
||||
|
||||
- Läuft als Pod/Deployment im Cluster
|
||||
- Beobachtet (watch) Ingress-Ressourcen im API-Server
|
||||
- Übersetzt die Regeln in eine konkrete Konfiguration (z. B. [[NGINX]], Envoy, Traefik …)
|
||||
- Lauscht auf einem (oder mehreren) Node-Ports/LoadBalancer-IPs und routet Traffic in die passende Services
|
||||
|
||||
Typische Implementierungen:
|
||||
|
||||
- **[[NGINX]] Ingress Controller**
|
||||
- **Traefik**
|
||||
- **HAProxy Ingress**
|
||||
- **Envoy-basierte** Controller
|
||||
- Cloud-spezifische:
|
||||
- GCE/GLBC (GKE HTTP(S) Load Balancing)
|
||||
- AWS ALB Ingress Controller
|
||||
- Azure Application Gateway Ingress
|
||||
|
||||
Wichtig:
|
||||
Du kannst mehrere Ingress-Controller im Cluster haben, z. B. einen für öffentliche, einen für interne Services.
|
||||
|
||||
---
|
||||
|
||||
## 4. IngressClass (Zuordnung Controller ↔ Ingress)
|
||||
|
||||
Mit `IngressClass` kann man genau definieren, **welcher** Ingress-Controller für welche Ingress-Ressourcen zuständig ist.
|
||||
|
||||
Beispiel IngressClass:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: IngressClass
|
||||
metadata:
|
||||
name: nginx
|
||||
spec:
|
||||
controller: k8s.io/ingress-nginx
|
||||
```
|
||||
|
||||
Im Ingress verknüpfst du das mit:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
# ...
|
||||
```
|
||||
|
||||
Somit:
|
||||
|
||||
- Nur der Ingress-Controller, der sich als `k8s.io/ingress-nginx` registriert, reagiert auf diesen Ingress.
|
||||
- Andere Controller ignorieren ihn.
|
||||
|
||||
Früher wurde das oft über **Annotations** geregelt (`kubernetes.io/ingress.class`), `ingressClassName` ist der neuere, bevorzugte Weg.
|
||||
|
||||
---
|
||||
|
||||
## 5. Request-Flow: Wie läuft eine Anfrage technisch?
|
||||
|
||||
Typischer Ablauf (z. B. mit [[NGINX]] Ingress Controller in einer Cloud):
|
||||
|
||||
1. Benutzer ruft im Browser `https://myapp.example.com/api/users` auf.
|
||||
2. DNS zeigt `myapp.example.com` auf die externe IP eines Cloud-Loadbalancers.
|
||||
3. Der Cloud-Loadbalancer leitet die Anfrage an einen Node/Port, auf dem der Ingress-Controller erreichbar ist.
|
||||
4. Der Ingress-Controller (Pod) erhält die HTTP(S)-Anfrage.
|
||||
5. Er vergleicht Host (`myapp.example.com`) und Pfad (`/api/users`) mit seinen Ingress-Regeln:
|
||||
- Host passt zu `myapp.example.com`
|
||||
- Pfad passt zum Prefix `/api`
|
||||
6. Er leitet die Anfrage intern an den Kubernetes-Service `my-api-service:80` weiter.
|
||||
7. Kubernetes-Service verteilt die Anfrage per kube-proxy/IPVS/iptables auf einen Pod (`my-api`-Pod).
|
||||
8. Antwort geht den Weg zurück und landet beim Benutzer.
|
||||
|
||||
---
|
||||
|
||||
## 6. Typische Features (Controller-abhängig)
|
||||
|
||||
Je nach Ingress-Controller gibt es zusätzliche Möglichkeiten, meist über **Annotations** oder spezifische CRDs:
|
||||
|
||||
- **TLS-Termination** und optional TLS-Passthrough
|
||||
- **HTTP → HTTPS Redirect**
|
||||
- **Path-Rewrites**, z. B. `/api` außen → `/` im Backend
|
||||
- **Authentifizierung** (z. B. OAuth2, Basic Auth)
|
||||
- **Rate Limiting**, IP-Whitelist/Blacklist
|
||||
- **Canary-Deployments / Traffic-Splitting**
|
||||
- **gRPC-Support**, WebSockets, etc.
|
||||
|
||||
Beispiel (nginx Spezifische Annotation für Redirect):
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Grenzen von Ingress & Gateway API
|
||||
|
||||
Die klassische Ingress-API ist bewusst relativ simpel (Host, Pfad, Backend, TLS).
|
||||
Für komplexere Szenarien (multi-tenant, umfangreiche Routing-Logik, mehrere Gateways) gibt es inzwischen die **Gateway API** (Ressourcen wie `Gateway`, `HTTPRoute` etc.), die Ingress langfristig ergänzen/teilweise ablösen soll.
|
||||
|
||||
Dennoch ist Ingress aktuell (2024) in vielen Clustern der Standardweg, HTTP/HTTPS-Traffic von außen hereinzubringen.
|
||||
|
||||
---
|
||||
|
||||
Wenn du möchtest, kann ich als Nächstes:
|
||||
|
||||
- ein konkretes Setup „von Null an“ durchgehen (z. B. Minikube + [[NGINX]] Ingress + Beispiel-App), oder
|
||||
- spezifisch auf Annotations/Features eines bestimmten Ingress-Controllers eingehen (etwa nginx oder Traefik).
|
||||
@@ -0,0 +1,427 @@
|
||||
Ein JSON Web Token (JWT) wirkt am Anfang oft etwas „magisch“. Wenn man es einmal verstanden hat, ist es aber ein relativ simples Baustein-konzept für Authentifizierung und Autorisierung in modernen Web‑ und API‑Systemen.
|
||||
|
||||
Ich gehe Schritt für Schritt durch:
|
||||
|
||||
1. Grundidee: Was ist ein JWT?
|
||||
2. Aufbau eines JWT
|
||||
3. Abgrenzung zu verwandten Konzepten
|
||||
4. Welche Probleme werden mit JWT gelöst?
|
||||
5. Typische Anwendungsfälle (praxisnah erklärt)
|
||||
6. Herausforderungen und Fallstricke
|
||||
7. Kurz-Fazit
|
||||
|
||||
---
|
||||
|
||||
## 1. Grundidee: Was ist ein JWT?
|
||||
|
||||
**Definition (vereinfacht):**
|
||||
|
||||
Ein **JWT (JSON Web Token)** ist ein **kompakter, URL-tauglicher, digital signierter Datenblock**, der Informationen über einen Benutzer oder eine Aktion enthält (z.B. „Benutzer X ist eingeloggt und hat Rolle admin“).
|
||||
Diese Informationen sind im JSON-Format strukturiert und werden mit einem kryptografischen Verfahren signiert (und optional verschlüsselt).
|
||||
|
||||
Damit kann ein Server (oder mehrere Server) **prüfen**, ob das Token:
|
||||
- von einem vertrauenswürdigen Aussteller stammt,
|
||||
- nicht manipuliert wurde,
|
||||
- noch gültig ist (nicht abgelaufen).
|
||||
|
||||
Man kann sich einen JWT grob als „fälschungssichereren Ausweis“ für Benutzer (oder Clients) vorstellen, der vom Server ausgestellt wird und den der Client bei weiteren Anfragen vorzeigt.
|
||||
|
||||
---
|
||||
|
||||
## 2. Aufbau eines JWT
|
||||
|
||||
Ein JWT besteht aus **drei Teilen**, jeweils Base64URL-kodiert, durch Punkte getrennt:
|
||||
|
||||
```text
|
||||
HEADER.PAYLOAD.SIGNATURE
|
||||
```
|
||||
|
||||
Ein Beispiel (gekürzt, sieht in der Praxis ähnlich aus):
|
||||
|
||||
```text
|
||||
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
|
||||
.
|
||||
eyJzdWIiOiIxMjM0NTYiLCJlbWFpbCI6Im1heC5tdXN0ZXJAbWFpbC5jb20iLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE3MzAxNjkzNDN9
|
||||
.
|
||||
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
|
||||
```
|
||||
|
||||
### 2.1 Header
|
||||
|
||||
Der Header beschreibt u.a.:
|
||||
- welches Signaturverfahren genutzt wird,
|
||||
- dass es sich um ein JWT handelt.
|
||||
|
||||
Beispiel:
|
||||
|
||||
```json
|
||||
{
|
||||
"alg": "HS256", // Algorithmus: HMAC-SHA256
|
||||
"typ": "JWT"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Payload (Claims)
|
||||
|
||||
Die Payload enthält die eigentlichen Informationen („Claims“).
|
||||
Beispiele:
|
||||
|
||||
```json
|
||||
{
|
||||
"sub": "123456", // subject: Benutzer-ID
|
||||
"email": "max.mustermann@example.com",
|
||||
"role": "admin",
|
||||
"iat": 1730169334, // issued at (Unix-Timestamp)
|
||||
"exp": 1730172934, // expiry: Ablaufzeitpunkt
|
||||
"iss": "https://auth.meine-app.de", // issuer
|
||||
"aud": "https://api.meine-app.de" // audience
|
||||
}
|
||||
```
|
||||
|
||||
Wichtige Standard-Claims (nicht verpflichtend, aber üblich):
|
||||
- `iss` – Issuer (Wer hat das Token ausgestellt?)
|
||||
- `sub` – Subject (Auf wen bezieht sich das Token? z.B. Benutzer-ID)
|
||||
- `aud` – Audience (Für welche Anwendung/Services ist das Token bestimmt?)
|
||||
- `exp` – Expiration Time (Wann läuft das Token ab?)
|
||||
- `iat` – Issued At (Wann wurde es ausgestellt?)
|
||||
- `nbf` – Not Before (Ab wann ist es gültig?)
|
||||
|
||||
Dazu kommen **anwendungsspezifische Claims**, z.B.:
|
||||
- `email`, `username`
|
||||
- `roles`: `["admin", "user"]`
|
||||
- `scope`: `"read:orders write:orders"`
|
||||
|
||||
### 2.3 Signature
|
||||
|
||||
Die Signatur wird aus dem Header + Payload + einem Geheimnis (oder Schlüssel) gebildet.
|
||||
Formel grob:
|
||||
|
||||
```text
|
||||
signature = Sign( base64Url(header) + "." + base64Url(payload), secret_or_private_key )
|
||||
```
|
||||
|
||||
Beim Prüfen:
|
||||
- rekonstruiert der Server diese Signatur aus Header+Payload,
|
||||
- vergleicht sie mit der Signatur im Token,
|
||||
- wenn sie übereinstimmen → Token wurde nicht manipuliert.
|
||||
|
||||
---
|
||||
|
||||
## 3. Abgrenzung zu verwandten Begriffen
|
||||
|
||||
### 3.1 JWT vs klassische Session-Cookies
|
||||
|
||||
**Klassische Session:**
|
||||
- Nach Login erzeugt der Server eine **Session-ID** und speichert alle Infos (Benutzer, Rollen usw.) **im Server-Speicher** (in Memory, Redis, DB).
|
||||
- Die Session-ID wird im Browser z.B. als Cookie gespeichert.
|
||||
- Bei jeder Anfrage sendet der Browser die Session-ID; Server schaut im eigenen Speicher nach, welche Daten dazu gehören.
|
||||
|
||||
**JWT:**
|
||||
- Nach Login erzeugt der Server ein **Token**, das die Infos (Benutzer, Rollen, Ablaufzeit) **direkt im Token** enthält.
|
||||
- Das Token wird typischerweise im Browser (Cookie oder Speicher der App) gehalten.
|
||||
- Bei jeder Anfrage schickt der Client das Token mit (z.B. via HTTP-Header `Authorization: Bearer <token>`).
|
||||
- Der Server liest und prüft das Token, braucht aber keinen Session-Speicher.
|
||||
|
||||
Kurz:
|
||||
|
||||
- Session: **zustandsbehaftet (stateful)** auf Server-Seite.
|
||||
- JWT: **zustandslos (stateless)** auf Server-Seite.
|
||||
|
||||
### 3.2 JWT vs OAuth2 / OpenID Connect
|
||||
|
||||
- **OAuth2** ist ein **Protokoll für Autorisierung** (wer darf was). Es definiert Flows, Rollen (Client, Resource Owner, Authorization Server, Resource Server) etc.
|
||||
- **OpenID Connect (OIDC)** baut auf OAuth2 auf und regelt **Authentifizierung** (wer bist du) inklusive ID-Token.
|
||||
|
||||
JWT ist hier eher ein **Datenformat**:
|
||||
- In OAuth2/OIDC werden oft **Access Tokens** und **ID Tokens** als JWT umgesetzt.
|
||||
- Aber OAuth2/OIDC kann theoretisch auch andere Tokenformate verwenden.
|
||||
|
||||
**Merksatz:**
|
||||
OAuth2 / OIDC = das Protokoll;
|
||||
JWT = ein mögliches Format für die Tokens.
|
||||
|
||||
### 3.3 JWT vs JWS / JWE
|
||||
|
||||
- **JWS (JSON Web Signature)**: Standard für signierte JSON-Daten.
|
||||
- **JWE (JSON Web Encryption)**: Standard für verschlüsselte JSON-Daten.
|
||||
|
||||
Ein **typisches JWT ist ein JWS**: signiert, aber nicht verschlüsselt.
|
||||
Es gibt aber auch **JWTs als JWE**: zusätzlich verschlüsselt (seltener in der Praxis).
|
||||
|
||||
Wichtig:
|
||||
**Signiert heißt: Integrität und Echtheit** (nicht manipuliert, vom richtigen Aussteller),
|
||||
**nicht automatisch: Geheimhaltung**.
|
||||
Payload ist bei normalen JWTs **lesbar**, auch wenn sie signiert sind.
|
||||
|
||||
### 3.4 JWT vs API-Schlüssel (API Key)
|
||||
|
||||
- Ein **API-Key** ist meist ein zufälliger String, der einen Client identifiziert.
|
||||
Logik: „Wer den Key kennt, darf die API nutzen.“
|
||||
- Ein **JWT** enthält strukturierte Informationen (Claims) und ist signiert, so dass man viele Details im Token selbst hat (Benutzer, Rollen, Ablauf).
|
||||
|
||||
JWT ist in der Regel **ausdrucksstärker** und besser integrierbar in komplexe Auth-Zusammenhänge; ein API-Key ist eher „simple Zugriffskarte“.
|
||||
|
||||
### 3.5 JWT vs SAML
|
||||
|
||||
- **SAML** ist ein älterer Standard für Single Sign-On (SSO), benutzt XML statt JSON.
|
||||
- JWT (bzw. OIDC mit JWT) ist moderner, leichtergewichtig, JSON-basiert.
|
||||
|
||||
Viele moderne Anwendungen bevorzugen OIDC + JWT statt SAML, vor allem im Web-/API-Bereich.
|
||||
|
||||
---
|
||||
|
||||
## 4. Welche Probleme werden mit JWT gelöst?
|
||||
|
||||
### 4.1 Skalierbare Authentifizierung in verteilten Systemen
|
||||
|
||||
Problem:
|
||||
- Klassische Sessions erfordern zentralen Server-Speicher (Session Store).
|
||||
- In modernen Microservice-Architekturen und skalierenden Web-Apps (viele Instanzen) ist das unpraktisch.
|
||||
|
||||
JWT-Lösung:
|
||||
- **Zustandslose Tokens**: Jeder Service kann das Token **selbst verifizieren**, ohne zentralen Session Store.
|
||||
- Mehrere Instanzen, mehrere Services, sogar andere Systeme (Partner-APIs) können mit dem gleichen Token arbeiten, solange sie den Signaturschlüssel kennen (oder das zugehörige Public Key).
|
||||
|
||||
### 4.2 Einfache Weitergabe von Benutzerinformationen
|
||||
|
||||
Problem:
|
||||
- Mehrere Services müssen wissen, wer der Benutzer ist und welche Rechte er hat.
|
||||
- Man möchte nicht jedes Mal eine zusätzliche Datenbankabfrage machen.
|
||||
|
||||
JWT-Lösung:
|
||||
- Claims im Token: `sub`, `email`, `roles`, `scope`, …
|
||||
- Jeder Service liest diese Claims aus dem Token und kann basierend darauf entscheiden.
|
||||
|
||||
### 4.3 Mobile / Single-Page-Applications (SPAs)
|
||||
|
||||
Problem:
|
||||
- SPAs (z.B. React, Angular, Vue) und Mobile-Apps sprechen meist direkt mit APIs.
|
||||
- Klassische serverseitige Sessions sind dafür unhandlich, weil es keinen klassischen Browser-Request/Response-Cookie-Workflow gibt oder dieser komplexer ist.
|
||||
|
||||
JWT-Lösung:
|
||||
- Client erhält nach Login ein **Access Token (JWT)**.
|
||||
- Bei jedem API-Request wird das JWT im `Authorization`-Header mitgeschickt.
|
||||
- APIs können unabhängig vom Frontend arbeiten (auch mehrere Frontends nutzen die gleiche API).
|
||||
|
||||
---
|
||||
|
||||
## 5. Praxisnahe Anwendungsbeispiele
|
||||
|
||||
### 5.1 Web-App / API-Login mit JWT
|
||||
|
||||
Ablauf:
|
||||
|
||||
1. Benutzer gibt E-Mail + Passwort ein und klickt auf „Login“.
|
||||
2. Frontend schickt diese Daten an `/auth/login` (Backend).
|
||||
3. Backend prüft:
|
||||
- Benutzer existiert?,
|
||||
- Passwort korrekt?
|
||||
4. Wenn ok:
|
||||
- Backend erstellt ein JWT:
|
||||
- `sub = Benutzer-ID`
|
||||
- `email = Benutzer-Email`
|
||||
- `role = "user"`
|
||||
- `exp = in 15 Minuten`
|
||||
- signiert das Token mit einem geheimen Schlüssel (z.B. HS256).
|
||||
5. Backend schickt das Token an das Frontend zurück.
|
||||
6. Frontend speichert das Token:
|
||||
- z.B. in einem **httpOnly Cookie** (empfohlen),
|
||||
- oder in einem sicheren Storage (abhängig vom Setup).
|
||||
7. Bei jeder API-Anfrage:
|
||||
- schickt das Frontend das Token mit, z.B.:
|
||||
|
||||
```http
|
||||
GET /api/orders
|
||||
Authorization: Bearer <JWT_HIER>
|
||||
```
|
||||
|
||||
8. Die API:
|
||||
- prüft die Signatur,
|
||||
- prüft `exp` (nicht abgelaufen?),
|
||||
- liest `sub`, `role`, `scope` aus,
|
||||
- entscheidet, ob Zugriff erlaubt ist.
|
||||
|
||||
### 5.2 Microservices hinter einem API Gateway
|
||||
|
||||
Stell dir eine Plattform mit mehreren Microservices vor:
|
||||
|
||||
- `User-Service`
|
||||
- `Order-Service`
|
||||
- `Billing-Service`
|
||||
|
||||
Es gibt einen **Auth-Service**, der JWTs ausstellt.
|
||||
Alle Services kennen den Public Key (bei asymmetrischer Signatur) oder den Secret Key (bei symmetrischer Signatur).
|
||||
|
||||
Ablauf:
|
||||
|
||||
- Benutzer loggt sich über Auth-Service ein → bekommt JWT.
|
||||
- Frontend ruft `Order-Service` auf mit `Authorization: Bearer <JWT>`.
|
||||
- `Order-Service` prüft JWT:
|
||||
- gültig?
|
||||
- `scope` beinhaltet `read:orders`?
|
||||
- Wenn ja → Bestellung anzeigen.
|
||||
|
||||
Vorteil:
|
||||
Jeder Service muss keinen eigenen Session-Store haben, sondern nur das JWT validieren.
|
||||
|
||||
### 5.3 E-Mail-Bestätigung / Passwort-Reset
|
||||
|
||||
JWTs eignen sich auch für **zeitlich begrenzte Links**:
|
||||
|
||||
Beispiel: Passwort-Reset:
|
||||
|
||||
1. Benutzer klickt „Passwort vergessen“.
|
||||
2. Backend erzeugt ein JWT mit Claims:
|
||||
- `sub = Benutzer-ID`
|
||||
- `exp = in 30 Minuten`
|
||||
- `purpose = "password_reset"`
|
||||
3. Backend verschickt E-Mail mit Link:
|
||||
|
||||
```text
|
||||
https://meine-app.de/reset-password?token=<JWT_HIER>
|
||||
```
|
||||
|
||||
4. Benutzer klickt den Link.
|
||||
5. Frontend schickt den Token an das Backend, z.B. POST `/auth/reset-password`.
|
||||
6. Backend prüft:
|
||||
- Signatur,
|
||||
- `exp` (noch gültig?),
|
||||
- `purpose == "password_reset"`.
|
||||
7. Wenn alles passt → Passwort darf geändert werden.
|
||||
|
||||
---
|
||||
|
||||
## 6. Herausforderungen und Fallstricke
|
||||
|
||||
JWTs lösen einige Probleme, bringen aber eigene Herausforderungen mit sich.
|
||||
|
||||
### 6.1 Sicherheit bei Signatur und Schlüssel
|
||||
|
||||
Wichtige Punkte:
|
||||
|
||||
- **Algorithmuswahl:**
|
||||
Typisch:
|
||||
- Symmetrisch: `HS256` (ein gemeinsames Secret für Signatur & Prüfung)
|
||||
- Asymmetrisch: `RS256` (privater Schlüssel signiert, öffentlicher Schlüssel prüft)
|
||||
- **Keys sicher verwalten:**
|
||||
- nicht im Code hardcoden,
|
||||
- in sicheren Secret-Stores halten,
|
||||
- Schlüssel regelmäßig rotieren.
|
||||
|
||||
Gefährliche Anti-Pattern:
|
||||
- `alg: none` akzeptieren (nie tun),
|
||||
- Server so konfigurieren, dass er das `alg` aus dem Token blind vertraut (statt fest vorzugeben, was erlaubt ist).
|
||||
|
||||
### 6.2 Token-Ablauf und „Logout“
|
||||
|
||||
JWT ist stateless – das macht „Logout“ tricky:
|
||||
|
||||
- Klassische Session:
|
||||
- Session im Server-Speicher löschen → Benutzer abgemeldet.
|
||||
- JWT:
|
||||
- Token ist selbstständig gültig, bis `exp` erreicht ist.
|
||||
- Serverseitig gibt es **keine zentrale Liste** aller aktiven JWTs.
|
||||
|
||||
Mögliche Lösungen:
|
||||
- Tokens **kurzlebig** machen, z.B. 5–15 Minuten.
|
||||
- Für längere Sessions:
|
||||
- **Access Token** kurzlebig,
|
||||
- **Refresh Token** längerlebig und serverseitig verwaltbar (z.B. in DB),
|
||||
- bei Logout → Refresh Token invalidieren, Access Token läuft automatisch bald ab.
|
||||
- Optional: Blacklists/Blocklists oder Token-Revocation-Mechanismen.
|
||||
|
||||
### 6.3 Wo speichert man JWT im Browser?
|
||||
|
||||
Varianten:
|
||||
- **httpOnly Cookie**:
|
||||
- Vorteil: nicht via JavaScript auslesbar → Schutz gegen XSS.
|
||||
- Nachteil: CSRF muss beachtet werden (CSRF-Protection implementieren).
|
||||
- **localStorage / sessionStorage**:
|
||||
- Vorteil: einfache Handhabung im JS-Code.
|
||||
- Nachteil: bei XSS kann ein Angreifer das Token auslesen → sehr riskant.
|
||||
|
||||
In der Praxis:
|
||||
- Oft Kombination aus httpOnly Cookies + CSRF-Schutz,
|
||||
- oder Speziallösungen mit sog. „Double Submit Cookies“, „SameSite“-Cookies etc.
|
||||
|
||||
### 6.4 Token sind nicht geheim (wenn nur signiert)
|
||||
|
||||
Wichtiger Punkt:
|
||||
- Ein **normaler signierter JWT ist nicht verschlüsselt**.
|
||||
- Jeder, der das Token sieht, kann die Payload (Claims) lesen, da sie Base64URL-kodiert ist (was keine Verschlüsselung ist).
|
||||
|
||||
Daraus folgt:
|
||||
- Keine hochsensiblen Daten in die Payload packen (z.B. Passwörter, Zahlungsdaten, interne Geheimnisse).
|
||||
- JWT nur über **HTTPS** übertragen, damit niemand auf dem Weg „mithören“ kann.
|
||||
- Wenn wirklich Geheimhaltung nötig ist → **JWE (verschlüsseltes JWT)** oder andere Verschlüsselungsmechanismen.
|
||||
|
||||
### 6.5 Token-Größe
|
||||
|
||||
Wenn man sehr viele Claims ins Token packt:
|
||||
- wird es groß,
|
||||
- verursacht mehr Traffic,
|
||||
- passt evtl. schlechter in Cookies oder Header.
|
||||
|
||||
Praktisch:
|
||||
Nur wirklich relevante Informationen ins JWT aufnehmen:
|
||||
- Benutzer-ID
|
||||
- Rollen, Rechte oder Scope
|
||||
- wenige zusätzliche Angaben
|
||||
|
||||
Den Rest kann man bei Bedarf aus der Datenbank abfragen.
|
||||
|
||||
### 6.6 Fehler bei der Prüfung des Tokens
|
||||
|
||||
Beim Validieren darf man nicht nur die Signatur prüfen, sondern auch:
|
||||
|
||||
- Ist das Token abgelaufen? (`exp`)
|
||||
- Ist das Token noch nicht gültig? (`nbf`, `iat`)
|
||||
- Stimmt `iss` (Issuer) mit dem erwarteten Aussteller überein?
|
||||
- Stimmt `aud` (Audience) mit der eigenen Anwendung/API überein?
|
||||
|
||||
Beispiel (Node.js mit `jsonwebtoken`):
|
||||
|
||||
```js
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const token = '...'; // vom Client erhalten
|
||||
const publicKey = '...'; // Public Key (bei RS256) oder Secret (bei HS256)
|
||||
|
||||
try {
|
||||
const payload = jwt.verify(token, publicKey, {
|
||||
algorithms: ['RS256'],
|
||||
issuer: 'https://auth.meine-app.de',
|
||||
audience: 'https://api.meine-app.de',
|
||||
});
|
||||
|
||||
console.log('Token gültig, Benutzer-ID:', payload.sub);
|
||||
} catch (err) {
|
||||
console.error('Ungültiges Token:', err.message);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Kurz-Fazit
|
||||
|
||||
- Ein **JWT** ist ein **signierter, kompakter Datenträger im JSON-Format**, der Claims über Benutzer/Clients enthält.
|
||||
- Er wird verwendet für:
|
||||
- Authentifizierung (z.B. „Benutzer X ist eingeloggt“),
|
||||
- Autorisierung (z.B. „Benutzer X hat die Rolle admin“),
|
||||
- zeitlich begrenzte Aktionen (Passwort-Reset, E-Mail-Bestätigung),
|
||||
- verteilte Systeme (Microservices), die ohne zentralen Session-Speicher auskommen sollen.
|
||||
- JWTs sind besonders sinnvoll in:
|
||||
- Web-APIs,
|
||||
- SPAs,
|
||||
- mobilen Apps,
|
||||
- Microservice- und Cloud-Architekturen.
|
||||
- Abgrenzung:
|
||||
- JWT ≠ OAuth2/OIDC (Protokoll vs. Tokenformat),
|
||||
- JWT ≠ Session-Cookie (zustandslos vs. zustandsbehaftet),
|
||||
- JWTs sind meist JWS (signiert, aber nicht verschlüsselt).
|
||||
- Herausforderungen:
|
||||
- Sichere Schlüsselverwaltung, korrekte Token-Prüfung,
|
||||
- Umgang mit Logout/Token-Invalidierung,
|
||||
- sicherer Speicherort im Client (XSS/CSRF),
|
||||
- kein Hineinpacken hochsensibler Daten.
|
||||
|
||||
+512
@@ -0,0 +1,512 @@
|
||||
## Inhaltsverzeichnis
|
||||
- [Grundkonzepte](#grundkonzepte)
|
||||
- [Schritt 1: Welche Endpoints gibt es?](#schritt-1-welche-endpoints-gibt-es)
|
||||
- [Schritt 2: Endpoint-Konfiguration prüfen](#schritt-2-endpoint-konfiguration-prüfen)
|
||||
- [Schritt 3: Endpoint erreichbar machen](#schritt-3-endpoint-erreichbar-machen)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
## Grundkonzepte
|
||||
|
||||
### Was ist ein Endpoint?
|
||||
Ein **Endpoint** ist eine URL, über die Sie auf eine Anwendung in Kubernetes zugreifen können (z.B. `https://jupyterhub.example.com` oder `http://localhost:8080`).
|
||||
|
||||
### Wichtige Kubernetes-Komponenten
|
||||
|
||||
#### 1. Pod
|
||||
- Ein **Pod** ist die kleinste Einheit in Kubernetes
|
||||
- Enthält einen oder mehrere Container (z.B. Ihre Anwendung)
|
||||
- Hat eine interne IP-Adresse im Cluster
|
||||
- Befehl: `kubectl get pods -n <namespace>`
|
||||
|
||||
#### 2. Service
|
||||
- Ein **Service** ist eine stabile Zugangsadresse zu einem oder mehreren Pods
|
||||
- Macht Pods innerhalb des Clusters erreichbar
|
||||
- Typen:
|
||||
- `ClusterIP`: Nur innerhalb des Clusters erreichbar
|
||||
- `NodePort`: Von außen über Port am Node erreichbar
|
||||
- `LoadBalancer`: Erstellt einen externen Load Balancer (z.B. bei AWS)
|
||||
- Befehl: `kubectl get svc -n <namespace>`
|
||||
|
||||
#### 3. Ingress
|
||||
- Ein **Ingress** ist die "Haustür" zu Ihren Services von außerhalb des Clusters
|
||||
- Ermöglicht HTTP/HTTPS-Zugriff über Domainnamen (z.B. `app.example.com`)
|
||||
- Benötigt einen Ingress Controller (z.B. [[nginx]])
|
||||
- Befehl: `kubectl get ingress -n <namespace>`
|
||||
|
||||
#### 4. Namespace
|
||||
- Ein **Namespace** ist wie ein Ordner in Kubernetes
|
||||
- Trennt verschiedene Anwendungen oder Teams
|
||||
- Beispiele: `openmetadata`, `jupyterhub`, `default`
|
||||
|
||||
---
|
||||
|
||||
## Schritt 1: Welche Endpoints gibt es?
|
||||
|
||||
### 1.1 Alle Namespaces auflisten
|
||||
|
||||
```bash
|
||||
kubectl get namespaces
|
||||
```
|
||||
|
||||
**Erklärung:** Zeigt alle Namespaces in Ihrem Cluster. Hier finden Sie, wo Ihre Anwendungen laufen.
|
||||
|
||||
**Beispiel-Output:**
|
||||
```
|
||||
NAME STATUS AGE
|
||||
default Active 30d
|
||||
jupyterhub Active 20d
|
||||
openmetadata Active 5d
|
||||
argocd Active 25d
|
||||
```
|
||||
|
||||
### 1.2 Anwendungen in einem Namespace finden
|
||||
|
||||
```bash
|
||||
# Pods (laufende Anwendungen)
|
||||
kubectl get pods -n openmetadata
|
||||
|
||||
# Services (Zugriffspunkte)
|
||||
kubectl get svc -n openmetadata
|
||||
|
||||
# Ingress (externe Zugänge)
|
||||
kubectl get ingress -n openmetadata
|
||||
```
|
||||
|
||||
**Wichtig:** Ersetzen Sie `openmetadata` mit Ihrem Namespace!
|
||||
|
||||
**Beispiel-Output:**
|
||||
```bash
|
||||
# Pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
openmetadata-559bf987f6-gxkdk 1/1 Running 0 4d20h
|
||||
|
||||
# Services
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
openmetadata ClusterIP 172.20.25.201 <none> 8585/TCP,8586/TCP 4d20h
|
||||
|
||||
# Ingress
|
||||
NAME CLASS HOSTS ADDRESS PORTS AGE
|
||||
openmetadata nginx openmetadata.dma.aai-dfine.de xxx.elb.amazonaws.com 80, 443 4d20h
|
||||
```
|
||||
|
||||
### 1.3 Alle Ingress-Endpoints im Cluster
|
||||
|
||||
```bash
|
||||
kubectl get ingress --all-namespaces
|
||||
```
|
||||
|
||||
**Erklärung:** Zeigt ALLE konfigurierten externen Zugänge über alle Namespaces hinweg.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 2: Endpoint-Konfiguration prüfen
|
||||
|
||||
### 2.1 Detaillierte Ingress-Informationen
|
||||
|
||||
```bash
|
||||
kubectl describe ingress <ingress-name> -n <namespace>
|
||||
```
|
||||
|
||||
**Beispiel:**
|
||||
```bash
|
||||
kubectl describe ingress openmetadata -n openmetadata
|
||||
```
|
||||
|
||||
**Was Sie hier sehen:**
|
||||
- **Hosts:** Der Domainname (z.B. `openmetadata.dma.aai-dfine.de`)
|
||||
- **TLS:** Ob HTTPS konfiguriert ist und welches Zertifikat verwendet wird
|
||||
- **Backends:** Zu welchem Service und Port der Ingress weiterleitet
|
||||
- **Address:** Der tatsächliche Load Balancer
|
||||
|
||||
**Beispiel-Output:**
|
||||
```
|
||||
Name: openmetadata
|
||||
Namespace: openmetadata
|
||||
Address: aa83990c7ad3548c4b0e28680b0952ba-1924426268.eu-central-1.elb.amazonaws.com
|
||||
Ingress Class: nginx
|
||||
TLS:
|
||||
aai-dfine-certificate-tls terminates openmetadata.dma.aai-dfine.de
|
||||
Rules:
|
||||
Host Path Backends
|
||||
---- ---- --------
|
||||
openmetadata.dma.aai-dfine.de / openmetadata:8585 (10.10.1.86:8585)
|
||||
```
|
||||
|
||||
### 2.2 Pod-Status überprüfen
|
||||
|
||||
```bash
|
||||
kubectl get pods -n <namespace>
|
||||
```
|
||||
|
||||
**Status-Bedeutungen:**
|
||||
- `Running`: ✅ Pod läuft normal
|
||||
- `Pending`: ⏳ Pod startet gerade
|
||||
- `CrashLoopBackOff`: ❌ Pod startet immer wieder neu (Fehler!)
|
||||
- `Error`: ❌ Pod hat einen Fehler
|
||||
|
||||
### 2.3 Service-Details
|
||||
|
||||
```bash
|
||||
kubectl get svc <service-name> -n <namespace> -o wide
|
||||
```
|
||||
|
||||
**Zeigt:** ClusterIP, Ports, Selectors (welche Pods werden angesprochen)
|
||||
|
||||
---
|
||||
|
||||
## Schritt 3: Endpoint erreichbar machen
|
||||
|
||||
Es gibt **drei Methoden**, um auf einen Kubernetes-Endpoint zuzugreifen:
|
||||
|
||||
### Methode 1: Port-Forwarding (Empfohlen für Tests) ⭐
|
||||
|
||||
**Wann nutzen?**
|
||||
- Schneller Zugriff für Tests
|
||||
- DNS ist nicht konfiguriert
|
||||
- Lokale Entwicklung
|
||||
|
||||
**Vorteile:**
|
||||
- ✅ Keine Cluster-Änderungen
|
||||
- ✅ Sicher (nur für Sie erreichbar)
|
||||
- ✅ Sofort verfügbar
|
||||
- ✅ Keine DNS-Konfiguration nötig
|
||||
|
||||
**Nachteile:**
|
||||
- ❌ Terminal muss offen bleiben
|
||||
- ❌ Nur von Ihrem PC erreichbar
|
||||
|
||||
**Befehl:**
|
||||
```bash
|
||||
kubectl port-forward -n <namespace> svc/<service-name> <lokaler-port>:<service-port>
|
||||
```
|
||||
|
||||
**Beispiel für OpenMetadata:**
|
||||
```bash
|
||||
kubectl port-forward -n openmetadata svc/openmetadata 8585:8585
|
||||
```
|
||||
|
||||
**Was passiert:**
|
||||
1. Kubernetes erstellt einen Tunnel von Ihrem PC zum Service
|
||||
2. Sie können nun auf `http://localhost:8585` zugreifen
|
||||
3. Der Tunnel leitet alle Anfragen an den Service im Cluster weiter
|
||||
|
||||
**Zugriff:**
|
||||
```
|
||||
http://localhost:8585
|
||||
```
|
||||
|
||||
**Beenden:** `Ctrl + C` im Terminal
|
||||
|
||||
**Tipp:** Im Hintergrund laufen lassen:
|
||||
```bash
|
||||
# Windows PowerShell
|
||||
Start-Process kubectl -ArgumentList "port-forward -n openmetadata svc/openmetadata 8585:8585" -WindowStyle Hidden
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Methode 2: Über Ingress mit DNS (Produktiv-Umgebung)
|
||||
|
||||
**Wann nutzen?**
|
||||
- Produktiv-Zugriff
|
||||
- Mehrere Nutzer
|
||||
- HTTPS/TLS erforderlich
|
||||
|
||||
**Voraussetzungen:**
|
||||
1. ✅ Ingress ist konfiguriert (siehe Schritt 2.1)
|
||||
2. ✅ DNS-Eintrag existiert
|
||||
3. ✅ TLS-Zertifikat ist vorhanden
|
||||
|
||||
#### 2.1 DNS-Auflösung testen
|
||||
|
||||
```bash
|
||||
# Windows PowerShell
|
||||
nslookup openmetadata.dma.aai-dfine.de
|
||||
|
||||
# Alternative
|
||||
Resolve-DnsName openmetadata.dma.aai-dfine.de
|
||||
```
|
||||
|
||||
**Wenn DNS funktioniert:**
|
||||
```
|
||||
Server: dns.google
|
||||
Address: 8.8.8.8
|
||||
|
||||
Name: openmetadata.dma.aai-dfine.de
|
||||
Address: 54.xxx.xxx.xxx
|
||||
```
|
||||
|
||||
**Wenn DNS NICHT funktioniert:**
|
||||
```
|
||||
*** dns.google kann openmetadata.dma.aai-dfine.de nicht finden: Non-existent domain
|
||||
```
|
||||
|
||||
#### 2.2 Problem: DNS funktioniert nicht
|
||||
|
||||
**Lösung A: Lokale Hosts-Datei (temporär für Tests)**
|
||||
|
||||
1. **Load Balancer IP/Hostname finden:**
|
||||
```bash
|
||||
kubectl get ingress <ingress-name> -n <namespace>
|
||||
```
|
||||
|
||||
Notieren Sie die `ADDRESS` (z.B. `xxx.elb.amazonaws.com`)
|
||||
|
||||
2. **Load Balancer IP auflösen:**
|
||||
```bash
|
||||
nslookup xxx.elb.amazonaws.com
|
||||
```
|
||||
|
||||
3. **Windows Hosts-Datei bearbeiten:**
|
||||
- Datei öffnen als Administrator: `C:\Windows\System32\drivers\etc\hosts`
|
||||
- Zeile hinzufügen:
|
||||
```
|
||||
<IP-Adresse> openmetadata.dma.aai-dfine.de
|
||||
```
|
||||
- Speichern
|
||||
|
||||
4. **Im Browser öffnen:**
|
||||
```
|
||||
https://openmetadata.dma.aai-dfine.de
|
||||
```
|
||||
|
||||
**Lösung B: DNS-Eintrag erstellen lassen (dauerhaft)**
|
||||
|
||||
Jemand mit AWS Route53-Zugriff muss einen DNS-Eintrag erstellen:
|
||||
- **Typ:** CNAME oder A-Record
|
||||
- **Name:** `openmetadata.dma.aai-dfine.de`
|
||||
- **Ziel:** Load Balancer Hostname/IP
|
||||
|
||||
---
|
||||
|
||||
### Methode 3: Direkt zum Load Balancer (ohne DNS)
|
||||
|
||||
**Wenn vorhanden:**
|
||||
|
||||
1. **Load Balancer URL finden:**
|
||||
```bash
|
||||
kubectl get ingress <ingress-name> -n <namespace>
|
||||
```
|
||||
|
||||
2. **Direkt mit curl testen:**
|
||||
```bash
|
||||
curl -H "Host: openmetadata.dma.aai-dfine.de" http://<load-balancer-url>
|
||||
```
|
||||
|
||||
**Hinweis:** Funktioniert nicht immer im Browser (Host-Header erforderlich)
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Problem: "Hmmm... can't reach this page" / ERR_NAME_NOT_RESOLVED
|
||||
|
||||
**Ursache:** DNS-Name kann nicht aufgelöst werden
|
||||
|
||||
**Lösung:**
|
||||
1. DNS testen: `nslookup <hostname>`
|
||||
2. Falls DNS fehlt → **Port-Forwarding** verwenden (Methode 1)
|
||||
3. Oder: Hosts-Datei editieren (Methode 2, Lösung A)
|
||||
|
||||
---
|
||||
|
||||
### Problem: Port-Forwarding schlägt fehl
|
||||
|
||||
**Fehlermeldung:** `Unable to listen on port 8585`
|
||||
|
||||
**Ursache:** Port ist bereits belegt
|
||||
|
||||
**Lösung:**
|
||||
```bash
|
||||
# Anderen lokalen Port verwenden
|
||||
kubectl port-forward -n openmetadata svc/openmetadata 9999:8585
|
||||
|
||||
# Dann öffnen: http://localhost:9999
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Problem: Pod läuft nicht (Status: CrashLoopBackOff)
|
||||
|
||||
**Logs anschauen:**
|
||||
```bash
|
||||
kubectl logs <pod-name> -n <namespace>
|
||||
|
||||
# Letzte 100 Zeilen
|
||||
kubectl logs <pod-name> -n <namespace> --tail=100
|
||||
|
||||
# Vorheriger Container (wenn Pod neu gestartet wurde)
|
||||
kubectl logs <pod-name> -n <namespace> --previous
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Problem: 502 Bad Gateway / 503 Service Unavailable
|
||||
|
||||
**Ursache:** Service erreicht den Pod nicht
|
||||
|
||||
**Prüfen:**
|
||||
```bash
|
||||
# 1. Läuft der Pod?
|
||||
kubectl get pods -n <namespace>
|
||||
|
||||
# 2. Sind Endpoints vorhanden?
|
||||
kubectl get endpoints <service-name> -n <namespace>
|
||||
|
||||
# 3. Service-Details
|
||||
kubectl describe svc <service-name> -n <namespace>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Problem: Authentifizierung erforderlich
|
||||
|
||||
**Wenn Login-Seite erscheint:**
|
||||
|
||||
**Standard-Credentials suchen:**
|
||||
```bash
|
||||
# Secrets auflisten
|
||||
kubectl get secrets -n <namespace>
|
||||
|
||||
# Secret anschauen (Werte sind base64-kodiert)
|
||||
kubectl get secret <secret-name> -n <namespace> -o yaml
|
||||
|
||||
# Secret dekodieren
|
||||
kubectl get secret <secret-name> -n <namespace> -o jsonpath='{.data.password}' | base64 -d
|
||||
```
|
||||
|
||||
**Beispiel OpenMetadata:**
|
||||
- Standard-User: `admin`
|
||||
- Standard-Password: `admin`
|
||||
|
||||
---
|
||||
|
||||
## Nützliche Befehle - Cheat Sheet
|
||||
|
||||
### Übersicht verschaffen
|
||||
```bash
|
||||
# Alle Namespaces
|
||||
kubectl get namespaces
|
||||
|
||||
# Alles in einem Namespace
|
||||
kubectl get all -n <namespace>
|
||||
|
||||
# Alle Ingress-Endpoints
|
||||
kubectl get ingress --all-namespaces
|
||||
```
|
||||
|
||||
### Status prüfen
|
||||
```bash
|
||||
# Pods mit mehr Details
|
||||
kubectl get pods -n <namespace> -o wide
|
||||
|
||||
# Pod-Logs live verfolgen
|
||||
kubectl logs -f <pod-name> -n <namespace>
|
||||
|
||||
# In Pod einloggen (für Debugging)
|
||||
kubectl exec -it <pod-name> -n <namespace> -- /bin/bash
|
||||
```
|
||||
|
||||
### Konfiguration anschauen
|
||||
```bash
|
||||
# YAML eines Ingress
|
||||
kubectl get ingress <name> -n <namespace> -o yaml
|
||||
|
||||
# Service-Details
|
||||
kubectl describe svc <name> -n <namespace>
|
||||
|
||||
# ConfigMap auslesen
|
||||
kubectl get configmap <name> -n <namespace> -o yaml
|
||||
```
|
||||
|
||||
### Port-Forwarding
|
||||
```bash
|
||||
# Standard
|
||||
kubectl port-forward -n <namespace> svc/<service-name> <local-port>:<service-port>
|
||||
|
||||
# Zu einem Pod (falls Service nicht existiert)
|
||||
kubectl port-forward -n <namespace> <pod-name> <local-port>:<container-port>
|
||||
|
||||
# Alle Interfaces binden (auch im Netzwerk erreichbar)
|
||||
kubectl port-forward --address 0.0.0.0 -n <namespace> svc/<service> 8585:8585
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Für Tests und Entwicklung
|
||||
✅ **Port-Forwarding** verwenden
|
||||
- Schnell, sicher, keine Änderungen am Cluster
|
||||
|
||||
### Für Produktiv-Zugriff
|
||||
✅ **Ingress mit DNS** verwenden
|
||||
- Korrekte DNS-Einträge erstellen lassen
|
||||
- TLS/HTTPS konfigurieren
|
||||
- Basic Auth oder OAuth für Authentifizierung
|
||||
|
||||
### Sicherheit
|
||||
⚠️ **Nie direkt auf Pods zugreifen** in Produktion
|
||||
⚠️ **Immer über Services** routen
|
||||
⚠️ **Port-Forwarding nicht dauerhaft** laufen lassen
|
||||
|
||||
---
|
||||
|
||||
## Glossar
|
||||
|
||||
| Begriff | Erklärung |
|
||||
|---------|-----------|
|
||||
| **Cluster** | Die gesamte Kubernetes-Umgebung mit allen Maschinen |
|
||||
| **Node** | Eine einzelne Maschine (VM) im Cluster |
|
||||
| **Pod** | Kleinste Einheit, enthält Container mit Ihrer App |
|
||||
| **Service** | Stabiler Zugriffspunkt zu einem oder mehreren Pods |
|
||||
| **Ingress** | HTTP/HTTPS-Zugang von außen, wie ein Router |
|
||||
| **Namespace** | Logische Trennung/Ordner für Anwendungen |
|
||||
| **ConfigMap** | Konfigurationsdaten (nicht-sensitiv) |
|
||||
| **Secret** | Sensible Daten (Passwörter, Tokens) - base64-kodiert |
|
||||
| **Load Balancer** | Verteilt Traffic auf mehrere Pods (z.B. AWS ELB) |
|
||||
| **TLS/SSL** | Verschlüsselung für HTTPS |
|
||||
| **Port-Forward** | Tunnel von lokalem PC zu Kubernetes-Service |
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
### Quick Start: Auf Anwendung zugreifen
|
||||
|
||||
1. **Namespace finden:**
|
||||
```bash
|
||||
kubectl get namespaces
|
||||
```
|
||||
|
||||
2. **Ingress prüfen:**
|
||||
```bash
|
||||
kubectl get ingress -n <namespace>
|
||||
```
|
||||
|
||||
3. **Port-Forwarding starten:**
|
||||
```bash
|
||||
kubectl port-forward -n <namespace> svc/<service-name> 8585:8585
|
||||
```
|
||||
|
||||
4. **Im Browser öffnen:**
|
||||
```
|
||||
http://localhost:8585
|
||||
```
|
||||
|
||||
Das war's! 🎉
|
||||
|
||||
---
|
||||
|
||||
## Weitere Ressourcen
|
||||
|
||||
- [Offizielle Kubernetes Dokumentation](https://kubernetes.io/docs/)
|
||||
- [kubectl Cheat Sheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/)
|
||||
- [Kubernetes Port-Forwarding](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)
|
||||
|
||||
---
|
||||
|
||||
*Erstellt am: {{ date:2026-02-10 }}*
|
||||
*Workspace: `gitops`*
|
||||
@@ -0,0 +1,299 @@
|
||||
#IT #Container #Open-Source #Cloud
|
||||
|
||||
---
|
||||
|
||||
## 1. Was ist Kubernetes – in einem Satz?
|
||||
|
||||
Kubernetes ist ein Open-Source‑System zur **Orchestrierung von Containern** (z. B. Docker), das die **Bereitstellung, Skalierung und Verwaltung** von Anwendungen automatisiert.
|
||||
|
||||
- Entwickelt von Google, heute von der CNCF (Cloud Native Computing Foundation) verwaltet
|
||||
- Läuft in der Cloud (AWS, Azure, GCP), im Rechenzentrum (On‑Prem) oder lokal (z. B. mit kind, minikube)
|
||||
|
||||
---
|
||||
|
||||
## 2. Warum braucht man Kubernetes?
|
||||
|
||||
### 2.1 Ausgangslage ohne Kubernetes
|
||||
|
||||
Bei klassischen Server- oder Container-Setups müssen viele Dinge manuell oder mit Skripten gelöst werden:
|
||||
|
||||
- Container starten/stoppen
|
||||
- Lastverteilung zwischen Instanzen
|
||||
- Neustart fehlerhafter Instanzen
|
||||
- Rollout neuer Versionen
|
||||
- Skalierung bei Lastspitzen
|
||||
- Konfigurationsmanagement und Secrets
|
||||
- Self-Healing bei Fehlern
|
||||
|
||||
### 2.2 Ziele von Kubernetes
|
||||
|
||||
Kubernetes löst diese Probleme, indem es:
|
||||
|
||||
1. **Deklaratives Modell** nutzt
|
||||
- Du beschreibst den „Soll-Zustand“ (z. B. „es sollen 3 Instanzen meiner App laufen“).
|
||||
- Kubernetes sorgt im Hintergrund dafür, dass dieser Zustand erreicht und gehalten wird.
|
||||
|
||||
2. **Automatisierung** von:
|
||||
- Rollouts und Rollbacks
|
||||
- Skalierung (horizontaler Ausbau: mehr Instanzen)
|
||||
- Self-Healing (Pods werden bei Absturz neu gestartet)
|
||||
- Service Discovery & Load Balancing
|
||||
|
||||
3. **Abstraktion von Infrastruktur**:
|
||||
- Egal ob deine Knoten VMs in der Cloud oder bare-metal-Server sind – Kubernetes abstrahiert das weg.
|
||||
|
||||
---
|
||||
|
||||
## 3. Hohe Ebene: Aufbau eines Kubernetes-Clusters
|
||||
|
||||
Ein Kubernetes-Cluster besteht grob aus:
|
||||
|
||||
- **Control Plane** (Master-Komponenten)
|
||||
- **Worker Nodes** (wo die Container wirklich laufen)
|
||||
|
||||
### 3.1 Control Plane (Steuerungsebene)
|
||||
|
||||
Wichtige Komponenten:
|
||||
|
||||
- **kube-apiserver**
|
||||
- Zentraler Einstiegspunkt
|
||||
- Alle Befehle von `kubectl` und anderen Komponenten laufen über die API ([[kubectl]])
|
||||
|
||||
- **etcd**
|
||||
- Verteilter Key-Value-Store
|
||||
- Hält den gesamten Cluster-Zustand (z. B. welche Pods, Deployments, ConfigMaps etc.)
|
||||
|
||||
- **kube-scheduler**
|
||||
- Entscheidet, auf welchem Node neue Pods laufen sollen
|
||||
- Berücksichtigt Ressourcen (CPU, RAM), Constraints, Affinities etc.
|
||||
|
||||
- **kube-controller-manager**
|
||||
- Mehrere Controller (z. B. für Deployments, Nodes, Endpoints)
|
||||
- Stellt sicher, dass der Ist-Zustand dem Soll-Zustand entspricht („Reconciliation Loop“)
|
||||
|
||||
- **cloud-controller-manager** (optional)
|
||||
- Integration mit Cloud-Anbietern (z. B. Load Balancer in AWS/Azure/GCP anlegen)
|
||||
|
||||
### 3.2 Worker Nodes (Arbeitsebene)
|
||||
|
||||
Auf jedem Worker laufen:
|
||||
|
||||
- **kubelet**
|
||||
- Agent auf dem Node
|
||||
- Kommuniziert mit der API und sorgt lokal dafür, dass die Pods wie gewünscht laufen
|
||||
|
||||
- **Container Runtime**
|
||||
- Führt Container aus: z. B. containerd, CRI‑O, Docker (früher direkt, heute über CRI)
|
||||
|
||||
- **kube-proxy**
|
||||
- Implementiert das Kubernetes-Service-Netzwerk
|
||||
- Kümmert sich um Weiterleitung von Netzwerkpaketen zu den richtigen Pods
|
||||
|
||||
---
|
||||
|
||||
## 4. Zentrale Konzepte in Kubernetes
|
||||
|
||||
### 4.1 Pod
|
||||
|
||||
- Kleinste deploybare Einheit in Kubernetes
|
||||
- Ein Pod enthält einen oder mehrere Container, die:
|
||||
- sich IP-Adresse und Ports teilen
|
||||
- sich lokale Volumes teilen
|
||||
- Typischerweise: 1 Container pro Pod (plus evtl. Sidecars)
|
||||
|
||||
Beispiel: Ein Pod mit einem [[NGINX]] Container:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: my-nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
### 4.2 Deployment
|
||||
|
||||
- Deklarative Beschreibung von Pods + Skalierung
|
||||
- Sagt z. B.: „Es sollen 3 identische Replikate dieses Pods laufen“
|
||||
- Unterstützt Rollouts und Rollbacks (z. B. `kubectl rollout undo`)
|
||||
|
||||
Beispiel-Deployment:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-nginx-deployment
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: my-nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.27
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
### 4.3 Service
|
||||
|
||||
- Stabile Netzwerk-Adresse (DNS-Name, virtuelle IP) für eine Gruppe von Pods
|
||||
- Entkoppelt Clients von einzelnen Pod-IP-Adressen
|
||||
- Typen:
|
||||
- **ClusterIP**: intern im Cluster
|
||||
- **NodePort**: nach außen freigegeben über einen Port jedes Nodes
|
||||
- **LoadBalancer**: Integration mit einem Cloud-Load-Balancer
|
||||
|
||||
Beispiel-Service:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-nginx-service
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: my-nginx
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
```
|
||||
|
||||
### 4.4 Namespace
|
||||
|
||||
- Logische Unterteilung innerhalb eines Clusters
|
||||
- Dient zur:
|
||||
- Trennung von Umgebungen (dev, test, prod)
|
||||
- Multi-Tenancy
|
||||
- Ressourcenkontrolle (ResourceQuotas, Limits)
|
||||
- Standard-Namespace: `default`, daneben z. B. `kube-system`, `kube-public`
|
||||
|
||||
### 4.5 ConfigMap & Secret
|
||||
|
||||
- **ConfigMap**: Konfiguration (nicht sensibel), z. B. Properties, ENV-Variablen
|
||||
- **Secret**: sensible Daten (Passwörter, Tokens, Zertifikate)
|
||||
- Werden in Pods als ENV oder als Files (Volumes) bereitgestellt
|
||||
|
||||
### 4.6 Volume & PersistentVolume
|
||||
|
||||
- **Volumes**: Daten, die nicht verschwinden, wenn ein Container neu startet
|
||||
- **PersistentVolume (PV)**: repräsentiert eine physische/Cloud-Speicher-Ressource
|
||||
- **PersistentVolumeClaim (PVC)**: „Anforderung“ eines Pods an Speicher (Größe, Klasse)
|
||||
|
||||
---
|
||||
|
||||
## 5. Wie arbeitet Kubernetes? – Das „Desired State“-Modell
|
||||
|
||||
1. Du definierst Ressourcen (YAML/JSON), z. B.:
|
||||
|
||||
- „Deployment mit 3 Replikas meiner App“
|
||||
- „Service, der auf Port 80 erreichbar ist“
|
||||
|
||||
2. Du übernimmt diese Definition per:
|
||||
|
||||
```bash
|
||||
kubectl apply -f deployment.yaml
|
||||
```
|
||||
|
||||
3. Die API speichert diese Definition in **etcd**.
|
||||
|
||||
4. Controller und Scheduler beobachten den Zustand und führen eine **Reconciliation Loop** aus:
|
||||
|
||||
- Ist-Zustand (z. B. 2 Pods laufen) vs. Soll-Zustand (3 Pods sollen laufen)
|
||||
- Kubernetes startet einen weiteren Pod
|
||||
- Fällt ein Pod aus → wird automatisch ersetzt
|
||||
|
||||
---
|
||||
|
||||
## 6. Typischer Entwickler-Workflow mit Kubernetes
|
||||
|
||||
1. **Container-Image bauen**
|
||||
- z. B. mit Docker oder Buildpacks
|
||||
|
||||
2. **Image registrieren**
|
||||
- In einer Container Registry (Docker Hub, GitHub Container Registry, ECR, GCR…)
|
||||
|
||||
3. **Kubernetes-Manifest(e) schreiben**
|
||||
- Deployment, Service, ConfigMap, Secret, etc.
|
||||
|
||||
4. **Deployen**
|
||||
- `kubectl apply -f .`
|
||||
- Oder über CI/CD-Pipelines (GitLab CI, GitHub Actions, Argo CD, Jenkins etc.)
|
||||
|
||||
5. **Monitoring & Logging**
|
||||
- Über Tools wie Prometheus, Grafana, ELK/EFK-Stack, Loki, etc.
|
||||
|
||||
---
|
||||
|
||||
## 7. Kubernetes im Ökosystem / Erweiterungen
|
||||
|
||||
Kubernetes ist eine Basis, auf der vieles aufbaut:
|
||||
|
||||
- **Helm**
|
||||
- „Package Manager“ für Kubernetes
|
||||
- Erleichtert das Installieren komplexer Anwendungen (Charts)
|
||||
|
||||
- **Ingress & Ingress Controller**
|
||||
- HTTP/HTTPS-Routing auf Services
|
||||
- Ermöglicht virtuelle Hosts, Pfad-basiertes Routing usw.
|
||||
|
||||
- **Service Mesh (z. B. Istio, Linkerd)**
|
||||
- Feinere Kontrolle über Traffic, Observability, Security (mTLS)
|
||||
|
||||
- **Operators**
|
||||
- Kubernetes-Erweiterungen, die komplexe Anwendungen als „Custom Resources“ managen (z. B. Datenbanken)
|
||||
|
||||
- **GitOps (z. B. Argo CD, Flux)**
|
||||
- Zustände des Clusters werden aus Git-Repositories synchronisiert
|
||||
|
||||
---
|
||||
|
||||
## 8. Vorteile von Kubernetes
|
||||
|
||||
- Hohe **Portabilität** über verschiedene Infrastrukturen
|
||||
- **Automatisierte Skalierung** und Self-Healing
|
||||
- **Standardisierte Schnittstellen** (API-first)
|
||||
- Große **Community** und reiches Ökosystem
|
||||
- Gut geeignet für **Microservices** und verteile Systeme
|
||||
|
||||
---
|
||||
|
||||
## 9. Herausforderungen und Komplexität
|
||||
|
||||
- **Steile Lernkurve**: viele Konzepte (Pods, Deployments, Services, Ingress, RBAC, Storage…)
|
||||
- **Betrieb** eines eigenen Clusters ist nicht trivial
|
||||
- Viele Unternehmen nutzen Managed Services: GKE, AKS, EKS, OpenShift, Rancher etc.
|
||||
- **Observability**: Logs, Metrics, Tracing sind komplexer als bei einer einzigen VM
|
||||
- **Sicherheit** (RBAC, NetworkPolicies, Secrets-Management) erfordert Planung
|
||||
|
||||
---
|
||||
|
||||
## 10. Wie kann man praktisch starten?
|
||||
|
||||
Konkrete Schritte, um anzufangen:
|
||||
|
||||
1. **Lokale Umgebung**:
|
||||
- `kind` (Kubernetes in Docker)
|
||||
- `minikube` oder `k3d`
|
||||
|
||||
2. **Übungen**:
|
||||
- Einen einfachen Webserver als Deployment & Service bereitstellen
|
||||
- Mit `kubectl get`, `describe`, `logs` spielen
|
||||
- Scaling testen: `kubectl scale deployment my-deployment --replicas=5`
|
||||
- Eine neue Version deployen und Rollback ausprobieren
|
||||
|
||||
3. **Doku & Lernressourcen**:
|
||||
- Offizielle Doku: https://kubernetes.io/docs/
|
||||
- Interaktive Tutorials: Katacoda-ähnliche Labs, Kubernetes Bootcamps, z. B. von Cloud-Anbietern
|
||||
@@ -0,0 +1,25 @@
|
||||
„Layer‑7‑Logik“ bezieht sich auf Entscheidungen/Routing auf Basis der **Anwendungsebene** (Layer 7 im OSI-Modell).
|
||||
|
||||
Kurz zum Kontext:
|
||||
|
||||
- **Layer 3 (Netzwerk)**: IP-Adressen
|
||||
- **Layer 4 (Transport)**: TCP/UDP, Ports (z. B. Port 80, 443)
|
||||
- **Layer 7 (Anwendung)**: HTTP, HTTPS, gRPC, SMTP etc. – also „Inhalt“ der Anfrage
|
||||
|
||||
**Layer‑4‑Routing**:
|
||||
Es wird nur nach IP + Port entschieden. Beispiel:
|
||||
- Alles an `10.0.0.5:80` geht zu Service A.
|
||||
Der Proxy/Loadbalancer „sieht“ nicht, ob das `/api` oder `/shop` ist.
|
||||
|
||||
**Layer‑7‑Logik**:
|
||||
Der Proxy versteht das Protokoll (z. B. HTTP) und kann anhand von Anwendungsdaten entscheiden:
|
||||
|
||||
- Hostname: `api.example.com` → Service A, `shop.example.com` → Service B
|
||||
- Pfad: `/api` → Backend 1, `/app` → Backend 2
|
||||
- HTTP-Header: bestimmter `User-Agent`, `X-Feature-Flag` → anderes Routing
|
||||
- Cookies / Session: z. B. „User ist in A/B-Test-Gruppe → anderes Backend“
|
||||
- Authentifizierung / [[JWT token]] prüfen, bevor weitergeleitet wird
|
||||
- TLS-Termination: HTTPS entschlüsseln, weiter innen nur HTTP sprechen
|
||||
|
||||
Im Kubernetes-Ingress-Kontext heißt „Layer‑7‑Logik“ also:
|
||||
Der Ingress-Controller trifft Routing- und Sicherheitsentscheidungen **auf Basis von HTTP(S)-Details** (Host, Pfad, Header, Cookies usw.), nicht nur auf Basis von IPs und Ports.
|
||||
@@ -0,0 +1,430 @@
|
||||
## 1. Grundidee: Was ist nginx – gerade im Python‑Kontext?
|
||||
|
||||
nginx („engine x“) ist ein **Webserver** und **Reverse Proxy**, der:
|
||||
|
||||
- HTTP(S)-Anfragen aus dem Internet annimmt
|
||||
- statische Dateien (HTML, CSS, Bilder, JS) direkt ausliefert
|
||||
- Anfragen für **dynamische Inhalte** (z.B. deine Python‑App) an einen **Anwendungsserver** weiterleitet (z.B. Gunicorn, uWSGI, [[uvicorn]])
|
||||
|
||||
Im Python‑Kontext wird nginx fast immer als **„Vorderseite“ (Frontend) vor einer Python‑Webanwendung** eingesetzt.
|
||||
|
||||
Typischer Aufbau:
|
||||
|
||||
```text
|
||||
Browser des Nutzers -> nginx -> Gunicorn/uWSGI/uvicorn -> Python-App (Django, Flask, FastAPI, ...)
|
||||
(Port 80/443) (lokaler Port, z.B. 8000)
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 2. Einordnung in die Webwelt: Grundbegriffe
|
||||
|
||||
Damit nginx einzuordnen ist, müssen ein paar Begriffe klar sein:
|
||||
|
||||
### 2.1 Webserver
|
||||
|
||||
Ein **Webserver**:
|
||||
|
||||
- läuft auf einem Rechner (Server)
|
||||
- „lauscht“ auf Port 80 (HTTP) oder 443 (HTTPS)
|
||||
- nimmt HTTP-Anfragen entgegen und schickt HTTP-Antworten zurück
|
||||
|
||||
Beispiele:
|
||||
- **nginx**
|
||||
- **Apache HTTP Server**
|
||||
- (leichtere) Caddy, lighttpd
|
||||
|
||||
### 2.2 Application Server / WSGI-/ASGI-Server
|
||||
|
||||
Ein **Application Server** führt deine **Web-App** aus, also deinen Python-Code.
|
||||
|
||||
- Für klassische synchronen Python-Webapps: **WSGI**-Server
|
||||
- z.B. **[[Gunicorn]]**, **uWSGI**, mod_wsgi
|
||||
- Für moderne, asynchrone Apps: **ASGI**-Server
|
||||
- z.B. **[[uvicorn]]**, **[[hypercorn]]**, Daphne
|
||||
|
||||
Der App-Server:
|
||||
|
||||
- spricht mit deinem Python-Framework (Django, Flask, [[FastAPI]], etc.)
|
||||
- versteht Anfragen im WSGI/ASGI-Format
|
||||
- erzeugt dynamische Antworten (z.B. JSON, HTML aus Templates)
|
||||
|
||||
### 2.3 Python-Webframework (Django, Flask, [[FastAPI]] …)
|
||||
|
||||
Ein **Framework** ist deine Programmierbibliothek, mit der du die Web-App baust:
|
||||
|
||||
- Django: „Vollausstattung“ (ORM, Admin, Auth, etc.)
|
||||
- Flask: minimaler Kern, viel per Erweiterung
|
||||
- [[FastAPI]]: modern, async, stark bei APIs
|
||||
|
||||
**Das Framework ist nicht der Webserver.**
|
||||
Es definiert nur, wie dein Code auf Anfragen reagieren soll.
|
||||
|
||||
---
|
||||
|
||||
## 3. Abgrenzung: nginx vs. verwandte Begriffe
|
||||
|
||||
### 3.1 nginx vs. Apache
|
||||
|
||||
Beide sind **Webserver**, Unterschiede grob:
|
||||
|
||||
- **nginx**
|
||||
- schnell bei vielen gleichzeitigen Verbindungen
|
||||
- ressourcensparend (eventbasiert)
|
||||
- sehr gut als Reverse Proxy, Load Balancer, TLS-Terminator
|
||||
- **Apache**
|
||||
- älter, sehr weit verbreitet
|
||||
- modulbasiert, viel Legacy
|
||||
- kann PHP & Co. direkt ausführen (mod_php, etc.)
|
||||
|
||||
Im modernen Python-Umfeld: **nginx + Gunicorn/[[uvicorn]]** ist ein sehr gängiges Setup.
|
||||
|
||||
### 3.2 nginx vs. [[Gunicorn]]/uWSGI/[[uvicorn]]
|
||||
|
||||
- **nginx**: Webserver / Reverse Proxy
|
||||
- **[[Gunicorn]]/uWSGI/[[uvicorn]]**: Python-Application-Server
|
||||
|
||||
nginx:
|
||||
|
||||
- kümmert sich um HTTP(S), TLS, statische Dateien, Load Balancing
|
||||
- schickt Anfragen an den Application-Server weiter
|
||||
|
||||
[[Gunicorn]]/[[uvicorn]]:
|
||||
|
||||
- startet deine Python-App
|
||||
- verarbeitet die Anfragen logikseitig
|
||||
- rendert Templates, greift auf Datenbanken zu, etc.
|
||||
|
||||
### 3.3 nginx vs. Django/Flask/[[FastAPI]]
|
||||
|
||||
- nginx: Infrastruktur-Komponente (Server)
|
||||
- Django/Flask/[[FastAPI]]: Bibliotheken, mit denen du deinen Code schreibst
|
||||
|
||||
Eine typische Kombi:
|
||||
|
||||
```text
|
||||
nginx + Gunicorn + Django
|
||||
nginx + uvicorn + FastAPI
|
||||
nginx + uWSGI + Flask
|
||||
```
|
||||
|
||||
Jede Komponente hat ihren klaren Aufgabenbereich.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 4. Welche Probleme löst nginx im Python-Setup?
|
||||
|
||||
### 4.1 Sichere und stabile Auslieferung deiner Python-Webapp
|
||||
|
||||
Problem:
|
||||
Die eingebaute Entwicklungsserver in Django/Flask sind nur für **lokale Entwicklung** gedacht:
|
||||
|
||||
- wenig performant
|
||||
- kaum Sicherheitsfeatures
|
||||
- nicht für viele gleichzeitige Nutzer ausgelegt
|
||||
|
||||
Lösung:
|
||||
nginx + App-Server (Gunicorn/uvicorn):
|
||||
|
||||
- nginx nimmt alle Anfragen entgegen
|
||||
- Python-App läuft hinter nginx auf einem internen Port
|
||||
- Anwendung ist stabiler, sicherer, skalierbarer
|
||||
|
||||
### 4.2 Auslieferung statischer Dateien
|
||||
|
||||
Problem:
|
||||
Python-Frameworks sind nicht optimiert, um Millionen von statischen Dateien schnell auszuliefern.
|
||||
|
||||
Lösung:
|
||||
|
||||
- nginx kann statische Dateien extrem effizient ausliefern
|
||||
- Python-App wird entlastet
|
||||
|
||||
**Beispiel:** Django-Setup:
|
||||
|
||||
```text
|
||||
Browser -> nginx -> (statische Dateien: /static/) direkt von nginx
|
||||
-> (dynamische URLs: /api/, /admin/) an Gunicorn/Django
|
||||
```
|
||||
|
||||
### 4.3 HTTPS / TLS-Termination
|
||||
|
||||
Problem:
|
||||
Du willst deine Seite unter **https://deinedomain.de** mit Zertifikat ausliefern.
|
||||
Python-Application-Server kümmern sich eher nicht um Zertifikate.
|
||||
|
||||
Lösung:
|
||||
|
||||
- nginx bietet HTTPS/TLS an (inkl. Let’s Encrypt-Integration)
|
||||
- entschlüsselt eingehende Anfragen
|
||||
- leitet sie dann intern als HTTP an Gunicorn/uvicorn weiter
|
||||
|
||||
So muss sich deine Python-App nicht um Zertifikate kümmern.
|
||||
|
||||
### 4.4 Load Balancing (Lastverteilung)
|
||||
|
||||
Problem:
|
||||
Eine einzelne Instanz deiner Python-App reicht nicht bei hoher Last.
|
||||
|
||||
Lösung:
|
||||
|
||||
- nginx kann Anfragen auf mehrere App-Server verteilen:
|
||||
|
||||
```text
|
||||
Browser -> nginx -> Gunicorn Instanz 1
|
||||
-> Gunicorn Instanz 2
|
||||
-> Gunicorn Instanz 3
|
||||
```
|
||||
|
||||
Damit erreichst du höhere Verfügbarkeit und Kapazität.
|
||||
|
||||
### 4.5 Reverse Proxy / Schutz der App
|
||||
|
||||
Problem:
|
||||
Du willst deine App nicht direkt ins Internet hängen (Sicherheitsrisiko, private Ports).
|
||||
|
||||
Lösung:
|
||||
|
||||
- nginx steht „davor“ und leitet nur definierte Anfragen durch
|
||||
- interne Ports (z.B. 8000) sind von außen nicht erreichbar
|
||||
- nginx kann zusätzliche Security-Header, Ratelimits, IP-Filter etc. einsetzen
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 5. Herausforderungen bei der Arbeit mit nginx
|
||||
|
||||
### 5.1 Konfigurationssyntax & -struktur
|
||||
|
||||
- nginx wird über Textdateien konfiguriert (z.B. `/etc/nginx/nginx.conf` und `sites-available/...`)
|
||||
- die Syntax ist am Anfang ungewohnt:
|
||||
- `http`, `server`, `location`, `upstream`, `listen`, etc.
|
||||
- Fehler in der Konfiguration führen dazu, dass nginx nicht startet oder falsch weiterleitet
|
||||
|
||||
Praxis-Hinweise:
|
||||
|
||||
```bash
|
||||
sudo nginx -t # Konfiguration testen
|
||||
sudo systemctl reload nginx # Konfiguration neu laden
|
||||
```
|
||||
|
||||
### 5.2 Rechte & Pfade (Linux-Dateisystem)
|
||||
|
||||
Probleme:
|
||||
|
||||
- nginx läuft als bestimmter Benutzer (z.B. `www-data`)
|
||||
- Python-App läuft evtl. als anderer Benutzer (z.B. `myapp`)
|
||||
- Zugriffsrechte auf Dateien/Ordner (Logs, statische Dateien) müssen passen
|
||||
|
||||
Beispiel:
|
||||
Wenn statische Dateien unter `/var/www/myapp/static/` liegen, muss der nginx-User Lesezugriff haben.
|
||||
|
||||
### 5.3 Fehlersuche (Debugging)
|
||||
|
||||
- Fehler können an mehreren Stellen auftreten:
|
||||
- DNS / Domain falsch
|
||||
- nginx-Konfiguration fehlerhaft
|
||||
- App-Server (Gunicorn/uvicorn) läuft nicht
|
||||
- Python-App wirft Fehler
|
||||
|
||||
Praxis-Tipp:
|
||||
|
||||
- in nginx-Logs schauen:
|
||||
- `/var/log/nginx/access.log`
|
||||
- `/var/log/nginx/error.log`
|
||||
- in App-Logs schauen
|
||||
- Ports prüfen: `ss -tulpen` oder `netstat -tulpen`
|
||||
|
||||
### 5.4 Performance-Tuning
|
||||
|
||||
Fortgeschrittener, aber wichtig bei größerem Traffic:
|
||||
|
||||
- wie viele Worker-Prozesse nginx nutzt
|
||||
- Keep-Alive-Einstellungen
|
||||
- Buffergrößen
|
||||
- Cache-Konfiguration für statische Inhalte
|
||||
|
||||
Am Anfang reicht meist die Standardkonfiguration, später optimiert man bei Bedarf.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 6. Praxisnahe Beispiele
|
||||
|
||||
### 6.1 Minimalbeispiel: Flask-App hinter nginx + Gunicorn
|
||||
|
||||
**1. Eine einfache Flask-App (Python)**
|
||||
|
||||
Datei: `app.py`
|
||||
|
||||
```python
|
||||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return "Hallo, Welt! Das kommt aus Flask hinter nginx."
|
||||
```
|
||||
|
||||
Start des App-Servers (Gunicorn):
|
||||
|
||||
```bash
|
||||
pip install flask gunicorn
|
||||
gunicorn -w 3 -b 127.0.0.1:8000 app:app
|
||||
# -w 3: 3 Worker
|
||||
# -b 127.0.0.1:8000: lauscht auf Port 8000 nur lokal
|
||||
```
|
||||
|
||||
**2. nginx-Konfiguration (vereinfacht)**
|
||||
|
||||
Datei: z.B. `/etc/nginx/sites-available/myflaskapp`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com; # deine Domain oder IP
|
||||
|
||||
# Statische Dateien (wenn du welche hast)
|
||||
# root /var/www/myflaskapp; # falls du HTML/Assets direkt ablegen willst
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8000; # Gunicorn
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Dann:
|
||||
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/myflaskapp /etc/nginx/sites-enabled/
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
Ablauf:
|
||||
|
||||
1. Browser ruft `http://example.com/` auf
|
||||
2. nginx nimmt Anfrage auf Port 80 entgegen
|
||||
3. nginx leitet an `http://127.0.0.1:8000` weiter (Gunicorn/Flask)
|
||||
4. Flask antwortet mit „Hallo, Welt“
|
||||
5. nginx sendet diese Antwort an den Browser zurück
|
||||
|
||||
|
||||
### 6.2 Beispiel: Django mit statischen Dateien
|
||||
|
||||
**1. Django-Setup (stark vereinfacht)**
|
||||
|
||||
In `settings.py`:
|
||||
|
||||
```python
|
||||
STATIC_URL = "/static/"
|
||||
STATIC_ROOT = "/var/www/mydjangoproject/static/"
|
||||
```
|
||||
|
||||
Danach statische Dateien sammeln:
|
||||
|
||||
```bash
|
||||
python manage.py collectstatic
|
||||
```
|
||||
|
||||
**2. nginx-Konfiguration (Ausschnitt)**
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
|
||||
# Statische Dateien direkt von nginx
|
||||
location /static/ {
|
||||
alias /var/www/mydjangoproject/static/;
|
||||
access_log off;
|
||||
expires 30d;
|
||||
}
|
||||
|
||||
# Alles andere an Django via Gunicorn
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8001; # hier läuft Gunicorn
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Vorteil:
|
||||
|
||||
- statische Inhalte kommen extrem schnell von nginx
|
||||
- Django/Gunicorn verarbeitet nur „echte“ App-Logik
|
||||
|
||||
|
||||
### 6.3 Beispiel: HTTPS mit Let’s Encrypt (Konzept)
|
||||
|
||||
Mit Tools wie **certbot** kannst du für nginx kostenlos TLS-Zertifikate holen.
|
||||
|
||||
Grobe Schritte:
|
||||
|
||||
```bash
|
||||
sudo apt install certbot python3-certbot-nginx
|
||||
sudo certbot --nginx -d example.com
|
||||
```
|
||||
|
||||
certbot:
|
||||
|
||||
- holt Zertifikat
|
||||
- passt nginx-Konfiguration an (Port 443, SSL-Parameter)
|
||||
- richtet automatische Erneuerung ein
|
||||
|
||||
nginx-Konfiguration enthält danach z.B.:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name example.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Damit ist deine Python-App per HTTPS erreichbar.
|
||||
|
||||
---
|
||||
|
||||
## 7. Zusammenfassung
|
||||
|
||||
- **nginx** ist ein leistungsfähiger Webserver und Reverse Proxy, der im Python-Kontext typischerweise:
|
||||
- vor deiner Python-Webanwendung sitzt
|
||||
- HTTP(S) abwickelt
|
||||
- statische Dateien effizient ausliefert
|
||||
- Anfragen an einen Python-Application-Server (Gunicorn, uWSGI, uvicorn) weiterleitet
|
||||
- TLS/HTTPS, Load Balancing, Security-Features bereitstellt
|
||||
|
||||
- **Abgrenzung**:
|
||||
- nginx ≠ Python-Framework (Django/Flask/[[FastAPI]])
|
||||
- nginx ≠ Application-Server (Gunicorn/uvicorn)
|
||||
- nginx = Webserver/Reverse Proxy
|
||||
|
||||
- **Gelöste Probleme**:
|
||||
- sichere Produktion anstelle von Entwicklungsservern
|
||||
- Performance für statische Inhalte
|
||||
- TLS/HTTPS, Lastverteilung, Schutz der App
|
||||
|
||||
- **Herausforderungen**:
|
||||
- Konfigurationsdateien verstehen
|
||||
- Rechte & Pfade korrekt setzen
|
||||
- Fehler systematisch debuggen
|
||||
- bei hoher Last Performance tunen
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
Im Folgenden bekommst du eine Einführung in OAuth 2, so dass du danach:
|
||||
|
||||
- weißt, was OAuth 2 grundsätzlich ist,
|
||||
- es von verwandten Konzepten wie „Login mit Google“, OpenID Connect oder reiner Authentifizierung unterscheiden kannst,
|
||||
- verstehst, welche Probleme OAuth 2 löst – und welche neuen Herausforderungen es mit sich bringt,
|
||||
- und ein paar praxisnahe Szenarien im Kopf hast.
|
||||
|
||||
---
|
||||
|
||||
## 1. Grundsätzliche Definition: Was ist OAuth 2?
|
||||
|
||||
**Kurze Definition**:
|
||||
OAuth 2 ist ein *Autorisierungs*-Framework. Es regelt, wie eine Anwendung (Client) **im Namen eines Benutzers** sicher auf Ressourcen (z. B. APIs, Daten) zugreifen kann, **ohne dass die Anwendung das Passwort des Benutzers kennen muss**.
|
||||
|
||||
Es geht also primär um:
|
||||
|
||||
- **Zugriffsrechte (Authorization)**
|
||||
- **Delegation**: „Ich (Nutzer) erlaube App X, auf meine Daten bei Dienst Y zuzugreifen.“
|
||||
|
||||
### Zentrales Prinzip
|
||||
|
||||
Statt:
|
||||
- Benutzer gibt sein Passwort direkt bei jeder Drittanbieter-App ein
|
||||
|
||||
nutzt man:
|
||||
- Benutzer loggt sich beim **vertrauenswürdigen Dienst** ein (z. B. Google, GitHub, dein Unternehmens-Identity-Server)
|
||||
- Dieser Dienst stellt ein **Token** aus (eine Art Eintrittskarte)
|
||||
- Drittanbieter-App nutzt dieses Token, um beim API-Server Zugriff zu bekommen
|
||||
|
||||
Dadurch muss die Drittanbieter-App nie das Passwort sehen – sie bekommt **nur einen begrenzten, kontrollierten Zugriff**.
|
||||
|
||||
---
|
||||
|
||||
## 2. Die wichtigsten Rollen in OAuth 2
|
||||
|
||||
Um Beispiele zu verstehen, braucht man die Standardrollen:
|
||||
|
||||
1. **Resource Owner**
|
||||
Der Besitzer der Daten/Ressourcen – meist der **Benutzer**.
|
||||
|
||||
2. **Client**
|
||||
Die Anwendung, die im Namen des Benutzers zugreifen möchte
|
||||
(z. B. eine mobile App, eine Web-App, ein Backend-Service).
|
||||
|
||||
3. **Resource Server**
|
||||
Die API/das System, das die geschützten Ressourcen bereitstellt
|
||||
(z. B. Google Calendar API, GitHub API, Unternehmens-REST-API).
|
||||
|
||||
4. **Authorization Server**
|
||||
Der Server, der:
|
||||
- den Benutzer authentifiziert (z. B. Login-Formular) und
|
||||
- **Tokens** ausstellt (Access Tokens, optional Refresh Tokens).
|
||||
|
||||
Oft sind Authorization Server und Resource Server derselbe technische Dienst, aber **konzeptionell** werden sie getrennt betrachtet.
|
||||
|
||||
---
|
||||
|
||||
## 3. Grund-Mechanik: Wie läuft ein OAuth-2-Flow ab?
|
||||
|
||||
Stark vereinfacht am typischen Web-Szenario:
|
||||
|
||||
1. Benutzer nutzt eine Drittanbieter-App (Client) und klickt z. B. auf:
|
||||
„Verbinde dich mit meinem Google-Kalender“.
|
||||
|
||||
2. Client leitet den Browser zum **Authorization Server** (z. B. accounts.google.com) weiter:
|
||||
- mit Angaben wie: „Diese App möchte Zugriff auf Kalenderdaten“.
|
||||
|
||||
3. Benutzer loggt sich **beim Authorization Server** ein (falls nicht schon eingeloggt).
|
||||
|
||||
4. Benutzer bekommt eine Seite angezeigt:
|
||||
„Die Anwendung X möchte auf Ihre Kalenderdaten zugreifen. Erlauben? (Ja/Nein)“
|
||||
|
||||
5. Wenn Benutzer zustimmt:
|
||||
- Authorization Server schickt den Benutzer zurück zur App
|
||||
- Die App bekommt einen **Authorization Code** (bei einem gängigen Flow).
|
||||
|
||||
6. Die App tauscht diesen Code im Hintergrund beim Authorization Server gegen ein **Access Token** (und evtl. ein **Refresh Token**) ein.
|
||||
|
||||
7. Die App nutzt das Access Token, um beim **Resource Server** (z. B. Google Calendar API) Daten abzufragen.
|
||||
|
||||
Der Benutzer muss sein **Passwort nur beim Authorization Server** eingeben – nicht bei der Drittanbieter-App.
|
||||
|
||||
---
|
||||
|
||||
## 4. Abgrenzung zu ähnlichen / verwandten Begriffen
|
||||
|
||||
### 4.1 OAuth 2 (Authorization) vs. Authentifizierung (Login)
|
||||
|
||||
**Authentifizierung**: „Wer bist du?“
|
||||
**Autorisierung**: „Worauf darfst du zugreifen?“
|
||||
|
||||
- OAuth 2 löst formal **Autorisierung** (Delegation von Zugriffsrechten).
|
||||
- Viele Systeme nutzen OAuth 2 aber **im Zusammenhang mit Login**, was verwirrend sein kann.
|
||||
|
||||
Ein Login mit Google, bei dem eine Anwendung am Ende weiß „dieser User ist Max Mustermann“, basiert meist auf **OpenID Connect**, das **auf OAuth 2 aufsetzt**.
|
||||
|
||||
### 4.2 OAuth 2 vs. OpenID Connect (OIDC)
|
||||
|
||||
- **OAuth 2**: Spezifiziert, wie Clients **Access Tokens** bekommen, um auf APIs zuzugreifen.
|
||||
- **OpenID Connect**: Erweiterung auf Basis von OAuth 2, um **Identität** zu transportieren.
|
||||
|
||||
OIDC liefert zusätzlich:
|
||||
- ein **ID Token** (meist ein [[JWT token]]), das Informationen wie:
|
||||
- User-ID
|
||||
- E-Mail
|
||||
- Name
|
||||
enthält.
|
||||
|
||||
Praxis-Beispiele:
|
||||
|
||||
- „Mit Google anmelden“ (Login) → **OpenID Connect**
|
||||
- „Google Kalender-API nutzen“ → **OAuth 2** (Autorisierung für API-Zugriff)
|
||||
|
||||
### 4.3 OAuth 2 vs. API-Key
|
||||
|
||||
**API-Key**:
|
||||
- Meist ein statischer Schlüssel, der im Client eingebaut ist.
|
||||
- Unterscheidet nicht zwischen verschiedenen Benutzern.
|
||||
- Hat wenig feingranulare Rechte (oft: „alles oder nichts“).
|
||||
- Sicherheitsrisiko bei Leaks (z. B. im Frontend-Code).
|
||||
|
||||
**OAuth 2**:
|
||||
- Nutzerbezogen (Access Token repräsentiert den Benutzer/das Delegationsrecht).
|
||||
- Token haben meist begrenzte Lebensdauer.
|
||||
- Zugriffsrechte (Scopes) sind feiner steuerbar.
|
||||
|
||||
### 4.4 OAuth 2 vs. SAML
|
||||
|
||||
- **SAML**: Älterer Standard, XML-basiert, häufig in Unternehmensumgebungen für SSO verwendet.
|
||||
- **OAuth 2 / OIDC**: JSON/HTTP-basiert, leichtergewichtig, stark im Web- und Mobile-Bereich verbreitet.
|
||||
|
||||
Grober Merksatz:
|
||||
- SAML: klassische Unternehmen, Single Sign-On im Browser, ältere Infrastruktur.
|
||||
- OAuth 2 + OIDC: moderne Web-/Mobile-Apps, REST-APIs, Microservices.
|
||||
|
||||
---
|
||||
|
||||
## 5. Welche Probleme löst OAuth 2?
|
||||
|
||||
### 5.1 Vermeidung von Passwortweitergabe an Drittanbieter
|
||||
|
||||
Früher:
|
||||
Eine App wollte auf Gmail zugreifen => Benutzer musste **sein Gmail-Passwort** in dieser App eingeben.
|
||||
Risiken:
|
||||
- App könnte Passwort speichern oder missbrauchen.
|
||||
- Bei Passwortänderung müsste der Benutzer alles neu einrichten.
|
||||
- Anbieter (Google) hat keine Kontrolle, welche App das tut.
|
||||
|
||||
Mit OAuth 2:
|
||||
- Benutzer loggt sich nur bei Google ein.
|
||||
- Drittanbieter-App erhält nur ein **Token mit begrenzten Rechten**, kein Passwort.
|
||||
|
||||
**Praxisbeispiel**:
|
||||
Eine To-Do-App möchte deine Google Kalender-Einträge anzeigen:
|
||||
Du klickst „Mit Google verbinden“, wirst zu Google geleitet, bestätigst die Berechtigungen und die App sieht danach deine Kalender – ohne dein Passwort zu kennen.
|
||||
|
||||
### 5.2 Feingranulare Zugriffsrechte (Scopes)
|
||||
|
||||
Mit **Scopes** kann eingeschränkt werden, worauf eine App zugreifen darf.
|
||||
|
||||
Beispiele:
|
||||
- `read_calendar`: nur Leserechte auf Kalender
|
||||
- `write_calendar`: Schreibrechte auf Kalender
|
||||
- `email`: Zugriff auf deine E-Mail-Adresse
|
||||
- `profile`: Zugriff auf deine Basisprofildaten
|
||||
|
||||
So kann der Benutzer (und auch der Resource Server) klar kontrollieren:
|
||||
- Eine App darf z. B. **nur lesen**, nicht schreiben.
|
||||
- Eine App darf **nur auf E-Mail und Profil**, nicht auf Kontakte oder Drive zugreifen.
|
||||
|
||||
### 5.3 Zeitlich begrenzte Tokens
|
||||
|
||||
**Access Tokens** sind typischerweise kurzlebig (z. B. 5–60 Minuten).
|
||||
|
||||
- Wenn ein Token geleakt wird, ist der Schaden zeitlich begrenzt.
|
||||
- Über Revocation-Mechanismen kann der Zugriff vorzeitig beendet werden.
|
||||
|
||||
Optional gibt es **Refresh Tokens**:
|
||||
- Länger gültig
|
||||
- Dienen dazu, neue Access Tokens zu holen
|
||||
- Können vom Authorization Server gezielt deaktiviert werden (z. B. bei Kompromittierung).
|
||||
|
||||
### 5.4 Single Sign-On / bessere User Experience (in Kombination mit OIDC)
|
||||
|
||||
In Kombination mit OIDC und Single-Sign-On-Konzepten:
|
||||
- Benutzer loggt sich einmal beim zentralen Identity Provider ein.
|
||||
- Mehrere Anwendungen können dann in einer Session auf Tokens zugreifen, ohne den Benutzer jedes Mal neu einzuloggen.
|
||||
|
||||
---
|
||||
|
||||
## 6. Typische OAuth-2-Flows (vereinfacht)
|
||||
|
||||
Es gibt verschiedene **„Flows“**, je nach Art des Clients und Nutzungsszenario. Die wichtigsten:
|
||||
|
||||
### 6.1 Authorization Code Flow (heute mit PKCE)
|
||||
|
||||
Typisch für:
|
||||
- Web-Anwendungen mit Backend
|
||||
- Single Page Applications (mit PKCE)
|
||||
- Mobile Apps
|
||||
|
||||
Ablauf (vereinfacht, ohne technische Details):
|
||||
|
||||
1. Anwendung leitet Benutzer zum Authorization Server.
|
||||
2. Benutzer loggt sich ein und stimmt zu.
|
||||
3. Authorization Server schickt **Authorization Code** an die Anwendung (über Redirect).
|
||||
4. Anwendung tauscht Code gegen ein **Access Token** (und optional Refresh Token).
|
||||
|
||||
**PKCE** (Proof Key for Code Exchange) ist eine Sicherheits-Erweiterung, um Code-Diebstahl zu verhindern, insbesondere bei mobilen/Browser-basierten Apps.
|
||||
|
||||
### 6.2 Client Credentials Flow
|
||||
|
||||
Für:
|
||||
- Machine-to-Machine-Kommunikation (kein Benutzer)
|
||||
- Hintergrundprozesse, Microservices, Server-zu-Server
|
||||
|
||||
Hier gibt es keinen Benutzer.
|
||||
Der Client identifiziert sich selbst (z. B. mit Client ID + Client Secret) beim Authorization Server und bekommt ein Access Token, um auf eine API zuzugreifen.
|
||||
|
||||
**Beispiel**:
|
||||
Ein Backend-Service ruft periodisch eine interne Unternehmens-API auf, um Daten zu synchronisieren.
|
||||
|
||||
### 6.3 Device Code Flow
|
||||
|
||||
Für Geräte ohne vollwertigen Browser oder ohne komfortable Eingabemöglichkeit, wie:
|
||||
- Smart-TVs
|
||||
- Konsolen
|
||||
- IoT-Geräte
|
||||
|
||||
Ablauf:
|
||||
- Gerät zeigt einen Code und eine URL an (z. B. „Bitte gehen Sie auf https://example.com/device und geben Sie Code ABCD ein“).
|
||||
- Benutzer geht an seinem Smartphone/PC auf diese URL, loggt sich dort ein und bestätigt.
|
||||
- Gerät bekommt anschließend ein Token und kann auf die Ressource zugreifen.
|
||||
|
||||
---
|
||||
|
||||
## 7. Herausforderungen und typische Stolperfallen
|
||||
|
||||
### 7.1 OAuth 2 ist komplex und flexibel
|
||||
|
||||
OAuth 2 ist sehr flexibel – das ist Stärke und Schwäche zugleich:
|
||||
|
||||
- Viele Optionen & Erweiterungen → schnell unübersichtlich.
|
||||
- Viele Entscheidungen zu treffen: Flows, Token-Formate, Scopes, Lifetimes, PKCE, etc.
|
||||
|
||||
Für Einsteiger wirkt es oft „überdimensioniert“, vor allem wenn man nur „einen einfachen Login“ braucht (wo eigentlich OIDC gefragt ist).
|
||||
|
||||
### 7.2 Verwechslung von OAuth 2 und Login
|
||||
|
||||
Weil viele große Anbieter beides kombiniert haben („Login mit Google“), entsteht oft:
|
||||
|
||||
- „OAuth 2 ist ein Login-Protokoll.“ → **Formal falsch**, es ist ein Autorisierungsframework.
|
||||
- Für „Login“ verwendet man **OpenID Connect**, auch wenn technisch OAuth-2-Mechanismen verwendet werden.
|
||||
|
||||
Konsequenz:
|
||||
Fehlkonzeptionen in Projekten, z. B. versucht man reine OAuth-2-Tokens zu nutzen, um Identität abzuleiten, statt OIDC zu verwenden.
|
||||
|
||||
### 7.3 Sicherheitsrisiken bei falscher Implementierung
|
||||
|
||||
Einige typische Fehler:
|
||||
|
||||
- **Tokens in URLs weitergeben** → landen in Logs, Browser-History, Referrer-Headern.
|
||||
- **Implicit Flow** für Single-Page-Apps ohne ausreichende Sicherheitsmaßnahmen
|
||||
→ gilt inzwischen als überholt; empfohlen wird Authorization Code Flow mit PKCE.
|
||||
- **Keine Einschränkung der Redirect-URIs** → Angreifer können Redirect-URIs manipulieren und Tokens abfangen.
|
||||
- **Zu lange gültige Tokens** → höheres Risiko bei Leaks.
|
||||
- **Speichern von Tokens im unsicheren Speicher** (z. B. localStorage in Browsern) → anfällig für XSS.
|
||||
|
||||
### 7.4 Komplexität für Endnutzer
|
||||
|
||||
Auch für Endnutzer ist die Zustimmung manchmal nicht klar:
|
||||
|
||||
- „Diese App möchte auf Ihr Profil, Ihre Kontakte, Ihre Dateien, Ihre E-Mails zugreifen.“
|
||||
→ Viele klicken aus Gewohnheit auf „Zulassen“, ohne zu verstehen, was das bedeutet.
|
||||
|
||||
Das ist eher ein UX-/Privacy-Thema, aber eng mit OAuth 2 verbunden, da die Darstellung der **Scopes** oft technisch und verwirrend ist.
|
||||
|
||||
---
|
||||
|
||||
## 8. Praxisnahe Beispiele
|
||||
|
||||
### Beispiel 1: „Mit Google anmelden“ in einer Web-App
|
||||
|
||||
**Situation**:
|
||||
Du entwickelst eine Web-App, in der sich Nutzer anmelden können. Statt ein eigenes Benutzerkontensystem aufzubauen, willst du „Login mit Google“ anbieten.
|
||||
|
||||
**In Wahrheit passiert (typisch)**:
|
||||
- Die App nutzt **OpenID Connect**:
|
||||
- OAuth 2 regelt den Token-Flow.
|
||||
- OIDC liefert ein ID Token mit Infos über den Benutzer.
|
||||
- Nutzer sieht: Google-Login, eine Consent-Seite, und wird danach in deine App zurückgeleitet.
|
||||
- Deine App bekommt:
|
||||
- ein **ID Token** (zur Identifikation des Nutzers)
|
||||
- ein **Access Token** (um z. B. zusätzlich auf Google APIs zuzugreifen, falls gewünscht).
|
||||
|
||||
**OAuth-2-Aspekt**:
|
||||
Der eigentliche Mechanismus, wie Access Token ausgestellt werden, ist OAuth 2.
|
||||
|
||||
### Beispiel 2: Drittanbieter-Tool liest GitHub-Repositories
|
||||
|
||||
**Situation**:
|
||||
Ein Build-Tool oder eine CI/CD-Plattform möchte deine privaten GitHub-Repositories lesen, um Builds auszulösen.
|
||||
|
||||
Ablauf:
|
||||
1. In der CI/CD-Plattform klickst du „Mit GitHub verbinden“.
|
||||
2. Du wirst zu GitHub weitergeleitet, loggst dich ein.
|
||||
3. GitHub zeigt dir eine Seite:
|
||||
„Tool X möchte Zugriff auf:
|
||||
- Ihre öffentlichen und privaten Repositories
|
||||
- Ihre Webhooks
|
||||
…“
|
||||
4. Du erlaubst.
|
||||
5. Die CI/CD-Plattform erhält ein Access Token mit bestimmten **Scopes** (z. B. `repo`).
|
||||
|
||||
**OAuth-2-Aspekt**:
|
||||
- Das Access Token erlaubt der CI/CD-Plattform, im Namen deines GitHub-Accounts zu agieren, innerhalb des erlaubten Scopes.
|
||||
|
||||
### Beispiel 3: Unternehmensinternes Microservice-System
|
||||
|
||||
**Situation**:
|
||||
In einer Microservice-Architektur gibt es:
|
||||
- einen zentralen Authorization Server (z. B. Keycloak, Auth0, Azure AD),
|
||||
- viele Services, die interne APIs bereitstellen.
|
||||
|
||||
Szenario:
|
||||
- Ein Frontend bekommt vom Authorization Server (über einen Login) ein Access Token.
|
||||
- Dieses Access Token wird vom Frontend bei Aufrufen an das API-Gateway oder direkt an Microservices mitgeschickt.
|
||||
- Microservices verifizieren das Token und entscheiden anhand von Scopes/Rollen, ob der Zugriff erlaubt ist.
|
||||
|
||||
**OAuth-2-Aspekt**:
|
||||
- Zugriffskontrolle wird zentralisiert.
|
||||
- Jeder Service muss nicht mehr selbst Benutzer verwalten, sondern nur Access Tokens prüfen.
|
||||
|
||||
---
|
||||
|
||||
## 9. Zusammenfassung in Stichpunkten
|
||||
|
||||
- **OAuth 2** ist ein **Autorisierungs-Framework** (nicht direkt ein Login-Protokoll).
|
||||
- Es ermöglicht, dass **Drittanbieter-Apps im Namen eines Nutzers** auf Ressourcen zugreifen können, ohne das Passwort des Nutzers zu kennen.
|
||||
- Wichtige Rollen: **Resource Owner**, **Client**, **Resource Server**, **Authorization Server**.
|
||||
- Es arbeitet mit **Tokens** (Access Tokens, optional Refresh Tokens) und **Scopes** (feingranulare Rechte).
|
||||
- Verwandte Standards:
|
||||
- **OpenID Connect**: für Authentifizierung/Identität (baut auf OAuth 2 auf).
|
||||
- **SAML**: alternative, ältere Lösung v. a. für SSO in Unternehmen.
|
||||
- Es löst Probleme wie:
|
||||
- Passwortweitergabe an Drittanbieter
|
||||
- Fehlende Feingranularität von Zugriffsrechten
|
||||
- Mangelnde Kontrolle über Zugriffsdelegation
|
||||
- Herausforderungen:
|
||||
- Komplexität und viele Optionen
|
||||
- Verwechslungsgefahr mit Authentifizierung
|
||||
- Sicherheitsrisiken bei falscher Implementierung
|
||||
- UX/Verständlichkeit von Zustimmungsdialogen
|
||||
- Praxis:
|
||||
- „Mit Google/GitHub/Facebook anmelden“
|
||||
- Drittanbieter-Apps, die auf APIs zugreifen
|
||||
- Microservice-Systeme mit zentralem Identity & Access Management
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,530 @@
|
||||
#infrastructure #Cloud
|
||||
## 1. Was ist Terraform?
|
||||
|
||||
Terraform ist ein Open-Source-Tool (ursprünglich MIT, seit 2023 Business Source License, BSL) von HashiCorp zur **deklarativen** Beschreibung und Verwaltung von Infrastruktur als Code (Infrastructure as Code, IaC).
|
||||
|
||||
Mit Terraform kannst du:
|
||||
|
||||
- Infrastruktur in Cloud-Providern (AWS, Azure, GCP, …), On-Premise und weiteren Systemen **beschreiben** (als Code).
|
||||
- Aus dieser Beschreibung eine **gewünschte Zielkonfiguration** (Desired State) definieren.
|
||||
- Terraform berechnet dann, **welche Änderungen nötig sind**, um vom Ist-Zustand zum Soll-Zustand zu gelangen.
|
||||
- Diese Änderungen werden mit `terraform apply` **automatisch ausgeführt**.
|
||||
|
||||
Terraform ist besonders stark in:
|
||||
|
||||
- **Multi-Cloud- und Hybrid-Szenarien**
|
||||
- **Reproduzierbaren Umgebungen** (z.B. Dev, Test, Prod)
|
||||
- **Versionierbarer Infrastruktur** (Git)
|
||||
- **Team-Kollaboration** an Infrastruktur
|
||||
|
||||
---
|
||||
|
||||
## 2. Grundkonzepte von Terraform
|
||||
|
||||
Die wichtigsten Bausteine:
|
||||
|
||||
### 2.1 Provider
|
||||
|
||||
Provider sind die „Treiber“, mit denen Terraform mit einem externen System spricht, z.B.:
|
||||
|
||||
- `aws` – Amazon Web Services
|
||||
- `azurerm` – Microsoft Azure
|
||||
- `google` – Google Cloud
|
||||
- `kubernetes` – Kubernetes-Cluster
|
||||
- `helm`, `docker`, `vault`, `github`, viele weitere
|
||||
|
||||
In Terraform-Code bindet man einen Provider ein, z.B.:
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = "eu-central-1"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Ressourcen
|
||||
|
||||
**Ressourcen** (`resource`) sind die eigentlichen Infrastruktur-Objekte, z.B.:
|
||||
|
||||
- `aws_instance` (EC2-VM)
|
||||
- `aws_s3_bucket`
|
||||
- `azurerm_resource_group`
|
||||
- `google_compute_instance`
|
||||
|
||||
Beispiel:
|
||||
|
||||
```hcl
|
||||
resource "aws_s3_bucket" "example" {
|
||||
bucket = "mein-terraform-bucket-12345"
|
||||
acl = "private"
|
||||
}
|
||||
```
|
||||
|
||||
`aws_s3_bucket` ist der Ressourcentyp, `"example"` der Name innerhalb der Terraform-Konfiguration.
|
||||
|
||||
### 2.3 Datenquellen (Data Sources)
|
||||
|
||||
`data`-Blöcke lesen Informationen aus einer bestehenden Umgebung, ohne etwas zu verändern.
|
||||
|
||||
```hcl
|
||||
data "aws_ami" "ubuntu" {
|
||||
most_recent = true
|
||||
|
||||
filter {
|
||||
name = "name"
|
||||
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
|
||||
}
|
||||
|
||||
owners = ["099720109477"] # Canonical
|
||||
}
|
||||
```
|
||||
|
||||
Die Daten können dann in Ressourcen verwendet werden.
|
||||
|
||||
### 2.4 Variablen und Outputs
|
||||
|
||||
**Variablen** (`variable`) erlauben Parametrisierung:
|
||||
|
||||
```hcl
|
||||
variable "region" {
|
||||
type = string
|
||||
default = "eu-central-1"
|
||||
description = "AWS Region"
|
||||
}
|
||||
```
|
||||
|
||||
Aufgerufen z.B.: `var.region`.
|
||||
|
||||
**Outputs** (`output`) geben wichtige Informationen aus (z.B. IP-Adressen):
|
||||
|
||||
```hcl
|
||||
output "instance_ip" {
|
||||
value = aws_instance.web.public_ip
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 Module
|
||||
|
||||
Module sind wiederverwendbare Bausteine von Terraform-Konfigurationen (eine Art „Bibliothek“ von Infrastruktur).
|
||||
|
||||
- Ein Modul ist einfach ein Ordner mit `.tf`-Dateien.
|
||||
- Man kann eigene Module oder Community-Module nutzen (z.B. aus dem Terraform Registry).
|
||||
|
||||
Beispiel Nutzung eines Moduls:
|
||||
|
||||
```hcl
|
||||
module "network" {
|
||||
source = "./modules/network"
|
||||
|
||||
vpc_cidr = "10.0.0.0/16"
|
||||
}
|
||||
```
|
||||
|
||||
Oder:
|
||||
|
||||
```hcl
|
||||
module "vpc" {
|
||||
source = "terraform-aws-modules/vpc/aws"
|
||||
version = "5.0.0"
|
||||
|
||||
name = "main-vpc"
|
||||
cidr = "10.0.0.0/16"
|
||||
azs = ["eu-central-1a", "eu-central-1b"]
|
||||
}
|
||||
```
|
||||
|
||||
### 2.6 Terraform State
|
||||
|
||||
Terraform hält den Zustand der verwalteten Ressourcen in einer **State-Datei** (`terraform.tfstate`) fest.
|
||||
|
||||
- Der State ist die „Wahrheit“, mit der Terraform den Ist-Zustand kennt.
|
||||
- Daran erkennt Terraform, welche Ressource es schon erstellt hat und wie deren IDs, Attribute usw. sind.
|
||||
- Änderungen am Code werden mit dem State abgeglichen → Terraform generiert einen Plan.
|
||||
|
||||
State kann liegen:
|
||||
|
||||
- lokal: `terraform.tfstate` im Projektordner
|
||||
- remote (empfohlen für Teams): z.B. in S3, Azure Storage, GCS, Terraform Cloud, etc.
|
||||
|
||||
Beispiel Backend-Konfiguration (Remote State mit S3):
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = "my-terraform-state-bucket"
|
||||
key = "prod/terraform.tfstate"
|
||||
region = "eu-central-1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Typischer Terraform-Workflow
|
||||
|
||||
### 3.1 Projektstruktur
|
||||
|
||||
Beispiel:
|
||||
|
||||
```text
|
||||
.
|
||||
├── main.tf # Ressourcen, Module
|
||||
├── variables.tf # Variablen
|
||||
├── outputs.tf # Outputs
|
||||
└── providers.tf # Provider / Backend
|
||||
```
|
||||
|
||||
### 3.2 Wichtige Terraform-Kommandos
|
||||
|
||||
1. `terraform init`
|
||||
- Initialisiert das Projekt
|
||||
- Lädt Provider-Plugins
|
||||
- Konfiguriert Backend (State)
|
||||
|
||||
2. `terraform plan`
|
||||
- Zeigt, was Terraform ändern würde (Create/Update/Delete)
|
||||
- Verändert noch nichts
|
||||
- Wichtig für Review (z.B. im CI)
|
||||
|
||||
3. `terraform apply`
|
||||
- Führt den Plan aus (Standard: vorher Anzeige + Bestätigung)
|
||||
- Erzeugt/aktualisiert/löscht Ressourcen
|
||||
|
||||
4. `terraform destroy`
|
||||
- Löscht alle Ressourcen, die Terraform verwaltet
|
||||
- Vorsicht: de facto „Infrastruktur-Abbau“
|
||||
|
||||
Typischer Ablauf:
|
||||
|
||||
```bash
|
||||
terraform init
|
||||
terraform plan
|
||||
terraform apply
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Terraform-Sprache: HCL (HashiCorp Configuration Language)
|
||||
|
||||
Terraform benutzt HCL, eine deklarative, blockbasierte Sprache.
|
||||
|
||||
### 4.1 Syntax-Grundlagen
|
||||
|
||||
Blöcke haben Form:
|
||||
|
||||
```hcl
|
||||
resource "TYP" "NAME" {
|
||||
argument = "value"
|
||||
|
||||
block {
|
||||
nested_arg = 123
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Datentypen:
|
||||
|
||||
- `string` – `"Text"`
|
||||
- `number` – `42`
|
||||
- `bool` – `true` / `false`
|
||||
- Listen – `["a", "b"]`
|
||||
- Maps – `{ key = "value" }`
|
||||
- Objekte/Tuples – komplexere Typen
|
||||
|
||||
### 4.2 Expressions & Referenzen
|
||||
|
||||
Referenzen auf andere Ressourcen:
|
||||
|
||||
```hcl
|
||||
resource "aws_instance" "web" {
|
||||
ami = data.aws_ami.ubuntu.id
|
||||
instance_type = var.instance_type
|
||||
|
||||
tags = {
|
||||
Name = "web-${var.environment}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Referenz-Regel:
|
||||
|
||||
- `ressourcentyp.name.attribut`
|
||||
- z.B. `aws_instance.web.public_ip`
|
||||
|
||||
---
|
||||
|
||||
## 5. Praktisches Beispiel
|
||||
|
||||
Ein minimaler Stack in AWS:
|
||||
|
||||
### `providers.tf`
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
required_version = ">= 1.6.0"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = var.region
|
||||
}
|
||||
```
|
||||
|
||||
### `variables.tf`
|
||||
|
||||
```hcl
|
||||
variable "region" {
|
||||
type = string
|
||||
default = "eu-central-1"
|
||||
description = "AWS Region"
|
||||
}
|
||||
|
||||
variable "instance_type" {
|
||||
type = string
|
||||
default = "t3.micro"
|
||||
}
|
||||
|
||||
variable "environment" {
|
||||
type = string
|
||||
default = "dev"
|
||||
}
|
||||
```
|
||||
|
||||
### `main.tf`
|
||||
|
||||
```hcl
|
||||
data "aws_ami" "ubuntu" {
|
||||
most_recent = true
|
||||
|
||||
filter {
|
||||
name = "name"
|
||||
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
|
||||
}
|
||||
|
||||
owners = ["099720109477"]
|
||||
}
|
||||
|
||||
resource "aws_instance" "web" {
|
||||
ami = data.aws_ami.ubuntu.id
|
||||
instance_type = var.instance_type
|
||||
|
||||
tags = {
|
||||
Name = "web-${var.environment}"
|
||||
Environment = var.environment
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `outputs.tf`
|
||||
|
||||
```hcl
|
||||
output "web_instance_id" {
|
||||
value = aws_instance.web.id
|
||||
}
|
||||
|
||||
output "web_instance_ami" {
|
||||
value = aws_instance.web.ami
|
||||
}
|
||||
```
|
||||
|
||||
Ablauf:
|
||||
|
||||
```bash
|
||||
terraform init
|
||||
terraform plan
|
||||
terraform apply
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Workspaces, Environments und Modularisierung
|
||||
|
||||
### 6.1 Workspaces
|
||||
|
||||
Terraform Workspaces ermöglichen getrennte States innerhalb desselben Codes (z.B. `default`, `dev`, `prod`).
|
||||
|
||||
```bash
|
||||
terraform workspace list
|
||||
terraform workspace new dev
|
||||
terraform workspace select dev
|
||||
```
|
||||
|
||||
Dann z.B.:
|
||||
|
||||
```hcl
|
||||
variable "environment" {
|
||||
default = terraform.workspace
|
||||
}
|
||||
```
|
||||
|
||||
Viele Teams gehen aber eher über **separate State-Dateien / Ordner / Repos** (z.B. `envs/dev`, `envs/prod`), statt Workspaces intensiv zu nutzen.
|
||||
|
||||
### 6.2 Module für Wiederverwendung
|
||||
|
||||
Struktur-Beispiel:
|
||||
|
||||
```text
|
||||
.
|
||||
├── main.tf
|
||||
├── modules
|
||||
│ ├── network
|
||||
│ │ ├── main.tf
|
||||
│ │ ├── variables.tf
|
||||
│ │ └── outputs.tf
|
||||
│ └── compute
|
||||
│ ├── main.tf
|
||||
│ ├── variables.tf
|
||||
│ └── outputs.tf
|
||||
```
|
||||
|
||||
In `main.tf`:
|
||||
|
||||
```hcl
|
||||
module "network" {
|
||||
source = "./modules/network"
|
||||
vpc_cidr = "10.0.0.0/16"
|
||||
}
|
||||
|
||||
module "compute" {
|
||||
source = "./modules/compute"
|
||||
vpc_id = module.network.vpc_id
|
||||
subnets = module.network.subnet_ids
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Terraform Cloud / Terraform Enterprise
|
||||
|
||||
Neben der CLI gibt es:
|
||||
|
||||
- **Terraform Cloud** (SaaS von HashiCorp)
|
||||
- **Terraform Enterprise** (Self-hosted)
|
||||
|
||||
Features:
|
||||
|
||||
- Remote-State-Storage
|
||||
- Remote-Execution (Plans/Applies)
|
||||
- Policies (Sentinel)
|
||||
- Team & Governance (RBAC)
|
||||
- UI für Runs, Logs, States, Variablen
|
||||
|
||||
Für kleine Teams reicht oft: Git + Remote State (S3/Azure/GCS) + CI/CD Pipeline.
|
||||
|
||||
---
|
||||
|
||||
## 8. Typische Anwendungsfälle
|
||||
|
||||
- **Cloud-Infrastruktur**:
|
||||
- VPCs/Netzwerke, Subnets, Security Groups
|
||||
- Compute (VMs, Managed Kubernetes, Serverless)
|
||||
- Datenbanken, Caches, Messaging
|
||||
- **Kubernetes-Infrastruktur**:
|
||||
- Cluster (EKS/AKS/GKE)
|
||||
- Add-ons via `kubernetes`-Provider, `helm`-Provider
|
||||
- **Multi-Cloud-Szenarien**:
|
||||
- Einheitliches Tool für AWS + Azure + GCP
|
||||
- **On-Prem / Sonstiges**:
|
||||
- VMware, OpenStack, F5, GitHub-Repos, DNS (Cloudflare/Route53), Monitoring (Datadog, New Relic), etc.
|
||||
|
||||
---
|
||||
|
||||
## 9. Vergleich zu anderen Tools
|
||||
|
||||
### Terraform vs. CloudFormation / ARM / Bicep
|
||||
|
||||
- Terraform:
|
||||
- Provider-übergreifend (nicht auf eine Cloud beschränkt)
|
||||
- HCL, verständliche Syntax
|
||||
- CloudFormation (AWS) / ARM/Bicep (Azure) / Deployment Manager (GCP):
|
||||
- Cloud-spezifisch, tief integriert
|
||||
- Gut für reines Single-Cloud-Setup
|
||||
- Multi-Cloud wird komplex
|
||||
|
||||
### Terraform vs. Ansible / Chef / Puppet
|
||||
|
||||
- Terraform:
|
||||
- Fokus: **Provisioning** + Lebenszyklus von Ressourcen
|
||||
- Deklarativ, fokus auf Infrastruktur
|
||||
- Ansible/Chef/Puppet:
|
||||
- Fokus: **Konfiguration** von Servern / Software
|
||||
- IdR. auf bereits existierende Maschinen
|
||||
|
||||
Häufig werden Terraform + Ansible kombiniert:
|
||||
Terraform baut VMs / Netzwerke, Ansible konfiguriert Software im OS.
|
||||
|
||||
### Terraform vs. Pulumi
|
||||
|
||||
- Pulumi: IaC mit **allgemeinen Programmiersprachen** (TypeScript, Python, Go, C#)
|
||||
- Terraform: HCL, deklarativ, stark verbreitete Community
|
||||
- Pulumi bietet mehr „Programmier-Features“ (Loops, Ifs) direkt in Sprache; Terraform hat ähnliche Mechanismen, aber bewusst begrenzt, um die Konfiguration simpel zu halten.
|
||||
|
||||
---
|
||||
|
||||
## 10. Best Practices & Stolperfallen
|
||||
|
||||
### 10.1 Best Practices
|
||||
|
||||
- **State nicht lokal** speichern, sondern Remote (z.B. S3 + DynamoDB Locking, Azure Storage + Locks).
|
||||
- **State schützen**:
|
||||
- Zugriff beschränken (IAM/RBAC)
|
||||
- Backups
|
||||
- **Struktur / Modularisierung**:
|
||||
- Wiederverwendbare Module
|
||||
- Trennung von Environments (dev/stage/prod)
|
||||
- **Git-Workflow**:
|
||||
- Terraform-Code in Repos
|
||||
- PRs/Merge-Requests
|
||||
- `terraform plan` via CI im PR anzeigen
|
||||
- **Versionen pinnen**:
|
||||
- Terraform-Version `required_version`
|
||||
- Provider-Versionen fixieren (z.B. `~> 5.0`)
|
||||
- **Kleine, inkrementelle Änderungen**:
|
||||
- Große Umbauten in mehreren Schritten
|
||||
- Plan gut reviewen
|
||||
|
||||
### 10.2 Typische Probleme
|
||||
|
||||
- **State-Drift**:
|
||||
- Ressourcen werden außerhalb von Terraform geändert (z.B. in der Cloud-Konsole)
|
||||
- Plan zeigt unerwartete Änderungen
|
||||
- Lösung: soweit möglich alle Änderungen via Terraform; bei Drift bewusst entscheiden (import, adopt, ignore)
|
||||
- **Manuelles Löschen von Ressourcen**:
|
||||
- Terraform „denkt“, Ressource existiert noch
|
||||
- Beim nächsten Apply werden sie ggf. neu erstellt
|
||||
- **Zyklen in Abhängigkeiten**:
|
||||
- Falsche Referenzen können zyklische Abhängigkeiten erzeugen
|
||||
- **Große States**:
|
||||
- Sehr viele Ressourcen in einem State → langsamere Plans, unübersichtliche Fehler
|
||||
- Lösung: Aufteilen in mehrere Terraform-Projekte / States (z.B. pro Domäne/Layer)
|
||||
|
||||
---
|
||||
|
||||
## 11. Aktuelle Entwicklungen: Lizenz & OpenTofu
|
||||
|
||||
HashiCorp hat 2023 die Lizenz von Terraform auf die **Business Source License (BSL)** geändert.
|
||||
Daraufhin entstand ein **Community-Fork**:
|
||||
|
||||
- **OpenTofu** (ehemals OpenTF):
|
||||
- Komplett Open Source (MPL 2.0)
|
||||
- CLI & HCL weitgehend kompatibel zu Terraform (Stand heute)
|
||||
- Ziel: drop-in Replacement für viele Terraform-Usecases
|
||||
|
||||
Für einen Einstieg in IaC ist es aber sinnvoll, zuerst die Konzepte anhand von Terraform zu verstehen – die meisten davon sind für OpenTofu nahezu identisch.
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,358 @@
|
||||
Hier ist eine kompakte, praxisorientierte Anleitung zu `kubectl` mit den wichtigsten Funktionen und Use Cases.
|
||||
|
||||
---
|
||||
|
||||
## 1. Was ist `kubectl`?
|
||||
|
||||
`kubectl` ist das Kommandozeilen-Tool, um mit einem Kubernetes-Cluster zu kommunizieren.
|
||||
Damit kannst du:
|
||||
|
||||
- Ressourcen erstellen, ändern und löschen (Deployments, Pods, Services, …)
|
||||
- Logs einsehen und Probleme debuggen
|
||||
- Rollouts steuern (Deployments updaten/rollback)
|
||||
- Konfigurationen verwalten (Kontexte, Namespaces, Kubeconfig)
|
||||
|
||||
---
|
||||
|
||||
## 2. Grundlagen: Aufbau von `kubectl`-Befehlen
|
||||
|
||||
Allgemeines Schema:
|
||||
|
||||
```bash
|
||||
kubectl <verb> <ressource> [name] [flags]
|
||||
```
|
||||
|
||||
Beispiele:
|
||||
|
||||
```bash
|
||||
kubectl get pods
|
||||
kubectl describe pod mein-pod
|
||||
kubectl delete service mein-service
|
||||
```
|
||||
|
||||
Wichtige Verben:
|
||||
|
||||
- `get` – Anzeigen
|
||||
- `describe` – Detailinformationen
|
||||
- `create` / `apply` – Ressourcen anlegen/aktualisieren
|
||||
- `delete` – Löschen
|
||||
- `logs` – Logs anzeigen
|
||||
- `exec` – Befehle innerhalb eines Pods ausführen
|
||||
|
||||
---
|
||||
|
||||
## 3. Konfiguration & Kontexte
|
||||
|
||||
### 3.1 Cluster-Zugriff prüfen
|
||||
|
||||
```bash
|
||||
kubectl version
|
||||
kubectl cluster-info
|
||||
```
|
||||
|
||||
### 3.2 Aktuellen Kontext anzeigen und wechseln
|
||||
|
||||
```bash
|
||||
kubectl config get-contexts
|
||||
kubectl config current-context
|
||||
kubectl config use-context mein-context
|
||||
```
|
||||
|
||||
### 3.3 Namespace festlegen
|
||||
|
||||
Temporär per Flag:
|
||||
|
||||
```bash
|
||||
kubectl get pods -n my-namespace
|
||||
```
|
||||
|
||||
Standard-Namespace setzen:
|
||||
|
||||
```bash
|
||||
kubectl config set-context --current --namespace=my-namespace
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Ressourcen anzeigen und inspizieren
|
||||
|
||||
### 4.1 Ressourcen auflisten
|
||||
|
||||
```bash
|
||||
kubectl get pods
|
||||
kubectl get deployments
|
||||
kubectl get services
|
||||
kubectl get all
|
||||
```
|
||||
|
||||
Mit mehr Details:
|
||||
|
||||
```bash
|
||||
kubectl get pods -o wide
|
||||
kubectl get pods -o yaml
|
||||
```
|
||||
|
||||
### 4.2 Detailinformationen zu einer Ressource
|
||||
|
||||
```bash
|
||||
kubectl describe pod mein-pod
|
||||
kubectl describe deployment mein-deployment
|
||||
```
|
||||
|
||||
Use Case: Debugging (Events, Container-Status, Restart-Gründe).
|
||||
|
||||
---
|
||||
|
||||
## 5. Deployments & Anwendungen verwalten
|
||||
|
||||
### 5.1 Deployment aus YAML erstellen
|
||||
|
||||
`deployment.yaml` Beispiel (stark vereinfacht):
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.25
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
Anwenden:
|
||||
|
||||
```bash
|
||||
kubectl apply -f deployment.yaml
|
||||
```
|
||||
|
||||
### 5.2 Deployment aktualisieren (Rolling Update)
|
||||
|
||||
Image ändern:
|
||||
|
||||
```bash
|
||||
kubectl set image deployment/nginx-deployment nginx=nginx:1.26
|
||||
```
|
||||
|
||||
Rollout-Status beobachten:
|
||||
|
||||
```bash
|
||||
kubectl rollout status deployment/nginx-deployment
|
||||
```
|
||||
|
||||
Rollback:
|
||||
|
||||
```bash
|
||||
kubectl rollout undo deployment/nginx-deployment
|
||||
```
|
||||
|
||||
### 5.3 Replica-Anzahl skalieren
|
||||
|
||||
```bash
|
||||
kubectl scale deployment nginx-deployment --replicas=5
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Services & Zugriff auf Anwendungen
|
||||
|
||||
### 6.1 Services anzeigen
|
||||
|
||||
```bash
|
||||
kubectl get svc
|
||||
```
|
||||
|
||||
Beispiel-Service:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx-service
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: nginx
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
```
|
||||
|
||||
Anwenden:
|
||||
|
||||
```bash
|
||||
kubectl apply -f service.yaml
|
||||
```
|
||||
|
||||
### 6.2 Port-Forwarding (lokaler Zugriff)
|
||||
|
||||
```bash
|
||||
kubectl port-forward svc/nginx-service 8080:80
|
||||
# Aufruf im Browser: http://localhost:8080
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Logs & Debugging
|
||||
|
||||
### 7.1 Logs eines Pods
|
||||
|
||||
```bash
|
||||
kubectl logs mein-pod
|
||||
kubectl logs mein-pod -c container-name
|
||||
kubectl logs -f mein-pod # -f = "follow"
|
||||
```
|
||||
|
||||
### 7.2 Befehle im Container ausführen
|
||||
|
||||
```bash
|
||||
kubectl exec -it mein-pod -- /bin/sh
|
||||
# oder
|
||||
kubectl exec -it mein-pod -- bash
|
||||
```
|
||||
|
||||
Typischer Use Case: Debugging von laufenden Containern, z.B. Netzwerkprobleme, Dateisystem prüfen.
|
||||
|
||||
### 7.3 Problem-Analyse mit `describe` & Events
|
||||
|
||||
```bash
|
||||
kubectl describe pod mein-pod
|
||||
kubectl get events --sort-by=.metadata.creationTimestamp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Ressourcen ändern & löschen
|
||||
|
||||
### 8.1 Änderungen anwenden
|
||||
|
||||
Konfiguration in einer Datei ändern und dann:
|
||||
|
||||
```bash
|
||||
kubectl apply -f deployment.yaml
|
||||
```
|
||||
|
||||
Um tatsächliche Unterschiede zu sehen:
|
||||
|
||||
```bash
|
||||
kubectl diff -f deployment.yaml
|
||||
```
|
||||
|
||||
### 8.2 Ressourcen löschen
|
||||
|
||||
```bash
|
||||
kubectl delete pod mein-pod
|
||||
kubectl delete -f deployment.yaml
|
||||
kubectl delete deployment nginx-deployment
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Konfigurationen & Secrets
|
||||
|
||||
### 9.1 ConfigMaps
|
||||
|
||||
Erstellen aus einer Datei:
|
||||
|
||||
```bash
|
||||
kubectl create configmap app-config --from-file=config.properties
|
||||
```
|
||||
|
||||
Oder aus Literalwert:
|
||||
|
||||
```bash
|
||||
kubectl create configmap app-config --from-literal=KEY=VALUE
|
||||
```
|
||||
|
||||
ConfigMaps anzeigen:
|
||||
|
||||
```bash
|
||||
kubectl get configmaps
|
||||
kubectl describe configmap app-config
|
||||
```
|
||||
|
||||
### 9.2 Secrets
|
||||
|
||||
```bash
|
||||
kubectl create secret generic db-secret \
|
||||
--from-literal=username=user \
|
||||
--from-literal=password=geheim
|
||||
```
|
||||
|
||||
Achtung: Standard-`kubectl get secret -o yaml` zeigt Base64-codierte, aber nicht verschlüsselte Daten.
|
||||
|
||||
---
|
||||
|
||||
## 10. Weitere nützliche Features
|
||||
|
||||
### 10.1 Autocomplete
|
||||
|
||||
Bash-Beispiel:
|
||||
|
||||
```bash
|
||||
source <(kubectl completion bash)
|
||||
echo 'source <(kubectl completion bash)' >> ~/.bashrc
|
||||
```
|
||||
|
||||
### 10.2 Kustomize (ohne extra Tool, ab neueren kubectl-Versionen)
|
||||
|
||||
```bash
|
||||
kubectl apply -k ./overlays/production
|
||||
```
|
||||
|
||||
Struktur z.B.:
|
||||
|
||||
```text
|
||||
base/
|
||||
deployment.yaml
|
||||
kustomization.yaml
|
||||
overlays/production/
|
||||
kustomization.yaml
|
||||
patches.yaml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Typische Praxis-Workflows
|
||||
|
||||
### 11.1 Neue Version deployen
|
||||
|
||||
```bash
|
||||
git pull
|
||||
kubectl apply -f k8s/
|
||||
kubectl rollout status deployment mein-service
|
||||
kubectl get pods -o wide
|
||||
```
|
||||
|
||||
### 11.2 Fehlerhafte Anwendung debuggen
|
||||
|
||||
```bash
|
||||
kubectl get pods
|
||||
kubectl describe pod fehler-pod
|
||||
kubectl logs fehler-pod
|
||||
kubectl exec -it fehler-pod -- sh
|
||||
kubectl get events --sort-by=.metadata.creationTimestamp
|
||||
```
|
||||
|
||||
### 11.3 Schnell in einen anderen Namespace/Cluster wechseln
|
||||
|
||||
```bash
|
||||
kubectl config use-context staging-cluster
|
||||
kubectl config set-context --current --namespace=team-a
|
||||
kubectl get pods
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Wenn du möchtest, kann ich dir für deinen konkreten Use Case (z.B. “Web-App deployen”, “CI/CD-Pipeline”, “lokales Minikube-Cluster”) eine konkrete Schritt-für-Schritt-Anleitung mit fertigen `kubectl`-Befehlen erstellen.
|
||||
Reference in New Issue
Block a user