Fra livet med Kubernetes: Hvordan HTTP-serveren ikke favoriserede spanierne

Fra livet med Kubernetes: Hvordan HTTP-serveren ikke favoriserede spanierne

En repræsentant for vores klient, hvis applikationsstack ligger i Microsoft-skyen (Azure), adresserede et problem: for nylig begyndte nogle anmodninger fra nogle klienter fra Europa at ende med fejl 400 (Dårlig anmodning). Alle applikationer er skrevet i .NET, implementeret i Kubernetes...

En af applikationerne er API'et, hvorigennem al trafik i sidste ende kommer. Denne trafik lyttes til af HTTP-serveren Kestrel, konfigureret af .NET-klienten og hostet i en pod. Med debugging var vi heldige i den forstand, at der var en specifik bruger, der konsekvent gengav problemet. Alt blev dog kompliceret af trafikkæden:

Fra livet med Kubernetes: Hvordan HTTP-serveren ikke favoriserede spanierne

Fejlen i Ingress så således ud:

{
   "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":{}
}

Samtidig gav Kestrel:

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

Selv med maksimal ordlyd indeholdt Kestrel-fejlen ekstremt lidt brugbar information:

{
   "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":{}
}

Det ser ud til, at kun tcpdump vil hjælpe med at løse dette problem ... men jeg vil gentage om trafikkæden:

Fra livet med Kubernetes: Hvordan HTTP-serveren ikke favoriserede spanierne

undersøgelse

Det er klart, at det er bedre at lytte til trafikken på den specifikke node, hvor Kubernetes har installeret en pod: volumen af ​​dumpen vil være sådan, at det vil være muligt at finde i det mindste noget ret hurtigt. Og faktisk, da man undersøgte det, blev følgende ramme bemærket:

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

Ved nærmere inspektion af lossepladsen blev ordet bemærket M.laga. Det er let at gætte, at der ikke er nogen M.laga-by i Spanien (men det er der Málaga). Med denne idé kiggede vi på Ingress-konfigurationerne, hvor vi så den, der blev indsat for en måned siden (på kundens anmodning) "harmløs" uddrag:

    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;

Efter at have deaktiveret videresendelsen af ​​disse overskrifter, blev alt fint! (Det blev hurtigt klart, at selve applikationen ikke længere havde brug for disse overskrifter.)

Lad os nu se på problemet mere generelt. Det kan nemt gengives inde i applikationen ved at lave en telnet-anmodning til 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

... vender tilbage 401 Unauthorized, som forventet. Hvad sker der, hvis vi gør:

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

?

Kommer tilbage 400 Bad request — i applikationsloggen vil vi modtage en fejl, der allerede er kendt for os:

{
   "@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
}

Resultaterne af

Nærmere bestemt Kestrel kan ikke behandle HTTP-headers korrekt med de korrekte tegn i UTF-8, som er indeholdt i navnene på et ret stort antal byer.

En yderligere faktor i vores tilfælde er, at klienten ikke på nuværende tidspunkt planlægger at ændre implementeringen af ​​Kestrel i applikationen. Men problemer i selve AspNetCore (№ 4318, № 7707) siger de, at det ikke vil hjælpe...

For at opsummere: notatet handler ikke længere om de specifikke problemer med Kestrel eller UTF-8 (i 2019?!), men om det faktum, at mindfulness og konsekvent undersøgelse Hvert skridt du tager, mens du søger efter problemer, vil før eller siden bære frugt. Held og lykke!

PS

Læs også på vores blog:

Kilde: www.habr.com

Tilføj en kommentar