De la vida amb Kubernetes: com el servidor HTTP no afavoria els espanyols

De la vida amb Kubernetes: com el servidor HTTP no afavoria els espanyols

Un representant del nostre client, la pila d'aplicacions del qual resideix al núvol de Microsoft (Azure), va solucionar un problema: recentment, algunes sol·licituds d'alguns clients d'Europa van començar a acabar amb l'error 400 (Sol·licitud incorrecta). Totes les aplicacions estan escrites en .NET, desplegades a Kubernetes...

Una de les aplicacions és l'API, a través de la qual finalment arriba tot el trànsit. Aquest trànsit és escoltat pel servidor HTTP Xoriguer, configurat pel client .NET i allotjat en un pod. Amb la depuració, vam tenir sort en el sentit que hi havia un usuari específic que reproduïa constantment el problema. Tot i això, tot es va complicar per la cadena de trànsit:

De la vida amb Kubernetes: com el servidor HTTP no afavoria els espanyols

L'error a Ingress tenia aquest aspecte:

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

Al mateix temps, Kestrel va donar:

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

Fins i tot amb la màxima verbositat, l'error Kestrel contenia extremadament poca informació útil:

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

Sembla que només tcpdump ajudarà a resoldre aquest problema... però repetiré sobre la cadena de trànsit:

De la vida amb Kubernetes: com el servidor HTTP no afavoria els espanyols

Investigació

Evidentment, és millor escoltar el trànsit en aquest node específic, on Kubernetes ha desplegat un pod: el volum de l'abocador serà tal que serà possible trobar almenys alguna cosa amb força rapidesa. I de fet, en examinar-lo, es va notar el següent marc:

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

En inspeccionar més de prop l'abocador, es va notar la paraula M.laga. És fàcil endevinar que no hi ha cap ciutat M.laga a Espanya (però n'hi ha Màlaga). Aprofitant aquesta idea, vam mirar les configuracions d'Ingress, on vam veure la inserida fa un mes (a petició del client) fragment "inofensiu".:

    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;

Després de desactivar el reenviament d'aquestes capçaleres, tot va anar bé! (Aviat va quedar clar que l'aplicació ja no necessitava aquestes capçaleres.)

Ara mirem el problema més generalment. Es pot reproduir fàcilment dins de l'aplicació fent una sol·licitud de telnet a 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

... torna 401 Unauthorized, com s'esperava. Què passa si fem:

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

?

Tornarà 400 Bad request — al registre de l'aplicació rebrem un error que ja ens és familiar:

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

Resultats de

Concretament Xoriguer no pot processar correctament les capçaleres HTTP amb els caràcters correctes en UTF-8, que es troben en els noms d'un nombre bastant gran de ciutats.

Un factor addicional en el nostre cas és que el client actualment no té previst canviar la implementació de Kestrel a l'aplicació. Tanmateix, els problemes al mateix AspNetCore (№ 4318, № 7707) diuen que això no ajudarà...

En resum: la nota ja no tracta dels problemes específics de Kestrel o UTF-8 (el 2019?!), sinó del fet que mindfulness i estudi coherent Cada pas que feu mentre busqueu problemes tard o d'hora donarà els seus fruits. Bona sort!

PS

Llegeix també al nostre blog:

Font: www.habr.com

Afegeix comentari