Skip to content

Commit a7877b7

Browse files
author
wlanboy
committed
added dokumentation
1 parent 9e492fe commit a7877b7

File tree

1 file changed

+247
-0
lines changed

1 file changed

+247
-0
lines changed

dokumentation.md

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
# JavaHttpClient – Projektdokumentation
2+
3+
## Zweck
4+
5+
Diagnose-Tool für HTTP-Konnektivitätsprobleme in Kubernetes-Clustern mit Istio Service Mesh.
6+
Läuft als Pod im Cluster und ermöglicht:
7+
- HTTP-Requests über einen Java-HTTP-Client an beliebige Ziel-URLs zu senden
8+
- Istio-Sidecar (Envoy) Konfiguration und Fehler-Metriken auszuwerten
9+
- VirtualService/DestinationRule/ServiceEntry-Konfiguration mit einer Ziel-URL zu korrelieren
10+
- TLS-Zertifikatsketten und mTLS/SPIFFE-Identitäten zu inspizieren
11+
- Redirect-Chains, Protokollversionen und DNS-Auflösungen sichtbar zu machen
12+
13+
---
14+
15+
## Tech Stack
16+
17+
| Schicht | Technologie |
18+
|---------|-------------|
19+
| Backend | Spring Boot 4.0.3, Java 25, Jetty |
20+
| HTTP-Client | `java.net.http.HttpClient` (JDK built-in) |
21+
| K8s-Integration | Official Kubernetes Java Client v25.0.0 |
22+
| Frontend | Vanilla JS, Bootstrap 5.3, Bootstrap Icons |
23+
| API-Doku | SpringDoc OpenAPI 3.0.1 (`/swagger-ui.html`, `/api-docs`) |
24+
| Deployment | Docker (AOT-Build), Helm, Istio Gateway |
25+
26+
---
27+
28+
## Architektur
29+
30+
```
31+
Browser
32+
33+
├─ POST /client → HttpClientController → ClientService
34+
│ ├─ HTTP/2-Client (NEVER redirect)
35+
│ ├─ Manuelle Redirect-Chain
36+
│ ├─ DNS-Auflösung (InetAddress)
37+
│ └─ Response-Header:
38+
│ X-Protocol-Version
39+
│ X-Redirect-Chain
40+
│ X-Resolved-IP
41+
42+
├─ GET /api/k8s/context → DiagnosticController → K8sDiagnosticService
43+
├─ GET /api/k8s/status → ↑
44+
├─ GET /api/k8s/istio/{type} → ↑
45+
├─ GET /api/k8s/istio/full-report → ↑ (Envoy Admin API: /stats, /clusters, /config_dump)
46+
├─ GET /api/k8s/correlate → ↑ (VS/DR/SE-Matching gegen URL)
47+
└─ GET /api/k8s/tls → DiagnosticController → TlsInspectorService (SSLSocket-Probe)
48+
```
49+
50+
---
51+
52+
## Backend – Klassen
53+
54+
### `ClientService`
55+
Sendet HTTP-Requests über `java.net.http.HttpClient`.
56+
57+
- **HTTP/2** aktiv (`Version.HTTP_2`), fällt automatisch auf HTTP/1.1 zurück (ALPN)
58+
- **`Redirect.NEVER`** – Redirects werden manuell verfolgt (bis zu 10 Hops)
59+
- 307/308: Methode + Body beibehalten
60+
- 301/302/303: → GET, kein Body
61+
- Folge-Requests erhalten **keine** originalen Browser-Header (verhindert Auth-Token-Leak)
62+
- **DNS-Auflösung** vor dem Request: `InetAddress.getAllByName()` → alle A/AAAA-Records
63+
- **Response-Header** die zurückgegeben werden:
64+
- `X-Protocol-Version`: `HTTP/2` oder `HTTP/1.1`
65+
- `X-Redirect-Chain`: JSON-Array der Zwischenschritte `[{from, status, to, proto}]`
66+
- `X-Resolved-IP`: kommagetrennte IPs
67+
68+
Gefilterte Request-Header (werden nie weitergeleitet):
69+
`host`, `content-length`, `connection`, `accept-encoding`, `upgrade`
70+
71+
Fehlermeldungen (502):
72+
| Exception | Meldung |
73+
|-----------|---------|
74+
| `UnknownHostException` | DNS Fehler: Host nicht gefunden |
75+
| `ConnectException` | Verbindung abgelehnt: Port zu / Pod läuft nicht |
76+
| `HttpConnectTimeoutException` | Timeout: NetworkPolicy Blockade? |
77+
| `IllegalArgumentException` (URI) | Ungültige URL |
78+
79+
---
80+
81+
### `K8sDiagnosticService`
82+
83+
**Envoy Admin API** (Standard: `http://127.0.0.1:15000`, konfigurierbar via `ENVOY_ADMIN_URL`):
84+
- `/config_dump` → vollständige Envoy-Konfiguration
85+
- `/clusters` → aktive Upstream-Cluster
86+
- `/stats`**alle** Metriken (kein serverseitiger Filter), nur Werte ≥ 0 (non-zero)
87+
88+
**Istio-Sidecar-Erkennung**: Socket-Test auf `127.0.0.1:15021`
89+
90+
**Unterstützte Istio-Ressourcentypen** (API-Versionen v1 → v1beta1 → v1alpha3 Fallback):
91+
`virtualservices`, `destinationrules`, `gateways`, `serviceentries`, `sidecars`,
92+
`envoyfilters`, `peerauthentications`, `requestauthentications`, `authorizationpolicies`
93+
94+
**Gefilterte Metriken**: `cluster.xds-grpc.*` wird aus `activeErrorMetrics` entfernt
95+
(interner Istio Control-Plane-Kanal, kein App-Traffic)
96+
97+
**`diagnoseMetrics()`** – automatische Problemerkennung aus Envoy-Stats:
98+
99+
| Pattern | Severity | Diagnose |
100+
|---------|----------|----------|
101+
| `upstream_cx_connect_fail` | KRITISCH | Verbindung abgelehnt (Connection refused) |
102+
| `upstream_rq_pending_overflow` | KRITISCH | Circuit Breaker / Pool-Overflow |
103+
| `upstream_cx_none_healthy` | KRITISCH | Keine gesunden Endpoints |
104+
| `upstream_rq_timeout` | WARNUNG | Request Timeouts (NetworkPolicy?) |
105+
| `upstream_cx_connect_timeout` | WARNUNG | Connection Timeout |
106+
| `upstream_rq_5xx` | WARNUNG | 5xx Fehler vom Upstream |
107+
| `upstream_rq_retry_limit_exceeded` | INFO | Retry-Limit überschritten |
108+
| `upstream_cx_destroy_remote_with_active_rq` | INFO | Verbindung mit aktiven Requests abgebrochen |
109+
110+
**`correlateUrl(url, namespace)`** – URL-Korrelation gegen Istio-Ressourcen:
111+
112+
*Host-Matching-Logik* (VS-Host vs. URL-Hostname):
113+
- Exakter Match
114+
- Wildcard: `*.namespace` matcht `foo.namespace`
115+
- Short-Name: `my-svc` matcht `my-svc.ns.svc.cluster.local`
116+
- Prefix: `my-svc.ns` matcht `my-svc.ns.svc.cluster.local`
117+
118+
*VirtualService*: prüft HTTP-Routen auf Pfad-Match (`exact` / `prefix` / `regex`)
119+
→ gibt matched Routes inkl. Destinations, Timeout, Retries, Fault-Injection zurück
120+
121+
*DestinationRule*: prüft Host-Match
122+
→ gibt TrafficPolicy (connectionPool, outlierDetection, loadBalancer) und Subsets zurück
123+
124+
*ServiceEntry*: prüft Host-Match + Port-Match gegen `spec.ports`
125+
→ gibt location, resolution, endpoints, subjectAltNames zurück
126+
→ Warnung wenn angeforderter Port nicht in `spec.ports` definiert
127+
128+
---
129+
130+
### `TlsInspectorService`
131+
132+
Separater `SSLSocket`-basierter TLS-Probe (unabhängig vom Haupt-Request):
133+
- Eigener `SSLContext` mit `X509ExtendedTrustManager` der **alles akzeptiert** (auch self-signed, expired) → Chain immer sichtbar
134+
- SNI korrekt gesetzt via `SSLParameters`
135+
- Gibt zurück:
136+
- `tlsVersion`: `TLSv1.3` / `TLSv1.2`
137+
- `cipherSuite`
138+
- `isMtls`: `true` wenn Leaf-Cert eine `URI:spiffe://`-SAN hat
139+
- `spiffeId`: extrahierte SPIFFE-URI (Istio-Workload-Identität)
140+
- `chain`: Array pro Zertifikat mit subject, issuer, serial, validFrom, validTo, daysUntilExpiry, expired, subjectAltNames
141+
- Wird nur für `https://`-URLs aufgerufen
142+
143+
**Wichtig**: Separate Verbindung – mögliche marginale Abweichung zu vom HttpClient genutzter Verbindung bei sehr kurzlebigen DNS-Einträgen.
144+
145+
---
146+
147+
## API-Endpoints
148+
149+
| Method | Path | Beschreibung |
150+
|--------|------|-------------|
151+
| `POST` | `/client` | HTTP-Request weiterleiten |
152+
| `GET` | `/api/k8s/context` | Pod-Name, Namespace, Istio-Status |
153+
| `GET` | `/api/k8s/status` | K8s-Client-Initialisierungsstatus |
154+
| `GET` | `/api/k8s/istio/full-report` | Envoy Config + Fehler-Metriken + Diagnosen |
155+
| `GET` | `/api/k8s/istio/{type}?namespace=` | Istio-Ressourcen eines Typs |
156+
| `GET` | `/api/k8s/correlate?url=&namespace=` | URL gegen VS/DR/SE korrelieren |
157+
| `GET` | `/api/k8s/tls?url=` | TLS-Zertifikatskette inspizieren |
158+
159+
---
160+
161+
## Frontend – Tabs & Features
162+
163+
### Hauptbereich (linke Spalte)
164+
- HTTP-Method-Dropdown + URL-Feld
165+
- Dynamische Custom-Header (Key/Value, add/remove)
166+
- Body-Textarea (JSON)
167+
- Option: Browser-Header kopieren
168+
- Buttons: **K8s/Istio Diagnose** | **Send Request**
169+
170+
**Response-Bereich** nach jedem Request:
171+
- `HTTP {status}`-Badge (grün/rot)
172+
- `HTTP/2` / `HTTP/1.1`-Badge (blau/grau) – tatsächlich verwendetes Protokoll
173+
- Resolved-IP-Badge (alle aufgelösten IPs)
174+
- Dauer in ms
175+
- **Redirect-Chain**: aufklappbare Schritte `URL → 301 HTTP/1.1 → URL → 302 HTTP/2 → ...`
176+
- **TLS-Panel** (nur HTTPS): TLS-Version, Cipher Suite, mTLS/SPIFFE-Badge, aufklappbare Cert-Cards pro Zertifikat (leaf/intermediate/root) mit Ablauf-Countdown
177+
178+
### Historie (rechte Spalte)
179+
- Bis zu 50 Einträge in `localStorage`
180+
- Grüner/roter Rand je nach Status
181+
- Klick stellt Formular wieder her
182+
- Export als JSON
183+
184+
### Istio-Panel (nach Diagnose-Klick)
185+
186+
**Tab A – Config & Erreichbarkeit**
187+
- Envoy Config JSON (aufklappbar)
188+
- Cluster-Suche mit Zähler
189+
- Aktive Endpoints als scrollbares Konsolen-Output
190+
191+
**Tab B – Aktive Fehler-Metriken**
192+
- Ziel-URL-Korrelation: hebt Metriken hervor die den Hostnamen der URL enthalten
193+
- Diagnose-Karten (KRITISCH/WARNUNG/INFO) mit Beschreibung + Empfehlung + betroffene Metriken
194+
- Vollständige Metriken-Tabelle (alle Werte inkl. 0)
195+
196+
**Tab C – Pod Kontext & Istio**
197+
- Navbar-Badges: Pod-Name, Namespace, Istio ON/OFF
198+
- Kontext-Tabelle: podName, namespace, istioSidecar
199+
- Istio Sidecar Details (clusterSummary, networkStats)
200+
- **URL-Korrelations-Report** (wenn URL eingegeben):
201+
- `Match gefunden` (grün) oder `Kein Match` (gelb)
202+
- VirtualServices: pro Route ob Pfad-Match + Destinations + Timeout/Retries/FaultInjection
203+
- DestinationRules: TrafficPolicy-Badges + Subsets mit Labels
204+
- ServiceEntries: location, resolution, Ports, Port-Match-Warnung
205+
- Istio-Ressourcen-Liste (alle 9 Typen):
206+
- Gematchte Ressourcen: grüner Rand + `URL-Match`-Badge + automatisch aufgeklappt
207+
- Nicht gematchte: zugeklappt
208+
- K8s-Client-Status
209+
210+
---
211+
212+
## Konfiguration
213+
214+
| Variable | Default | Beschreibung |
215+
|----------|---------|-------------|
216+
| `ENVOY_ADMIN_URL` | `http://127.0.0.1:15000` | Envoy Admin API Adresse |
217+
| `KUBERNETES_NAMESPACE` | `default` | Fallback wenn Namespace-Datei nicht lesbar |
218+
219+
Namespace wird primär aus `/var/run/secrets/kubernetes.io/serviceaccount/namespace` gelesen.
220+
221+
---
222+
223+
## Deployment
224+
225+
```
226+
Namespace: clients
227+
Service: ClusterIP :8080
228+
Istio: Gateway in istio-ingress
229+
TLS: cert-manager ClusterIssuer
230+
Hosts: javahttpclient.tp.lan / javahttpclient.gmk.lan
231+
```
232+
233+
**Docker-Builds:**
234+
- `Dockerfile25` – Java 25 mit JRE
235+
- `Dockerfile25Jlink` – Java 25 mit JLink Custom Image (~295MB vs ~510MB)
236+
- AOT aktiv: `spring-boot:process-aot` im Build, `-Dspring.aot.enabled=true` zur Laufzeit
237+
238+
---
239+
240+
## Bekannte Einschränkungen
241+
242+
- **TLS-Inspektion**: Separate Verbindung – bei extrem kurzlebigen DNS-Einträgen kann die angezeigte IP marginal abweichen
243+
- **mTLS via Istio**: Wenn Traffic durch Envoy-Sidecar (iptables intercept) geht, handelt Envoy das TLS – Java sieht dann ggf. plain HTTP intern. TLS-Panel zeigt in dem Fall das Cert des Envoy-Proxys (SPIFFE-Cert), nicht des Zielservices direkt.
244+
- **HTTP/2 h2c**: Cleartext HTTP/2 funktioniert nur wenn der Zielserver h2c-Upgrade unterstützt; sonst automatischer Fallback auf HTTP/1.1
245+
- **Redirect Auth-Header**: Browser-Header werden nur beim ersten Hop mitgeschickt (Schutz vor Token-Leak bei Cross-Domain-Redirects)
246+
- **Envoy-Stats**: `upstream_cx_connect_fail` in den Diagnosen greift nur wenn der Traffic durch den Envoy-Sidecar proxied wird
247+
- **K8s-API**: ServiceAccount muss RBAC-Rechte auf Istio Custom Resources haben (get/list)

0 commit comments

Comments
 (0)