Aus dem Leben mit Kubernetes: Wie der HTTP-Server den Spaniern nicht gefiel

Aus dem Leben mit Kubernetes: Wie der HTTP-Server den Spaniern nicht gefiel

Ein Vertreter unseres Kunden, dessen Anwendungsstapel sich in der Microsoft-Cloud (Azure) befindet, ging auf ein Problem ein: Vor kurzem endeten einige Anfragen einiger Kunden aus Europa mit Fehler 400 (Bad Request). Alle Anwendungen sind in .NET geschrieben und in Kubernetes bereitgestellt ...

Eine der Anwendungen ist die API, über die letztlich der gesamte Datenverkehr läuft. Dieser Datenverkehr wird vom HTTP-Server abgehört Turmfalke, vom .NET-Client konfiguriert und in einem Pod gehostet. Beim Debuggen hatten wir insofern Glück, als es einen bestimmten Benutzer gab, der das Problem konsequent reproduzierte. Allerdings wurde alles durch die Verkehrskette kompliziert:

Aus dem Leben mit Kubernetes: Wie der HTTP-Server den Spaniern nicht gefiel

Der Fehler in Ingress sah so 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":{}
}

Gleichzeitig gab Kestrel:

HTTP/1.1 400 Bad Request
Connection: close
Date: Wed, 06 Mar 2019 12:34:20 GMT
Server: Kestrel
Content-Length: 0

Selbst bei maximaler Ausführlichkeit enthielt der Kestrel-Fehler extrem viel 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":"Connection id "{ConnectionId}" bad request data: "{message}"",
      "@t":"2019-03-07T13:06:48.1449083Z",
      "@x":"Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Malformed request: invalid headers.n   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection.TryParseRequest(ReadResult result, Boolean& endConnection)n   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<ProcessRequestsAsync>d__185`1.MoveNext()",
      "message":"Malformed request: invalid headers."
   },
   "timestamp":"2019-03-07 13:06:48",
   "labels":{
      "pod-template-hash":"2368795483",
      "service":"app"
   },
   "namespace":"production",
   "nsec":145341848,
   "source":"kubernetes",
   "host":"k8s-node-55555-1",
   "pod_name":"app-67bdcf98d7-mhktx",
   "container_name":"app",
   "boolean_fields":{}
}

Es scheint, dass nur tcpdump dieses Problem lösen kann ... aber ich wiederhole es zur Verkehrskette:

Aus dem Leben mit Kubernetes: Wie der HTTP-Server den Spaniern nicht gefiel

Untersuchung

Natürlich ist es besser, auf den Verkehr zu hören auf diesem bestimmten Knoten, wo Kubernetes einen Pod bereitgestellt hat: Das Volumen des Dumps wird so groß sein, dass man zumindest ziemlich schnell etwas finden kann. Und tatsächlich ist bei der Untersuchung folgender Rahmen aufgefallen:

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: Spain
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, like 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: many_encrypted_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 näherer Betrachtung der Mülldeponie fiel das Wort auf M.laga. Es ist leicht zu erraten, dass es in Spanien keine M.laga-Stadt gibt (aber es gibt eine). Malaga). Wir griffen diese Idee auf und schauten uns die Ingress-Konfigurationen an. Dort sahen wir die vor einem Monat eingefügte Konfiguration (auf Wunsch des Kunden). „harmloser“ Ausschnitt:

    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 ich die Weiterleitung dieser Header deaktiviert hatte, war alles wieder gut! (Es wurde schnell klar, dass die Anwendung selbst diese Header nicht mehr benötigte.)

Schauen wir uns nun das Problem an allgemeiner. Es kann leicht innerhalb der Anwendung reproduziert werden, indem eine Telnet-Anfrage gestellt wird 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

... kehrt zurück 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ückkehren 400 Bad request — Im Anwendungsprotokoll erhalten wir einen uns bereits bekannten Fehler:

{
   "@t":"2019-03-31T12:59:54.3746446Z",
   "@mt":"Connection id "{ConnectionId}" bad request data: "{message}"",
   "@x":"Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Malformed request: invalid headers.n   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection.TryParseRequest(ReadResult result, Boolean& endConnection)n   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<ProcessRequestsAsync>d__185`1.MoveNext()",
   "ConnectionId":"0HLLLR1J974L9",
   "message":"Malformed request: invalid headers.",
   "EventId":{
      "Id":17,
      "Name":"ConnectionBadRequest"
   },
   "SourceContext":"Microsoft.AspNetCore.Server.Kestrel",
   "ThreadId":71
}

Ergebnisse

Speziell Turmfalke kann nicht HTTP-Header mit den richtigen Zeichen in UTF-8, die in den Namen einer größeren Anzahl von Städten enthalten sind, korrekt verarbeiten.

Ein weiterer Faktor in unserem Fall ist, dass der Kunde derzeit nicht plant, die Implementierung von Kestrel in der Anwendung zu ändern. Allerdings gibt es Probleme in AspNetCore selbst (№ 4318, № 7707) Sie sagen, dass das nicht helfen wird...

Zusammenfassend: In dem Hinweis geht es nicht mehr um die spezifischen Probleme von Kestrel oder UTF-8 (im Jahr 2019?!), sondern um die Tatsache, dass Achtsamkeit und konsequentes Lernen Jeder Schritt, den Sie auf der Suche nach Problemen unternehmen, wird früher oder später Früchte tragen. Viel Glück!

PS

Lesen Sie auch auf unserem Blog:

Source: habr.com

Kommentar hinzufügen