Mula sa buhay kasama ang Kubernetes: Paano hindi pinapaboran ng HTTP server ang mga Espanyol

Mula sa buhay kasama ang Kubernetes: Paano hindi pinapaboran ng HTTP server ang mga Espanyol

Isang kinatawan ng aming kliyente, na ang application stack ay naninirahan sa cloud mula sa Microsoft (Azure), ay tumugon sa isang problema: kamakailan, ang ilang mga kahilingan mula sa ilang mga kliyente mula sa Europa ay nagsimulang magwakas sa error 400 (Masamang Kahilingan). Ang lahat ng mga application ay nakasulat sa .NET, na-deploy sa Kubernetes...

Ang isa sa mga application ay ang API, kung saan dumarating ang lahat ng trapiko. Ang trapikong ito ay pinakikinggan ng HTTP server kestrel, na-configure ng .NET client at naka-host sa isang pod. Sa pag-debug, masuwerte kami sa kahulugan na mayroong isang partikular na user na patuloy na nag-reproduce ng problema. Gayunpaman, ang lahat ay kumplikado ng kadena ng trapiko:

Mula sa buhay kasama ang Kubernetes: Paano hindi pinapaboran ng HTTP server ang mga Espanyol

Ang error sa Ingress ay ganito ang hitsura:

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

Kasabay nito, nagbigay si Kestrel:

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

Kahit na may pinakamataas na verbosity, ang Kestrel error ay naglalaman ng labis maliit na kapaki-pakinabang na impormasyon:

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

Mukhang ang tcpdump lang ang makakatulong sa paglutas ng problemang ito... ngunit uulitin ko ang tungkol sa kadena ng trapiko:

Mula sa buhay kasama ang Kubernetes: Paano hindi pinapaboran ng HTTP server ang mga Espanyol

Pagsisiyasat

Obviously, mas masarap makinig sa traffic sa partikular na node na iyon, kung saan nag-deploy ng pod ang Kubernetes: ang dami ng dump ay magiging posible na makahanap ng kahit isang bagay na medyo mabilis. At sa katunayan, kapag sinusuri ito, napansin ang sumusunod na frame:

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

Sa masusing pagsisiyasat sa tambakan, napansin ang salita M.laga. Madaling hulaan na walang lungsod ng M.laga sa Spain (ngunit mayroon malaga). Sa pagkuha sa ideyang ito, tiningnan namin ang Ingress configs, kung saan nakita namin ang ipinasok noong isang buwan (sa kahilingan ng kliyente) "hindi nakakapinsala" na 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;

Matapos i-disable ang pagpapasa ng mga header na ito, naging maayos ang lahat! (Sa lalong madaling panahon naging malinaw na ang application mismo ay hindi na kailangan ang mga header na ito.)

Ngayon tingnan natin ang problema mas pangkalahatan. Madali itong mai-reproduce sa loob ng application sa pamamagitan ng paghiling sa telnet 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

... nagbabalik 401 Unauthorized, tulad ng inaasahan. Ano ang mangyayari kung gagawin natin:

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

?

Magbabalik 400 Bad request β€” sa log ng application makakatanggap kami ng error na pamilyar na sa amin:

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

Mga resulta ng

Partikular na si Kestrel hindi pwede wastong iproseso ang mga header ng HTTP na may mga tamang character sa UTF-8, na nakapaloob sa mga pangalan ng medyo malaking bilang ng mga lungsod.

Ang isang karagdagang kadahilanan sa aming kaso ay ang kliyente ay hindi kasalukuyang nagpaplano na baguhin ang pagpapatupad ng Kestrel sa aplikasyon. Gayunpaman, ang mga isyu sa AspNetCore mismo (β„– 4318, β„– 7707) sabi nila hindi ito makakatulong...

Upang ibuod: ang tala ay hindi na tungkol sa mga partikular na problema ng Kestrel o UTF-8 (sa 2019?!), ngunit tungkol sa katotohanan na pag-iisip at pare-parehong pag-aaral Ang bawat hakbang na gagawin mo habang naghahanap ng mga problema ay magbubunga sa malao't madali. Good luck!

PS

Basahin din sa aming blog:

Pinagmulan: www.habr.com

Magdagdag ng komento