Σφάλμα check_hostname του pip πίσω από proxy: pip ή το τούνελ;
Δύο αποτυχίες εκτυπώνουν το ίδιο μήνυμα ονόματος κεντρικού υπολογιστή του pip πίσω από proxy. Ξεχωρίστε έναν παλιό πελάτη από ένα proxy που επαναϋπογράφει την κίνηση και επισκευάστε το σωστό επίπεδο.
Δύο διαφορετικές βλάβες εκτυπώνουν το ίδιο traceback του pip και η επισκευή που ταιριάζει στη μία χειροτερεύει την άλλη. Ένας πελάτης πολύ παλιός για να ονομάσει έναν τούνελ κεντρικό υπολογιστή χρειάζεται αναβάθμιση. Ένα proxy που επαναϋπογράφει την κίνηση χρειάζεται αξιόπιστο ριζικό πιστοποιητικό, όχι υποβάθμιση. Βρείτε ποια από τις δύο έχετε πριν επεξεργαστείτε μια μεταβλητή proxy, γιατί τα μονοπάτια οδηγούν σε αντίθετες κατευθύνσεις.
Διαβάστε τα τελευταία πλαίσια πριν αγγίξετε τις ρυθμίσεις
Το σημείο όπου τελειώνει το traceback σας λέει ποιο επίπεδο τα παράτησε. Αν τα τελικά πλαίσια βρίσκονται μέσα στον ενσωματωμένο κώδικα TLS του urllib3 στο pip και το κείμενο παραπονιέται για όνομα κεντρικού υπολογιστή, η βιβλιοθήκη πελάτη δεν μπόρεσε να ολοκληρώσει ένα βήμα επαλήθευσης, και αυτό είναι πρόβλημα έκδοσης πολύ συχνότερα παρά πρόβλημα πιστοποιητικού. Αν το κείμενο αναφέρει αντ' αυτού απορριφθείσα σύνδεση, άλυτο όνομα proxy ή σφάλμα HTTP 407, φταίει το τελικό σημείο του τούνελ και καμία αναβάθμιση δεν θα το αλλάξει.
Καταγράψτε την έκδοση του pip και τις μεταβλητές proxy στο ίδιο κέλυφος που αποτυγχάνει. Ένα κέλυφος που άνοιξε πριν σηκωθεί το τούνελ φέρει διαφορετικές τιμές από ένα που άνοιξε μετά, και η διαφορά μεταξύ τους είναι συχνά ολόκληρη η διάγνωση.
python3 -m pip --version
env | grep -i -E 'proxy|no_proxy'
Όταν ο πελάτης είναι παλαιότερος από το τούνελ
Οι παλαιότερες εκδόσεις του pip ενσωμάτωναν μια στοίβα HTTPS που έχανε το όνομα του προορισμού μόλις το socket τυλιγόταν από τούνελ. Το μήνυμα check_hostname είναι αυτό που εκπέμπει αυτή η στοίβα όταν φτάνει στην επαλήθευση χωρίς όνομα για σύγκριση. Η αναβάθμιση αφαιρεί τη βλάβη επειδή ο νεότερος πελάτης διατηρεί το όνομα καθ' όλη τη χειραψία, και η αλλαγή είναι αρκετά φθηνή ώστε να δοκιμαστεί πρώτη όποτε τα τελικά πλαίσια δείχνουν ενσωματωμένο κώδικα TLS.
Αν ο κατάλογος δεν είναι προσβάσιμος από το μηχάνημα που αποτυγχάνει, κατεβάστε ένα τρέχον wheel σε έναν κεντρικό υπολογιστή που μπορεί και εγκαταστήστε το από το αρχείο. Χρησιμοποιήστε το όνομα αρχείου που κατεβάσατε πραγματικά, όχι μια έκδοση αντιγραμμένη από μια ανάρτηση ιστολογίου.
python3 -m pip install --upgrade pip
python3 -m pip install ./pip-24.2-py3-none-any.whl
Όταν το proxy επαναϋπογράφει την κίνηση
Ένα proxy που τερματίζει το TLS και επανεκδίδει πιστοποιητικά κάτω από εταιρική ρίζα παράγει διαφορετικό σφάλμα: certificate verify failed, όχι παράπονο για όνομα κεντρικού υπολογιστή. Αυτή η διαφορά είναι το στοιχείο, γιατί ο πελάτης έφτασε σε έναν διακομιστή και μετά απέρριψε την ταυτότητα που του δείχθηκε. Η επισκευή είναι να εμπιστευτείτε ρητά αυτή τη ρίζα, είτε για μία εντολή είτε μέσω της μεταβλητής PIP_CERT, ώστε ο πελάτης να μπορεί να χτίσει αλυσίδα προς ό,τι παρουσιάζει το proxy. Η προσθήκη της ρίζας στο σύστημα αξιόπιστων πιστοποιητικών λειτουργεί επίσης, αλλά αλλάζει την εμπιστοσύνη για κάθε πρόγραμμα στο μηχάνημα, που είναι μεγαλύτερη απόφαση από τη διόρθωση μιας εγκατάστασης πακέτου.
Κρατήστε το --trusted-host ως διαγνωστικό εργαλείο, ποτέ ως μόνιμη κατάσταση. Απενεργοποιεί τον έλεγχο που προσπαθούσατε να διατηρήσετε, οπότε ένα πραγματικά λάθος πιστοποιητικό φαίνεται υγιές μετά. Αν το χρησιμοποιήσατε για να εγκαταστήσετε ένα πακέτο, αφαιρέστε το και επισκευάστε την αλυσίδα πριν από την επόμενη έκδοση.
Ο δικός σας κώδικας Python αγνοεί εντελώς τη διαμόρφωση του pip. Μια κλήση requests χρειάζεται το proxy και το πακέτο περασμένα εκεί όπου τα βλέπει αυτή η συνεδρία, γι' αυτό το παρακάτω μπλοκ θέτει και τα δύο στο αντικείμενο συνεδρίας.
pip install --cert /usr/local/share/ca-certificates/corp-root.crt requests
export PIP_CERT=/usr/local/share/ca-certificates/corp-root.crt
s = requests.Session()
s.proxies = {"https": "http://10.20.30.40:8080"}
s.verify = "/usr/local/share/ca-certificates/corp-root.crt"
s.get("https://pypi.org/simple/", timeout=15)
Όταν το τελικό σημείο ή η θύρα είναι λάθος
Ένας πελάτης τούνελ συχνά ξαναγράφει το proxy του συστήματος καθώς συνδέεται, κάτι που μπορεί να αφήσει το pip στραμμένο σε έναν κεντρικό υπολογιστή που δεν απαντά ποτέ σε αυτή τη θύρα. Δοκιμάστε το τελικό σημείο με πελάτη που δεν είναι pip πριν αλλάξετε οποιαδήποτε ρύθμιση του pip. Αν το curl αποτύχει με το ίδιο όρισμα proxy, η βλάβη βρίσκεται πάνω από το pip και καμία ποσότητα διαμόρφωσης μέσα στο pip δεν θα βοηθήσει.
Η σημαία εντολής και οι μεταβλητές περιβάλλοντος λένε το ίδιο πράγμα σε διαφορετικά πεδία: η σημαία ισχύει για μία κλήση, οι μεταβλητές για κάθε διεργασία που ξεκινά μετά. Προσθέστε NO_PROXY για έναν εσωτερικό κατάλογο ώστε η ιδιωτική κίνηση πακέτων να παρακάμπτει την παράκαμψη μέσω του τούνελ.
curl -x http://proxy.corp.internal:8080 --head https://pypi.org/simple/
pip install --proxy http://proxy.corp.internal:8080 requests
Αποθηκεύστε τη ρύθμιση και αποδείξτε ότι το μονοπάτι λειτουργεί
Αποθηκεύστε το proxy στη δική του διαμόρφωση του pip όταν πρέπει να επιβιώσει από το τρέχον κέλυφος, και μετά διαβάστε τι θα χρησιμοποιήσει πραγματικά το pip. Η έξοδος debug ονομάζει το αρχείο και τη μεταβλητή πίσω από κάθε τιμή, κάτι που λύνει τις διαφωνίες για την προτεραιότητα γρηγορότερα από την ανάγνωση της τεκμηρίωσης.
Η επαλήθευση χρησιμοποιεί σκόπιμα δύο πελάτες. Το αίτημα της τυπικής βιβλιοθήκης αποδεικνύει τη διαδρομή και την αλυσίδα εμπιστοσύνης, ενώ η λήψη αποδεικνύει ότι η δική του διαμόρφωση του pip συμφωνεί μαζί τους. Όταν το πρώτο πετυχαίνει και το δεύτερο αποτυγχάνει, η διαφορά είναι μέσα στο pip και όχι στο δίκτυο.
pip config set global.proxy http://proxy.corp.internal:8080
pip config debug
python3 -c "import urllib.request as r; print(r.urlopen('https://pypi.org/simple/').status)"
pip download --no-deps -d /tmp/wheelcheck requests
| What you see | First command | Repair |
|---|---|---|
| hostname message inside vendored TLS frames | python3 -m pip --version | upgrade the client |
| certificate verify failed after the tunnel | curl -x http://proxy.corp.internal:8080 --head https://pypi.org/simple/ | trust the corporate root |
| connection refused or HTTP 407 | env | grep -i -E 'proxy|no_proxy' | correct host, port or credentials |