
Der Vertreter unseres Kunden, dessen Anwendungsarchitektur in der Microsoft-Cloud (Azure) gehostet wird, hat uns ein Problem mitgeteilt: Seit kurzem enden einige Anfragen von europĂ€ischen Kunden mit dem Fehler 400 (). Alle Anwendungen sind in .NET geschrieben und in Kubernetes bereitgestelltâŠ
Eine der Anwendungen ist ein API, ĂŒber das der gesamte Datenverkehr letztendlich lĂ€uft. Dieser Datenverkehr wird von dem HTTP-Server , der vom Kunden konfiguriert wurde und sich in einem Pod befindet, empfangen. Bei der Fehlersuche hatten wir das GlĂŒck, dass es einen spezifischen Benutzer gab, bei dem das Problem konstant reproduzierbar war. Allerdings wurde alles durch die Kette des Datenverkehrs kompliziert:

Der Fehler im Ingress sah wie folgt aus:
{
"number_fields":{
"status":400,
"request_time":0.001,
"bytes_sent":465,
"upstream_response_time":0,
"upstream_retries":0,
"bytes_received":2328
},
"stream":"stdout",
"string_fields":{
"ingress":"app",
"protocol":"HTTP/1.1",
"request_id":"f9ab8540407208a119463975afda90bc",
"path":"/api/sign-in",
"nginx_upstream_status":"400",
"service":"app",
"namespace":"production",
"location":"/front",
"scheme":"https",
"method":"POST",
"nginx_upstream_response_time":"0.000",
"nginx_upstream_bytes_received":"120",
"vhost":"api.app.example.com",
"host":"api.app.example.com",
"user":"",
"address":"83.41.81.250",
"nginx_upstream_addr":"10.240.0.110:80",
"referrer":"https://api.app.example.com/auth/login?long_encrypted_header",
"service_port":"http",
"user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
"time":"2019-03-06T18:29:16+00:00",
"content_kind":"cache-headers-not-present",
"request_query":""
},
"timestamp":"2019-03-06 18:29:16",
"labels":{
"app":"nginx",
"pod-template-generation":"6",
"controller-revision-hash":"1682636041"
},
"namespace":"kube-nginx-ingress",
"nsec":6726612,
"source":"kubernetes",
"host":"k8s-node-55555-0",
"pod_name":"nginx-v2hcb",
"container_name":"nginx",
"boolean_fields":{}
}In der Zwischenzeit gab Kestrel aus:
HTTP/1.1 400 Bad Request
Connection: close
Date: Wed, 06 Mar 2019 12:34:20 GMT
Server: Kestrel
Content-Length: 0Selbst bei maximaler Detailgenauigkeit enthielt der Kestrel-Fehler extrem wenig nĂŒtzliche Informationen:
{
"number_fields":{"ThreadId":76},
"stream":"stdout",
"string_fields":{
"EventId":"{"Id"=>17, "Name"=>"ConnectionBadRequest"}",
"SourceContext":"Microsoft.AspNetCore.Server.Kestrel",
"ConnectionId":"0HLL2VJSST5KV",
"@mt":"Verbindungs-ID "{ConnectionId}" ungĂŒltige Anforderungsdaten: "{message}"",
"@t":"2019-03-07T13:06:48.1449083Z",
"@x":"Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: UngĂŒltige Anforderung: fehlerhafte Header.n bei Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection.TryParseRequest(ReadResult result, Boolean& endConnection)n bei Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<ProcessRequestsAsync>d__185`1.MoveNext()",
"message":"UngĂŒltige Anforderung: fehlerhafte Header."
},
"timestamp":"2019-03-07 13:06:48",
"labels":{
"pod-template-hash":"2368795483",
"service":"app"
},
"namespace":"produktion",
"nsec":145341848,
"source":"kubernetes",
"host":"k8s-node-55555-1",
"pod_name":"app-67bdcf98d7-mhktx",
"container_name":"app",
"boolean_fields":{}
}Es scheint, dass nur tcpdump bei der Lösung dieses Problems helfen kann⊠aber ich wiederhole die Verkehrskette:

