Από τη ζωή με την Kubernetes: Πώς ο διακομιστής HTTP δεν ευνόησε τους Ισπανούς

Από τη ζωή με την Kubernetes: Πώς ο διακομιστής HTTP δεν ευνόησε τους Ισπανούς

Ένας εκπρόσωπος του πελάτη μας, του οποίου η στοίβα εφαρμογών βρίσκεται στο cloud από τη Microsoft (Azure), αντιμετώπισε ένα πρόβλημα: πρόσφατα, ορισμένα αιτήματα από ορισμένους πελάτες από την Ευρώπη άρχισαν να τελειώνουν με σφάλμα 400 (Κακή Αίτηση). Όλες οι εφαρμογές είναι γραμμένες σε .NET, που αναπτύσσονται στο Kubernetes...

Μία από τις εφαρμογές είναι το API, μέσω του οποίου έρχεται τελικά όλη η κίνηση. Αυτή η κίνηση ακούγεται από τον διακομιστή HTTP Είδος μικρού γερακίου, που έχει ρυθμιστεί από τον πελάτη .NET και φιλοξενείται σε ένα pod. Με τον εντοπισμό σφαλμάτων, ήμασταν τυχεροί με την έννοια ότι υπήρχε ένας συγκεκριμένος χρήστης που αναπαρήγαγε με συνέπεια το πρόβλημα. Ωστόσο, όλα ήταν περίπλοκα από την τροχαία αλυσίδα:

Από τη ζωή με την Kubernetes: Πώς ο διακομιστής HTTP δεν ευνόησε τους Ισπανούς

Το σφάλμα στο Ingress έμοιαζε ως εξής:

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

Την ίδια στιγμή, ο Kestrel έδωσε:

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

Ακόμη και με τη μέγιστη περιφρόνηση, το σφάλμα Kestrel περιείχε εξαιρετικά λίγες χρήσιμες πληροφορίες:

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

Φαίνεται ότι μόνο το tcpdump θα βοηθήσει στην επίλυση αυτού του προβλήματος... αλλά θα επαναλάβω για την αλυσίδα κυκλοφορίας:

Από τη ζωή με την Kubernetes: Πώς ο διακομιστής HTTP δεν ευνόησε τους Ισπανούς

Ερευνα

Προφανώς, είναι καλύτερο να ακούτε την κίνηση στον συγκεκριμένο κόμβο, όπου η Kubernetes έχει αναπτύξει ένα pod: ο όγκος του dump θα είναι τέτοιος που θα είναι δυνατό να βρεθεί τουλάχιστον κάτι αρκετά γρήγορα. Και πράγματι, κατά την εξέτασή του, παρατηρήθηκε το εξής πλαίσιο:

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

Μετά από προσεκτικότερη επιθεώρηση της χωματερής, η λέξη έγινε αντιληπτή M.laga. Είναι εύκολο να μαντέψει κανείς ότι δεν υπάρχει πόλη M.laga στην Ισπανία (αλλά υπάρχει Μάλαγα). Εκμεταλλευόμενοι αυτήν την ιδέα, εξετάσαμε τις ρυθμίσεις παραμέτρων Ingress, όπου είδαμε αυτό που εισήχθη πριν από ένα μήνα (κατόπιν αιτήματος του πελάτη) «ακίνδυνο» απόσπασμα:

    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;

Μετά την απενεργοποίηση της προώθησης αυτών των κεφαλίδων, όλα έγιναν καλά! (Σύντομα έγινε σαφές ότι η ίδια η εφαρμογή δεν χρειαζόταν πλέον αυτές τις κεφαλίδες.)

Τώρα ας δούμε το πρόβλημα πιο γενικά. Μπορεί να αναπαραχθεί εύκολα μέσα στην εφαρμογή κάνοντας ένα αίτημα 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

... επιστρέφει 401 Unauthorized, όπως αναμενόταν. Τι θα συμβεί αν κάνουμε:

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

?

Θα επιστρέψει 400 Bad request — στο αρχείο καταγραφής της εφαρμογής θα λάβουμε ένα σφάλμα που είναι ήδη γνωστό σε εμάς:

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

Αποτελέσματα της

Συγκεκριμένα το Κιρκινάκι δεν μπορεί Επεξεργαστείτε σωστά τις κεφαλίδες HTTP με τους σωστούς χαρακτήρες στο UTF-8, οι οποίοι περιέχονται στα ονόματα ενός αρκετά μεγάλου αριθμού πόλεων.

Ένας επιπλέον παράγοντας στην περίπτωσή μας είναι ότι ο πελάτης δεν σχεδιάζει επί του παρόντος να αλλάξει την εφαρμογή του Kestrel στην εφαρμογή. Ωστόσο, προβλήματα στο ίδιο το AspNetCore (№ 4318, № 7707) λένε ότι αυτό δεν θα βοηθήσει...

Συνοψίζοντας: η σημείωση δεν αφορά πλέον τα συγκεκριμένα προβλήματα του Kestrel ή του UTF-8 (το 2019;!), αλλά για το γεγονός ότι επίγνωση και συνεπής μελέτη Κάθε βήμα που κάνετε αναζητώντας προβλήματα αργά ή γρήγορα θα αποφέρει καρπούς. Καλή τύχη!

PS

Διαβάστε επίσης στο blog μας:

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο