Fra livet med Kubernetes: Hvordan HTTP-serveren ikke favoriserte spanjolene

Fra livet med Kubernetes: Hvordan HTTP-serveren ikke favoriserte spanjolene

En representant for vår klient, hvis applikasjonsstabel ligger i Microsoft-skyen (Azure), løste et problem: nylig begynte noen forespørsler fra noen klienter fra Europa å ende med feil 400 (Dårlig forespørsel). Alle applikasjoner er skrevet i .NET, distribuert i Kubernetes...

En av applikasjonene er API, som all trafikk til slutt kommer gjennom. Denne trafikken lyttes til av HTTP-serveren Kestrel, konfigurert av .NET-klienten og vert i en pod. Med feilsøking var vi heldige i den forstand at det var en spesifikk bruker som konsekvent reproduserte problemet. Alt ble imidlertid komplisert av trafikkkjeden:

Fra livet med Kubernetes: Hvordan HTTP-serveren ikke favoriserte spanjolene

Feilen i Ingress så slik ut:

{
   "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 ga 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 inneholdt Kestrel-feilen ekstremt lite nyttig informasjon:

{
   "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 ut til at bare tcpdump vil bidra til å løse dette problemet ... men jeg vil gjenta om trafikkkjeden:

Fra livet med Kubernetes: Hvordan HTTP-serveren ikke favoriserte spanjolene

etterforskning

Det er klart det er bedre å lytte til trafikken på den spesifikke noden, hvor Kubernetes har distribuert en pod: volumet på dumpen vil være slik at det vil være mulig å finne i det minste noe ganske raskt. Og faktisk, når du undersøkte det, ble følgende ramme lagt merke til:

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 inspeksjon av fyllingen ble ordet lagt merke til M.laga. Det er lett å gjette at det ikke er noen M.laga-by i Spania (men det er det Malaga). Med denne ideen så vi på Ingress-konfigurasjonene, der vi så den som ble satt inn for en måned siden (på klientens forespørsel) "ufarlig" utdrag:

    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;

Etter å ha deaktivert videresending av disse overskriftene, ble alt bra! (Det ble snart klart at selve applikasjonen ikke lenger trengte disse overskriftene.)

La oss nå se på problemet mer generelt. Det kan enkelt reproduseres inne i applikasjonen ved å gjøre en telnet-forespørsel 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

... returnerer 401 Unauthorized, som forventet. Hva skjer hvis vi gjø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

?

Vil returnere 400 Bad request — i søknadsloggen vil vi motta en feil som allerede er kjent for oss:

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

Resultater av

Nærmere bestemt Kestrel kan ikke korrekt behandle HTTP-overskrifter med de riktige tegnene i UTF-8, som finnes i navnene på et ganske stort antall byer.

Et tilleggsmoment i vårt tilfelle er at oppdragsgiver foreløpig ikke planlegger å endre implementeringen av Kestrel i applikasjonen. Imidlertid problemer i selve AspNetCore (№ 4318, № 7707) de sier at dette ikke vil hjelpe...

For å oppsummere: notatet handler ikke lenger om de spesifikke problemene til Kestrel eller UTF-8 (i 2019?!), men om det faktum at oppmerksomhet og konsekvente studier Hvert skritt du tar mens du leter etter problemer vil før eller siden bære frukter. Lykke til!

PS

Les også på bloggen vår:

Kilde: www.habr.com

Legg til en kommentar