Kubernetes-en bizitzatik: nola HTTP zerbitzariak ez zuen espainiarren alde egin

Kubernetes-en bizitzatik: nola HTTP zerbitzariak ez zuen espainiarren alde egin

Gure bezeroaren ordezkari batek, bere aplikazio pila Microsoft hodeian (Azure), arazo bati aurre egin zion: duela gutxi, Europako bezero batzuen eskaera batzuk 400 errorearekin amaitzen hasi ziren (Eskaera txarra). Aplikazio guztiak .NET-en idatzita daude, Kubernetes-en zabalduta...

Aplikazioetako bat APIa da, eta azken finean trafiko guztia etortzen da. Trafiko hori HTTP zerbitzariak entzuten du Kortxoa, .NET bezeroak konfiguratua eta pod batean ostatatuta. Arazketarekin, zortea izan genuen arazoa etengabe erreproduzitzen zuen erabiltzaile zehatz bat zegoelako. Hala ere, dena zaildu zen trafiko-kateak:

Kubernetes-en bizitzatik: nola HTTP zerbitzariak ez zuen espainiarren alde egin

Ingress-eko errorea honelakoa izan zen:

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

Aldi berean, Kestrel-ek:

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

Gehienezko verbositatearekin ere, Kestrel akatsak oso eduki zuen informazio erabilgarria gutxi:

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

Badirudi tcpdump-ek bakarrik lagunduko duela arazo hau konpontzen... baina trafiko-kateari buruz errepikatuko dut:

Kubernetes-en bizitzatik: nola HTTP zerbitzariak ez zuen espainiarren alde egin

Ikerketa

Jakina, hobe dela trafikoa entzutea nodo zehatz horretan, non Kubernetes-ek pod bat zabaldu duen: zabortegiaren bolumena halakoa izango da, gutxienez zerbait nahiko azkar aurkitzea posible izango baita. Eta, hain zuzen ere, hura aztertzean, honako marko hau nabaritu zen:

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

Zabortegia gertuagotik begiratuta, hitza nabaritu zen M.laga. Espainian M.laga hiririk ez dagoela asmatzea erraza da (baina badago Malaga). Ideia horretaz baliatuz, Ingress konfigurazioak aztertu genituen, non duela hilabete txertatutakoa ikusi genuen (bezeroak hala eskatuta) "kaltegabea" zatia:

    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;

Goiburu hauen birbidaltzea desgaitu ondoren, dena ondo geratu zen! (Laster argi geratu zen aplikazioak berak ez zituela goiburu hauek behar.)

Ikus dezagun orain arazoa orokorrean. Aplikazio barruan erraz erreproduzitu daiteke telnet eskaera bat eginez 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

... itzultzen da 401 Unauthorized, espero bezala. Zer gertatzen da egiten badugu:

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

?

Itzuliko da 400 Bad request β€” aplikazioaren erregistroan dagoeneko ezaguna zaigun errore bat jasoko dugu:

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

Emaitzak

Zehazki Kestrel ezin behar bezala prozesatu HTTP goiburuak UTF-8-n karaktere zuzenak dituztenak, hiri kopuru handi baten izenetan daudenak.

Gure kasuan faktore gehigarri bat da bezeroak ez duela aplikazioan Kestrel-en ezarpena aldatzeko asmorik. Hala ere, arazoak AspNetCore-n bertan (β„– 4318, β„– 7707) honek ez duela lagunduko diote...

Laburbilduz: oharra ez da jada Kestrel edo UTF-8ren arazo zehatzei buruz (2019an?!), baizik eta mindfulness eta azterketa koherentea Arazoak bilatzen dituzunean ematen duzun urrats bakoitzak goiz edo geroago fruituak emango ditu. Zorte on!

PS

Irakurri ere gure blogean:

Iturria: www.habr.com

Gehitu iruzkin berria