Το Nginx μπροστά, ιδιωτικό backend πίσω από το VPN
Ο περιηγητής μιλά στο Nginx, και το Nginx ανοίγει δεύτερη σύνδεση μέσα στη σήραγγα. Δρομολόγησε και τις δύο, επαλήθευσε και τα δύο πιστοποιητικά και κράτησε δημόσιες τις δημόσιες ανακατευθύνσεις.
Ακολούθησε ένα αίτημα από ένα τηλέφωνο σε τρένο μέχρι ένα backend που υπάρχει μόνο μέσα σε ιδιωτικό δίκτυο. Το τηλέφωνο επιλύει ένα δημόσιο όνομα, συνδέεται σε μια δημόσια διεύθυνση στη θύρα 443 και ολοκληρώνει μια κανονική χειραψία TLS. Το Nginx δέχεται αυτή τη σύνδεση και μετά ανοίγει μια δεύτερη, εντελώς ξεχωριστή, προς μια διεύθυνση που φτάνει μόνο μέσω διεπαφής VPN. Τίποτα στο τηλέφωνο δεν αλλάζει, και το τηλέφωνο δεν μαθαίνει ποτέ ότι υπήρξε σήραγγα.
Παρακολούθηση ενός αιτήματος μέσα από δύο συνδέσεις
Το εισερχόμενο σκέλος είναι μια δημόσια συναλλαγή HTTP. Έχει δημόσιο όνομα, δημόσιο πιστοποιητικό και διαδρομή απάντησης που πρέπει να λειτουργεί για οποιαδήποτε διεύθυνση έχει ο επισκέπτης εκείνη τη στιγμή. Οποιαδήποτε αλλαγή διαταράσσει αυτή τη διαδρομή σπάει όλους τους επισκέπτες ταυτόχρονα. Γι’ αυτό το δημόσιο σκέλος είναι αυτό στο οποίο θέλεις λιγότερο να πειραματιστείς.
Το εξερχόμενο σκέλος είναι ιδιωτικό. Το Nginx γίνεται πελάτης, επιλύει ένα εσωτερικό όνομα ή χρησιμοποιεί σταθερή διεύθυνση, και φτάνει σε μια υπηρεσία που θα απέρριπτε σύνδεση από το διαδίκτυο.
Public client -> frontend public address:443 (TLS, public name)
Frontend -> VPN private backend 10.40.0.20:8443 (TLS, private name)
Κράτησέ τα ξεχωριστά στο μυαλό σου και η διαμόρφωση γίνεται προφανής. Αν τα ενώσεις, θα καταλήξεις να προσπαθείς να βάλεις έναν δημόσιο πελάτη να συμμετάσχει σε σήραγγα, και από εκεί προέρχεται το μεγαλύτερο μέρος της σύγχυσης σε αυτόν τον σχεδιασμό. Το ιδιωτικό σκέλος επιτρέπεται να είναι εύθραυστο. Το δημόσιο όχι.
Πριν χτίσεις οτιδήποτε από αυτά, επιβεβαίωσε ότι η δημοσίευση της εφαρμογής είναι σκόπιμη. Ένας διακομιστής μεσολάβησης που λειτουργεί είναι και μια έκθεση που λειτουργεί, και το μοντέλο ταυτοποίησης πρέπει να είναι απόφαση και όχι παρενέργεια.
Το όνομα της πύλης πρέπει να επιβιώσει της σήραγγας
Υπάρχει μια λεπτή παγίδα στην επίλυση ονομάτων. Αν το ιδιωτικό DNS υπεργράψει το ίδιο όνομα που το προφίλ VPN χρησιμοποιεί για τη δική του πύλη, μια επανασύνδεση μπορεί να καταλήξει να προσπαθεί να φτάσει αυτή την πύλη μέσα από τη σήραγγα που υποτίθεται ότι θα δημιουργήσει. Ο πελάτης χρειάζεται αυτό το όνομα επιλυμένο πριν υπάρξει η σήραγγα. Μόλις επιλυθεί μέσα στη σήραγγα, η σύνδεση δεν μπορεί πια να χτιστεί.
Χρησιμοποίησε ξεχωριστά εγκεκριμένα ονόματα για την πύλη και το backend, και περιόρισε την πολιτική του resolver ώστε κάθε όνομα να επιλύεται στη διεύθυνση που χρειάζεται ο καταναλωτής του. Η αλλαγή της κεφαλίδας Host μιας εφαρμογής δεν βοηθά εδώ, γιατί την αναζήτηση την κάνει ο πελάτης VPN.
Στη συνέχεια σκέψου το εύρος. Το frontend χρειάζεται διαδρομή προς τη διεύθυνση του backend, και πρέπει επίσης να συνεχίσει να απαντά σε δημόσιους πελάτες. Μια πλήρης σήραγγα σε αυτόν τον κεντρικό υπολογιστή μπορεί να ικανοποιήσει την πρώτη απαίτηση και να σπάσει τη δεύτερη.
Όπου η πολιτική το επιτρέπει, μια σήραγγα προς συγκεκριμένο προορισμό είναι ο καθαρότερος σχεδιασμός. Όπου η πολιτική απαιτεί πλήρη σήραγγα, το frontend ανήκει σε ξεχωριστό δικτυακό περιβάλλον αντί να μπαλώνεται με ad hoc διαδρομές για γνωστούς επισκέπτες.
Γράψε το μπλοκ διακομιστή ώστε και τα δύο σκέλη να επαληθεύουν
Υπόθεσε ότι το backend παρουσιάζει πιστοποιητικό για backend.corp.example και απαντά σε ιδιωτική διεύθυνση. Το να συνδέεσαι σε μια διεύθυνση ενώ επαληθεύεις ένα όνομα είναι ακριβώς ο σκοπός των επιλογών SNI και ονόματος της μονάδας proxy.
upstream private_app {
server 10.40.0.20:8443;
}
server {
listen 443 ssl;
server_name app.example.com;
ssl_certificate /etc/nginx/tls/app-fullchain.pem;
ssl_certificate_key /etc/nginx/tls/app-key.pem;
location / {
proxy_pass https://private_app;
proxy_ssl_server_name on;
proxy_ssl_name backend.corp.example;
proxy_ssl_trusted_certificate /etc/nginx/trust/backend-ca.pem;
proxy_ssl_verify on;
proxy_ssl_verify_depth 3;
proxy_set_header Host app.example.com;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
Κάθε διαδρομή και διεύθυνση παραπάνω είναι ένα σύμβολο κράτησης θέσης. Τα σημαντικά μέρη είναι εκείνα που κρατούν την επαλήθευση ενεργή: ένα όνομα προς έλεγχο, ένα πακέτο εμπιστοσύνης για έλεγχο απέναντί του και ένα βάθος που ταιριάζει με την εγκεκριμένη αλυσίδα.
proxy_set_header Host app.example.com είναι σκόπιμο. Το backend πρέπει να ρυθμιστεί ώστε να δέχεται αυτή τη δημόσια προέλευση, και πρέπει να εμπιστεύεται προωθημένες κεφαλίδες μόνο από αυτό το frontend. Το να υπεργράφεις το X-Forwarded-For με τη διεύθυνση του πελάτη είναι σωστό για έναν μόνο μεσολαβητή και λάθος για αλυσίδα, οπότε μια εγκατάσταση με πολλούς μεσολαβητές χρειάζεται τη δική της ρύθμιση αξιόπιστων διευθύνσεων.
Κάνε τη δημόσια προέλευση να συμπεριφέρεται ως τέτοια
Η εφαρμογή πρέπει να εκδίδει απόλυτα URL, ανακατευθύνσεις και cookies για τη δημόσια προέλευση. Αν ανακατευθύνει έναν επισκέπτη στο backend.corp.example, αυτός ο επισκέπτης στέλνεται σε ένα όνομα που δεν μπορεί να επιλύσει.
Διόρθωσέ το μέσω της υποστηριζόμενης ρύθμισης εξωτερικού URL της εφαρμογής και μιας αναθεωρημένης πολιτικής ανακατεύθυνσης, όχι ξαναγράφοντας ονόματα κεντρικών υπολογιστών στα σώματα των απαντήσεων. Η αντικατάσταση συμβολοσειρών σε αυθαίρετο περιεχόμενο σπάει υπογεγραμμένα φορτία και δημιουργεί σφάλματα που δύσκολα εντοπίζονται.
Τα cookies αξίζουν την ίδια φροντίδα. Ένα cookie περιορισμένο στο ιδιωτικό όνομα δεν θα σταλεί ποτέ από περιηγητή που γνωρίζει μόνο το δημόσιο.
Επιβεβαίωσε επίσης ότι το Nginx μπορεί πραγματικά να κατέχει τη δημόσια υποδοχή. Μια υπάρχουσα υπηρεσία ιστού στη θύρα 443 πρέπει να μετακινηθεί ή το frontend πρέπει να ζει αλλού, γιατί δύο διεργασίες δεν μπορούν να δεσμεύσουν την ίδια διεύθυνση και θύρα.
Έλεγξε κάθε σκέλος εκεί όπου πραγματικά εκτελείται
Επαλήθευσε τη διαμόρφωση με τον εγκατεστημένο αναλυτή πριν από κάθε επαναφόρτωση, ώστε ένα τυπογραφικό λάθος να μην ρίξει τον ακροατή που εξυπηρετεί αυτή τη στιγμή.
Στη συνέχεια δοκίμασε το σκέλος του backend από τον ίδιο τον κεντρικό υπολογιστή του frontend, στο ίδιο δικτυακό περιβάλλον που χρησιμοποιεί το Nginx. Ένα ping μέσα από τη σήραγγα αποδεικνύει προσβασιμότητα και τίποτα για TLS, εξουσιοδότηση ή την εφαρμογή.
Τέλος κάνε ένα νέο δημόσιο αίτημα προς το πραγματικό όνομα κεντρικού υπολογιστή με κανονική επαλήθευση πιστοποιητικού, και παρατήρησε τη διαδρομή απάντησης και όχι μόνο το σώμα.
Κράτησε και τις δύο παρατηρήσεις μαζί με τη διαμορφωμένη εγκατάσταση και κατέγραψε τι συμβαίνει όταν η σήραγγα δεν είναι διαθέσιμη. Το frontend πρέπει να επιστρέφει ελεγχόμενο σφάλμα upstream, όχι να πέφτει σιωπηλά σε άλλο backend που κανείς δεν τεκμηρίωσε. Ένα 502 με καθαρή γραμμή αρχείου καταγραφής είναι καλό αποτέλεσμα. Μια σελίδα από προσωρινή μνήμη από ανεπιθύμητη προέλευση δεν είναι.