OpenVPN στο Docker: το συμβόλαιο εκτέλεσης που χρειάζεται ένας ελάχιστος πελάτης
Μια ελεγμένη εικόνα, ένα προστατευμένο προφίλ, πρόσβαση TUN και NET_ADMIN. Τι παίρνει το κοντέινερ, τι δεν πρέπει να πάρει και πώς αποδεικνύεται ότι το τούνελ λειτουργεί.
Βάλτε έναν πελάτη VPN σε ένα κοντέινερ και παίρνετε έναν χώρο ονομάτων με ένα τούνελ μέσα του, όχι έναν υπολογιστή που δρομολογεί όλη την κίνησή του μέσω VPN. Πρόκειται για ξεχωριστά έργα, και η αντιμετώπισή τους ως ενός είναι ο τρόπος με τον οποίο τα κοντέινερ καταλήγουν κατά λάθος με προνόμια. Αυτός ο οδηγός καλύπτει μόνο το πρώτο: μία ελεγμένη εικόνα, ένα προστατευμένο προφίλ και μια διεργασία πελάτη περιορισμένη στον δικό της χώρο ονομάτων δικτύου.
Ξεκινήστε από ένα τεχνούργημα που έχει ήδη εγκρίνει κάποιος. Τα παρακάτω βήματα προϋποθέτουν μια εικόνα που περιέχει το εκτελέσιμο openvpn και ένα πλήρες προφίλ πελάτη με το πιστοποιητικό και το υλικό κλειδιού του ήδη επιλυμένα μέσα στην προσάρτηση. Δεν χτίζουν λογισμικό, δεν εκδίδουν διαπιστευτήρια και δεν καλύπτουν περιβάλλοντα χωρίς root ούτε εγγενή κοντέινερ Windows, καθένα από τα οποία αλλάζει την απάντηση.
Τι παίρνει το κοντέινερ και τι δεν παίρνει
Κρατήστε το προφίλ και ό,τι αναφέρει σε έναν τοπικό κατάλογο με περιορισμένα δικαιώματα, προσαρτημένο μόνο για ανάγνωση. Οι σχετικές διαδρομές μέσα στο προφίλ πρέπει να επιλύονται μέσα σε αυτή την προσάρτηση· είναι μια λεπτομέρεια που οι άνθρωποι χάνουν όταν ένα πιστοποιητικό βρίσκεται έναν κατάλογο πάνω από το προφίλ και το κοντέινερ δεν το βλέπει ποτέ.
services:
vpn:
image: ${VPN_CLIENT_IMAGE:?set the reviewed image reference}
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- ./vpn:/vpn:ro
working_dir: /vpn
entrypoint: ["openvpn"]
command: ["--config", "/vpn/client.ovpn"]
Αυτό το αρχείο παρέχει τρία πράγματα και δεν ζητά τίποτε άλλο. Η αναφορά της εικόνας πρέπει να καρφιτσώνεται με digest αν το λέει η πολιτική ανάπτυξής σας, και το προφίλ πρέπει να είναι το ελεγμένο, όχι ένα αντίγραφο που κάποιος επεξεργάστηκε επί τόπου στον υπολογιστή.
Μόνο για ανάγνωση εδώ σημαίνει ότι το κοντέινερ δεν μπορεί να αλλάξει τα αρχεία σας στον υπολογιστή· δεν σημαίνει ότι δεν μπορεί να διαβάσει το ιδιωτικό κλειδί που προσαρτήσατε. Αυτός είναι όλος ο σκοπός της προσάρτησης, και γι' αυτό τα δικαιώματα αρχείων, η ιδιοκτησία και το πώς έφτασε το μυστικό στον υπολογιστή εξακολουθούν να έχουν σημασία. Μη μεταβιβάζετε ποτέ κωδικό πρόσβασης στη γραμμή εντολών και μην τον ψήνετε σε επίπεδο εικόνας, γιατί και τα δύο επιβιώνουν σε σημεία που δεν μπορείτε να καθαρίσετε αργότερα.
Δυνατότητες, entrypoint και η παγίδα ανάμεσά τους
Χρειάζονται δύο ρυθμίσεις και κάνουν άσχετες δουλειές. Το NET_ADMIN επιτρέπει χειρισμό διασυνδέσεων και διαδρομών μέσα στον χώρο ονομάτων του κοντέινερ. Η καταχώριση συσκευής /dev/net/tun επιτρέπει στη διεργασία να ανοίξει καθόλου τη συσκευή τούνελ. Η παροχή του ενός χωρίς το άλλο παράγει σαφή αποτυχία, κάτι που είναι βολικό: μια απούσα συσκευή TUN αποτυγχάνει στο άνοιγμα, ενώ μια απούσα δυνατότητα αποτυγχάνει όταν ο πελάτης προσπαθεί να ρυθμίσει τη διασύνδεση.
Κανένα από τα δύο δεν δικαιολογεί το privileged: true. Ένα κοντέινερ με προνόμια παίρνει κάθε δυνατότητα συν πρόσβαση σε συσκευές, και αυτό είναι πολύ μεγαλύτερη παραχώρηση από ό,τι χρειάζεται αυτό το φορτίο εργασίας. Η αναφορά προνομίων και δυνατοτήτων του περιβάλλοντος εκτέλεσης εξηγεί πόσο μακριά φτάνει αυτή η παραχώρηση. Αν ένα chart ή μια ανάρτηση ιστολογίου το ζητά, ελέγξτε πρώτα αν η απαίτηση ήταν στην πραγματικότητα μια απούσα διαδρομή συσκευής ή μια απούσα δυνατότητα.
Η παράκαμψη του entrypoint είναι το κομμάτι που δαγκώνει. Η άμεση κλήση του openvpn είναι σωστή για μια συνηθισμένη εικόνα και λάθος για κάθε εικόνα προϊόντος της οποίας το σενάριο εκκίνησης προετοιμάζει κανόνες τείχους προστασίας, αρχεία resolver ή διαπιστευτήρια πριν εκτελέσει τον δαίμονα. Η παράκαμψη αυτού του σεναρίου παραλείπει την προετοιμασία και σας αφήνει να αποσφαλματώσετε ένα τούνελ που σηκώθηκε σε μισοδιαμορφωμένο χώρο ονομάτων.
Τρέξτε τον πελάτη στο προσκήνιο και αφήστε τον να είναι η κύρια διεργασία του κοντέινερ. Μια διεργασία που δαιμονοποιείται εξέρχεται αμέσως, το κοντέινερ επανεκκινείται σε βρόχο, και τα αρχεία καταγραφής που χρειάζεστε είναι διάσπαρτα σε επανεκκινήσεις που όλες μοιάζουν ίδιες.
Επαληθεύστε από μέσα στον χώρο ονομάτων, όχι από τον υπολογιστή
Σηκώστε τη στοίβα, επιβεβαιώστε στο αρχείο καταγραφής ότι ο πελάτης έφτασε σε συνδεδεμένη κατάσταση και μετά επιθεωρήστε τον χώρο ονομάτων που κρατά πραγματικά το τούνελ.
docker compose up -d
docker compose logs --tail 40 vpn
docker compose exec vpn ip -br addr
docker compose exec vpn ip route
Η λίστα διευθύνσεων θα πρέπει να δείχνει μια διασύνδεση τούνελ με διεύθυνση από τη δεξαμενή, και ο πίνακας δρομολόγησης θα πρέπει να δείχνει τους προωθημένους προορισμούς να δείχνουν προς αυτή. Αν η διασύνδεση λείπει, ο πελάτης δεν έφτασε ποτέ στο σημείο να τη δημιουργήσει. Αν υπάρχει αλλά καμία διαδρομή δεν τη χρησιμοποιεί, το σημείο αναζήτησης είναι το push ή οι επιλογές διαδρομής.
Στη συνέχεια δοκιμάστε τον προορισμό που σας ενδιαφέρει, από τον χώρο ονομάτων που υποτίθεται ότι χρησιμοποιεί το τούνελ, με την εφαρμογή και όχι μόνο με ping. Η επίλυση ονομάτων είναι μια ξεχωριστή αποτυχία που αξίζει ρητή δοκιμή: μια προωθημένη διεύθυνση DNS δεν ενημερώνει από μόνη της τον resolver ενός κοντέινερ, και ένας αυτόνομος πελάτης που αγνοεί το push θα επιλύει ονόματα μέσω ό,τι έχει ρυθμίσει η εικόνα.
Η αποσυνδεδεμένη κατάσταση είναι μέρος του συμβολαίου
Η συμπεριφορά επανασύνδεσης χρειάζεται δικό της έλεγχο, γιατί μια πολιτική επανεκκίνησης αποδεικνύει ότι η διεργασία επανεκκινείται και δεν λέει τίποτε για το τι κάνει η κίνηση στο μεταξύ. Σταματήστε το τούνελ, δοκιμάστε τον επιδιωκόμενο προορισμό και παρατηρήστε αν η σύνδεση απορρίπτεται, κολλάει ή πετυχαίνει σιωπηλά μέσω της συνηθισμένης διαδρομής του κοντέινερ. Το τελευταίο αποτέλεσμα είναι αυτό που μετρά, και είναι αόρατο σε ένα υγιές αρχείο καταγραφής.
Αν το φορτίο εργασίας δεν πρέπει ποτέ να χρησιμοποιεί τη συνηθισμένη διαδρομή, σχεδιάστε το ρητά με κανόνες τείχους προστασίας και ένα σήμα ετοιμότητας μέσα στον χώρο ονομάτων. Ένα kill switch είναι μια πολιτική που γράφετε και δοκιμάζετε, όχι μια ιδιότητα που κληρονομείτε τρέχοντας έναν πελάτη σε ένα κοντέινερ.
Τέλος, θυμηθείτε το όριο: αυτές οι διαδρομές ζουν στον χώρο ονομάτων του κοντέινερ και δεν αντικαθιστούν τον πίνακα δρομολόγησης του υπολογιστή. Οι κανόνες προώθησης, μετάφρασης και τείχους προστασίας του Docker παραμένουν μέρος της εξωτερικής διαδρομής, και μια δημοσιευμένη θύρα δεν είναι διασύνδεση VPN.