Untersuchung
Offensichtlich ist es besser, den Verkehr zu belauschen auf dem spezifischen Knoten, wo Kubernetes das Pod bereitgestellt hat: Das Volumen des Dumps wird so groà sein, dass man schnell etwas finden kann. Und tatsÀchlich wurde bei seiner Betrachtung ein solches Frame bemerkt:
GET /back/user HTTP/1.1
Host: api.app.example.com
X-Request-ID: 27ceb14972da8c21a8f92904b3eff1e5
X-Real-IP: 83.41.81.250
X-Forwarded-For: 83.41.81.250
X-Forwarded-Host: api.app.example.com
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Original-URI: /front/back/user
X-Scheme: https
X-Original-Forwarded-For: 83.41.81.250
X-Nginx-Geo-Client-Country: Spanien
X-Nginx-Geo-Client-City: M.laga
Accept-Encoding: gzip
CF-IPCountry: ES
CF-RAY: 4b345cfd1c4ac691-MAD
CF-Visitor: {"scheme":"https"}
pragma: no-cache
cache-control: no-cache
accept: application/json, text/plain, *
origin: https://app.example.com
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, wie Gecko) Chrome/72.0.3626.119 Safari/537.36
referer: https://app.example.com/auth/login
accept-language: en-US,en;q=0.9,en-GB;q=0.8,pl;q=0.7
cookie: viele_verschlĂŒsselte_cookies; .AspNetCore.Identity.Application=something_encrypted;
CF-Connecting-IP: 83.41.81.250
True-Client-IP: 83.41.81.250
CDN-Loop: cloudflare
HTTP/1.1 400 Bad Request
Connection: close
Date: Wed, 06 Mar 2019 12:34:20 GMT
Server: Kestrel
Content-Length: 0 Bei genauerer Betrachtung des Dumps wurde das Wort bemerkt M.laga. Es ist leicht zu erraten, dass es in Spanien keine Stadt namens M.laga gibt (aber es gibt ). Angetrieben von dieser Idee sahen wir uns die Ingress-Konfigurationen an, wo wir vor einem Monat auf Kundenanfrage hinein eingefĂŒgte âharmlosenâ Snippet:
ingress.kubernetes.io/configuration-snippet: |
proxy_set_header X-Nginx-Geo-Client-Country $geoip_country_name;
proxy_set_header X-Nginx-Geo-Client-City $geoip_city;Nachdem wir das Durchleiten dieser Header deaktiviert hatten, war alles gut! (Bald stellte sich heraus, dass diese Header fĂŒr die Anwendung selbst nicht mehr benötigt wurden.)
Nun schauen wir uns das Problem in allgemeinerer Form. Es ist leicht, es innerhalb der Anwendung nachzustellen, wenn man eine telnet-Anfrage an localhost:80:
GET /back/user HTTP/1.1
Host: api.app.example.com
cache-control: no-cache
accept: application/json, text/plain, */*
origin: https://app.example.com
Cookie: test=Desiree ⊠wird zurĂŒckgegeben 401 Unauthorized, wie erwartet. Was passiert, wenn wir Folgendes tun:
GET /back/user HTTP/1.1
Host: api.app.example.com
cache-control: no-cache
accept: application/json, text/plain, */*
origin: https://app.example.com
Cookie: test=Désirée?
Wird zurĂŒckgegeben 400 Bad request â im Anwendungsprotokoll erhalten wir bereits den bekannten Fehler:
{
"@t":"2019-03-31T12:59:54.3746446Z",
"@mt":"Verbindungs-ID "{ConnectionId}" ungĂŒltige Anfragedaten: "{message}"",
"@x":"Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Fehlgeschlagene Anfrage: ungĂŒltige Header.n bei Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection.TryParseRequest(ReadResult result, Boolean& endConnection)n bei Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<ProcessRequestsAsync>d__185`1.MoveNext()",
"ConnectionId":"0HLLLR1J974L9",
"message":"Fehlgeschlagene Anfrage: ungĂŒltige Header.",
"EventId":{
"Id":17,
"Name":"ConnectionBadRequest"
},
"SourceContext":"Microsoft.AspNetCore.Server.Kestrel",
"ThreadId":71
}Ergebnisse
Konkret Kestrel HTTP-Header mit korrekten Zeichen in UTF-8, die in den Namen einer ziemlich groĂen Anzahl von StĂ€dten enthalten sind, nicht korrekt verarbeiten.
Ein zusĂ€tzlicher Faktor in unserem Fall â die Implementierung von Kestrel in der Clientanwendung wird derzeit nicht geĂ€ndert. Allerdings zeigen die Issues in AspNetCore (, ) dass dies auch nicht helfen wirdâŠ
Zusammenfassend: Diese Notiz handelt nicht mehr von spezifischen Problemen mit Kestrel oder UTF-8 (im Jahr 2019?!), sondern davon, dass Aufmerksamkeit und systematisches Lernen jeden Schritt beim Auffinden des Problems frĂŒher oder spĂ€ter FrĂŒchte tragen. Viel Erfolg!
P.S.
Lesen Sie auch in unserem Blog:
- «»;
- «»;
- «»;
- «»;
- «».
Quelle: habr.com
