Ιστολόγιο
Ποιοι πελάτες πραγματικά χρειάζονται τη δική τους εικονική μηχανή; Ένα σχέδιο απομόνωσης Docker με επίπεδα
Μια εικονική μηχανή για κάθε πελάτη είναι υπερβολή. Δείτε πώς να αποφασίσετε πόση απομόνωση χρειάζεται κάθε μισθωτής—και πώς να αυτοματοποιήσετε την απόφαση.
Σύνοψη
Οι οργανισμοί συχνά πανικοβάλλονται όταν ένας πελάτης ρωτά πόσο πραγματικά απομονωμένα είναι τα δεδομένα του από άλλους μισθωτές. Τα namespaces και τα cgroups του Docker παρέχουν πραγματική απομόνωση, αλλά δεν είναι το ίδιο με ένα όριο υλικού. Αντί να τρέχετε κάθε πελάτη σε εικονική μηχανή—ή χειρότερα, να αντιμετωπίζετε όλους τους πελάτες το ίδιο—δημιουργήστε ένα μικρό σύνολο επιπέδων απομόνωσης και αντιστοιχίστε κάθε πελάτη σε ένα με βάση την ευαισθησία των δεδομένων, την εμπιστοσύνη και τη συμμόρφωση. Ένα περιορισμένο container (χωρίς root, χωρίς δυνατότητες, seccomp, μόνο για ανάγνωση root) καλύπτει τις περισσότερες ιστοσελίδες· οι ρυθμισμένες ή εχθρικές εργασίες χρειάζονται εικονική μηχανή ή υβριδικό μοντέλο container-σε-εικονική μηχανή. Αυτό το άρθρο παρέχει μια επαναλήψιμη διαδικασία απόφασης, έναν πίνακα σύγκρισης και μια ειλικρινή ματιά στο πότε η επιπλέον απομόνωση είναι υπερβολή.
Είστε σε εκείνο το σημείο μιας εμπορικής κλήσης όπου ο νέος πελάτης λέει «είμαστε στον τομέα της υγείας, δείξε μου ότι τα δεδομένα μας είναι απομονωμένα από τους άλλους πελάτες σου» και θα προτιμούσατε να μιλήσετε για οτιδήποτε άλλο;
Αυτό είναι το πρόβλημα των οργανισμών: όχι μία τέλεια ανάπτυξη, αλλά η ίδια αξιόπιστη ανάπτυξη επαναλαμβανόμενη σε δώδεκα πελάτες με διαφορετικούς προϋπολογισμούς, προφίλ κινδύνου και απαιτήσεις συμμόρφωσης. Ορίστε η ειλικρινής εκδοχή. Η απομόνωση του Docker είναι πραγματική, αλλά είναι συγκεκριμένη. Τα namespaces δίνουν σε κάθε container τη δική του άποψη για διεργασίες, δίκτυο και σύστημα αρχείων· τα cgroups περιορίζουν CPU, μνήμη και I/O δίσκου έτσι ώστε οι μισθωτές να μην μπορούν να αλληλοεξαντληθούν. Αυτό που δεν σας αγοράζει είναι ένας τοίχος υλικού μεταξύ του container και του πυρήνα του host. Αν ένας εισβολέας δραπετεύσει από το container, βρίσκεται μέσα στον μοναδικό πυρήνα που έχετε. Το υπόλοιπο αυτού του άρθρου μετατρέπει αυτό το άβολο γεγονός σε μια επαναλήψιμη απόφαση: ταξινομήστε κάθε πελάτη με βάση την ευαισθησία δεδομένων και την εμπιστοσύνη, εφαρμόστε ένα βασικό προφίλ σκλήρυνσης και φτάστε μόνο σε εικονική μηχανή όταν το κόστος μιας παραβίασης είναι υψηλότερο από το κόστος της εικονικής μηχανής.
Περιμένετε, δεν είναι ήδη απομονωμένα τα containers;
Το Docker τρέχει σε namespaces και cgroups του Linux, και αυτές οι λέξεις κάνουν πραγματική δουλειά. Τα namespaces διαχωρίζουν IDs διεργασιών, στοίβες δικτύου, σημεία προσάρτησης και χρήστες, ώστε μια διεργασία σε ένα container να μην μπορεί να δει τον πίνακα διεργασιών ενός άλλου. Τα cgroups θέτουν όρια: δώστε σε ένα container 0,5 CPU, 512 MB μνήμης και σταθερό βάρος I/O μπλοκ, και αυτό ακριβώς παίρνει. Ένας ανεξέλεγκτος βρόχος σε έναν μισθωτή περιορίζεται αντί να ρίξει τον γείτονα. Αν δεν έχετε διαμορφώσει όρια, έχετε παραλείψει το πιο βασικό πράγμα για το οποίο υπάρχουν τα cgroups.
Πάρτε μια απλή εφαρμογή PHP στο container A. Βλέπει το δικό του σύστημα αρχείων, τη δική του διεπαφή δικτύου, το δικό του PID 1. Το container B έχει το ίδιο, αλλά με διαφορετική άποψη. Αυτά είναι τα namespaces. Τώρα απομακρυνθείτε και παραλείψτε το όριο μνήμης: το container A μπορεί να γεμίσει τη RAM του host και να κάνει το container B να σέρνεται. Αυτό ακριβώς υπάρχουν για να αποτρέπουν τα cgroups. Αλλά δύο containers μπορούν να είναι απομονωμένα μεταξύ τους μέσω namespaces και να μοιράζονται τον πυρήνα του host, που είναι το μέρος που αφορά κάθε ιστορία απόδρασης από container. Μια εκμετάλλευση που φτάνει στον πυρήνα μπορεί δυνητικά να φτάσει σε κάθε μισθωτή σε αυτόν τον host.
Η φράση «το Docker είναι απομονωμένο» είναι μισή αλήθεια. Η ακριβής εκδοχή είναι «το Docker απομονώνει με namespaces και cgroups, και μια ευπάθεια του πυρήνα είναι η ακτίνα έκρηξης». Πριν εμπιστευτείτε έναν μισθωτή να τρέξει μη αξιόπιστο κώδικα, καθίστε με αυτή τη σκέψη για ένα λεπτό. Η απάντηση δεν είναι «ποτέ μην χρησιμοποιείτε containers»—αυτός είναι ο εύκολος πανικός. Η απάντηση είναι ένα σύστημα επιπέδων.
Λοιπόν, γιατί μερικοί πελάτες χρειάζονται κάτι περισσότερο από namespaces;
Η ειλικρινής απάντηση είναι ότι η απομόνωση δεν είναι διακόπτης, είναι φάσμα. Στο ένα άκρο έχετε ένα πλήρως κοινόχρηστο container όπου όλοι είναι ουσιαστικά σε μία εφαρμογή. Στο άλλο άκρο έχετε μια ξεχωριστή εικονική μηχανή ανά μισθωτή με τον δικό της πυρήνα. Οι περισσότερες εργασίες των οργανισμών βρίσκονται στο άβολο μέσο, και το μέσο δεν είναι δυαδική επιλογή μεταξύ «το Docker είναι εντάξει» και «τρέξτε μια εικονική μηχανή για όλους».
Αυτό που σπρώχνει έναν πελάτη προς τα δεξιά δεν είναι το μέγεθός τους. Είναι τέσσερις ερωτήσεις:
- Αποθηκεύουν ρυθμιζόμενα δεδομένα; Μητρώα υγείας, λεπτομέρειες καρτών πληρωμής, οτιδήποτε ένας ρυθμιστής θα χαρακτήριζε ευαίσθητο.
- Μια παραβίαση στον μισθωτή τους έχει ρεαλιστική διαδρομή προς άλλο μισθωτή; Αν μπορούν να τρέξουν αυθαίρετο κώδικα, ναι.
- Εμπιστεύεστε τον κώδικα και τους ανθρώπους που τον αναπτύσσουν; Ένας πελάτης που προσλαμβάνει τον φθηνότερο ελεύθερο επαγγελματία δεν είναι το ίδιο επίπεδο εμπιστοσύνης με έναν πελάτη του οποίου την ομάδα ανάπτυξης γνωρίζετε.
- Το συμβόλαιό τους λέει «αφιερωμένο», «απομονωμένο» ή «ιδιωτικό»; Αν λέει, έχετε ήδη υποσχεθεί ένα επίπεδο· το μόνο που απομένει είναι να επιλέξετε το σωστό.
Αν δεν μπορείτε να απαντήσετε ακόμη σε αυτές τις ερωτήσεις, βάλτε τον πελάτη σε ένα βασικό επίπεδο και καταγράψτε τις υποθέσεις. Αυτό δεν είναι έλεγχος ασφαλείας· είναι ένας έλεγχος λογικής που επαναλαμβάνετε σε κάθε νέα ένταξη.
Πώς αποφασίζω για κάθε πελάτη χωρίς να εκτελώ έλεγχο ασφαλείας κάθε φορά;
Φτιάξτε έναν μικρό πίνακα και δεσμευτείτε σε αυτόν. Δεν χρειάζεστε έναν πίνακα με σαράντα κελιά. Τέσσερα επίπεδα θα καλύψουν σχεδόν κάθε πελάτη που βλέπει ένας οργανισμός.
| Θέση πελάτη | Τι πραγματικά τους διαχωρίζει | Χρησιμοποιήστε όταν |
|---|---|---|
| Επίπεδο 1: Κοινή εφαρμογή/container | Μόνο λογική εφαρμογής | Εσωτερικά βοηθητικά προγράμματα, δεδομένα χαμηλού κινδύνου, έργα όπου όλοι είναι ρητά σε ένα σύστημα σύνδεσης |
| Επίπεδο 2: Ίδιος host, ξεχωριστά containers | Namespaces και cgroups | Οι περισσότερες ιστοσελίδες μάρκετινγκ, φόρμες επικοινωνίας, χωρίς ευαίσθητα δεδομένα |
| Επίπεδο 3: Περιορισμένο container | Επίπεδο 2 + χωρίς root, χωρίς δυνατότητες, seccomp, μόνο για ανάγνωση root, τμηματοποίηση δικτύου | Ηλεκτρονικό εμπόριο, PII, προσαρμοσμένος κώδικας που δεν εμπιστεύεστε πλήρως |
| Επίπεδο 4: Εικονική μηχανή ανά μισθωτή | Hypervisor και ξεχωριστός πυρήνας | Υγεία, χρηματοοικονομικά, έγγραφα συμμόρφωσης, μη αξιόπιστος κώδικας, ενοχλητικοί γείτονες |
Ορίστε πώς λειτουργεί πρακτικά. Ένας πελάτης φούρνος με φόρμα επικοινωνίας και σύνδεσμο Instagram πάει στο Επίπεδο 2: ένα container σε κοινόχρηστο host, προεπιλεγμένο δίκτυο Docker, όρια πόρων, δουλειά τελειωμένη. Ένα ηλεκτρονικό κατάστημα που αποθηκεύει ονόματα, διευθύνσεις και ανακατευθύνσεις πληρωμών πελατών πάει στο Επίπεδο 3: ίδιος κοινόχρηστος host, αλλά το container τρέχει ως χρήστης χωρίς root, δεν έχει πρόσθετες δυνατότητες πυρήνα, χρησιμοποιεί προφίλ seccomp και εκθέτει μόνο την πόρτα 443. Μια ιατρική πύλη εισόδου που αποθηκεύει προστατευμένες πληροφορίες υγείας πάει στο Επίπεδο 4: εικονική μηχανή ανά μισθωτή, επειδή το κόστος μιας παραβίασης δεν είναι «θα το καθαρίσουμε» αλλά «δεν μπορούμε να δείξουμε στον πελάτη ότι τον πήραμε στα σοβαρά».
Το όλο κόλπο είναι ότι δεν ξανασκέφτεστε την αρχιτεκτονική για κάθε πελάτη. Διαλέγετε μια σειρά από έναν πίνακα που έχετε ήδη συμφωνήσει. Έτσι, ένας οργανισμός με πέντε άτομα μπορεί να διαχειριστεί εκατό ιστοσελίδες χωρίς εκατό ξεχωριστές εμμονές για την ασφάλεια. Σημαίνει επίσης ότι ο επόμενος πελάτης δεν παίρνει μια απάντηση που εξαρτάται από το ποιο μέλος της ομάδας απάντησε στο τηλέφωνο. Για τη βαθύτερη αρχιτεκτονική συζήτηση πίσω από αυτές τις επιλογές, αυτός ο οδηγός για τον σχεδιασμό επιπέδων απομόνωσης πολλαπλών μισθωτών καλύπτει τους συμβιβασμούς με περισσότερη λεπτομέρεια.
Πώς μοιάζει πραγματικά ένα περιορισμένο container;
Ας σταματήσουμε να λέμε «περιορισμένο» και ας γίνουμε συγκεκριμένοι. Αυτό σημαίνει το Επίπεδο 3 για έναν τυπικό πελάτη WordPress ή PHP.
Πρώτον, αλλάξτε τον χρήστη. Οι περισσότερες επίσημες εικόνες εξακολουθούν να τρέχουν ως root από προεπιλογή· στο Dockerfile σας, δημιουργήστε έναν χρήστη χωρίς root και τρέξτε την εφαρμογή ως αυτόν τον χρήστη. Αυτό αφαιρεί αμέσως τον πιο συνηθισμένο τρόπο με τον οποίο μια παραβίαση container γίνεται παραβίαση του host. Δεύτερον, αφαιρέστε τα δικαιώματα (capabilities) που δεν χρειάζεστε. Εκτελέστε με --cap-drop ALL και προσθέστε πίσω μόνο ένα, συνήθως το NET_BIND_SERVICE, ώστε η εφαρμογή να ακούει στην πόρτα 80. Μόνο αυτό είναι μια μεγαλύτερη αλλαγή από ό,τι περιμένουν οι περισσότεροι. Τρίτον, κάντε το root σύστημα αρχείων μόνο για ανάγνωση με --read-only και προσαρτήστε τους εγγράψιμους καταλόγους (uploads, τον κατάλογο δεδομένων της βάσης) ως volumes ή tmpfs. Τέταρτον, εφαρμόστε ένα προφίλ seccomp και, αν το υποστηρίζει ο host σας, AppArmor ή SELinux. Τέλος, βάλτε το container σε ένα αποκλειστικό δίκτυο Docker και εκθέστε μόνο τις πόρτες που πρέπει πραγματικά να είναι προσβάσιμες.
Ας δούμε ένα παράδειγμα με WordPress. Η βασική εικόνα πιθανόν τρέχει ως root, οπότε προσθέτετε ένα βήμα useradd και μια οδηγία USER. Εκτελείτε το container με όριο μνήμης και όριο CPU, ώστε μια έξαρση κίνησης από πρόσθετα να μην βλάψει τον γείτονα. Προσαρτάτε το /var/www/html/wp-content/uploads ως εγγράψιμο volume. Ορίζετε --read-only. Το συνδέετε σε ένα δίκτυο που δεν έχει καμία σημαία --privileged κοντά. Το αποτέλεσμα είναι ένα container που κάποτε ήταν «μια ιστοσελίδα WordPress» και τώρα είναι «μια ιστοσελίδα WordPress που είναι περισσότερο περιορισμένη από τους περισσότερους εικονικούς ιδιωτικούς διακομιστές».
Αν το να τα φτιάχνετε όλα με το χέρι φαίνεται εύθραυστο, υπάρχει μια πιο εύκολη ενδιάμεση λύση: η Enhanced Container Isolation του Docker, η οποία χρησιμοποιεί απομόνωση user namespace και ασφαλές χρόνο εκτέλεσης container. Είναι νόμιμη συντόμευση, αλλά δεν είναι δωρεάν πάσο για να παραλείψετε το non-root ή την αφαίρεση δικαιωμάτων. Ο μισθωτής εξακολουθεί να χρειάζεται μια λογική εικόνα. Η διαφορά είναι ότι η επιφάνεια επίθεσης προς τον πυρήνα μικραίνει χωρίς να γίνετε ειδικός σε seccomp εν μία νυκτί. Αν θέλετε την ακριβή ακολουθία για έναν μόνο μισθωτή, ο οδηγός σταδιακής σκλήρυνσης απομόνωσης μετατρέπει αυτή την ενότητα σε εντολές αντιγραφής-επικόλλησης.
Πότε σταματάω να προσθέτω επίπεδα και απλώς τους δίνω μια εικονική μηχανή;
Ορίστε το αντίθετο μέρος: η περισσότερη απομόνωση δεν είναι αυτόματα καλύτερη. Οι εικονικές μηχανές προσφέρουν απομόνωση σε επίπεδο υλικού, ξεχωριστό πυρήνα και πολύ μικρότερη επιφάνεια επίθεσης αν πέσει ο πυρήνας του επισκέπτη. Αυτό ακριβώς περιμένουν οι πελάτες υγείας και χρηματοοικονομικών όταν λένε «θέλουμε να είμαστε απομονωμένοι». Αλλά κάθε εικονική μηχανή προσθέτει κόστος ενημερώσεων, αντιγράφων ασφαλείας και υπολογιστικής ισχύος, και πολλαπλασιάζει τη δουλειά διατήρησης ενός στόλου ενημερωμένου. Αν βάζετε εικονική μηχανή σε κάθε πελάτη επειδή κάποτε ένας πελάτης σας είπε ότι το Docker τον φόβιζε, έχετε αγοράσει θέατρο ασφαλείας με πραγματικά χρήματα.
Μια εικονική μηχανή είναι η σωστή απάντηση όταν ο κίνδυνος ανά μισθωτή είναι υψηλότερος από το λειτουργικό κόστος μιας εικονικής μηχανής ανά μισθωτή. Αυτό σημαίνει ρυθμιζόμενα δεδομένα, γραπτές απαιτήσεις συμμόρφωσης, μη αξιόπιστο κώδικα τρίτων ή πελάτη που χρειάζεται να αφαιρεθεί ένας ενοχλητικός γείτονας. Είναι επίσης η σωστή απάντηση όταν το συμβόλαιο του πελάτη υπόσχεται κυριολεκτικά ένα αποκλειστικό περιβάλλον, επειδή «container» δεν είναι αυτό που φαντάζεται όταν υπογράφει για «αποκλειστικό».
Αλλά μια εικονική μηχανή δεν δικαιολογεί ένα πρόχειρο container. Μια κοινή παγίδα είναι να βάλετε τον πελάτη σε μια εικονική μηχανή και να παραλείψετε τη σκλήρυνση επειδή «η εικονική μηχανή τους προστατεύει». Η εικονική μηχανή προστατεύει τον host από τον μισθωτή, όχι τον μισθωτή από τη δική του κακή εικόνα. Εξακολουθείτε να θέλετε non-root, αφαίρεση δικαιωμάτων και seccomp μέσα σε αυτή την εικονική μηχανή. Η υβριδική προσέγγιση—containers μέσα σε μια εικονική μηχανή—είναι συχνά το βέλτιστο σημείο: η εικονική μηχανή παρέχει το όριο για τις συζητήσεις συμμόρφωσης, και το container σας δίνει τη ροή εργασίας ανάπτυξης που ήδη γνωρίζετε. Υπάρχει μια μεγαλύτερη εκδοχή αυτής της συζήτησης στο Πρέπει κάθε μισθωτής να έχει τη δική του εικονική μηχανή;, αλλά η σύντομη απάντηση είναι ότι η εικονική μηχανή είναι για το συμβόλαιο, όχι για τον φόβο.
Πώς το κάνω αυτό επαναλήψιμο σε κάθε πελάτη;
Το κάνετε επαναλήψιμο κάνοντας το σύστημα επιπέδων ένα πρότυπο, όχι μια ανάμνηση. Κρατήστε έναν κατάλογο με αρχεία Compose, ένα ανά επίπεδο: tier2-baseline, tier3-locked, tier4-vm-hybrid. Όταν εμφανίζεται ένας νέος πελάτης, αντιγράψτε το πρότυπο, αλλάξτε τις μεταβλητές περιβάλλοντος και ήδη γνωρίζετε το σχήμα απομόνωσης πριν γράψετε μια γραμμή νέας υποδομής.
Στη συνέχεια, καταγράψτε την απόφαση. Όχι μια έκθεση ασφαλείας 400 σελίδων, αλλά μια σύντομη παράγραφο στο αποθετήριο του πελάτη: τι δεδομένα αποθηκεύει, σε ποιο επίπεδο βρίσκεται, γιατί, και τι θα τον μετακινούσε σε υψηλότερο επίπεδο. Αυτή η παράγραφος αξίζει περισσότερο από εκατό κανόνες τείχους προστασίας, επειδή είναι το πράγμα που μπορείτε να δείξετε στον επόμενο ελεγκτή ή στον επόμενο ανήσυχο πελάτη. Σας εμποδίζει επίσης να χρειαστεί να θυμάστε γιατί ο φούρνος πήρε το Επίπεδο 2 και το ηλεκτρονικό κατάστημα το Επίπεδο 3 αφού έχει ξεθωριάσει η αρχική εμπορική κλήση.
Αυτοματοποιήστε τους βαρετούς ελέγχους. Βάλτε το CI σας να σαρώνει κάθε εικόνα πελάτη και να αποτυγχάνει η δημιουργία αν εκτελείται ως root, αν έχει όλα τα δικαιώματα ή αν προσπαθεί να δημοσιεύσει μια πόρτα διαφορετική από αυτές που επιτρέπει το επίπεδο. Τίποτα από αυτά δεν είναι εξωτικό· είναι απλώς για να βεβαιωθείτε ότι το πρότυπο δεν σπάει κατά λάθος από έναν καλοπροαίρετο προγραμματιστή. Αν χτίζετε ούτως ή άλλως τη γύρω ροή εργασίας φιλοξενίας, το άρθρο για στρατηγικές φιλοξενίας Docker έτοιμες για παραγωγή καλύπτει το μέρος που έρχεται μετά τον ορισμό των containers.
Τίποτα από αυτά δεν είναι λαμπερό. Κανένα άρθρο ιστολογίου δεν πρόκειται να κάνει την «απομόνωση μισθωτών» να ακούγεται τόσο συναρπαστική όσο ένα διάγραμμα αρχιτεκτονικής σε νέο έδαφος. Αλλά αυτή είναι η διαφορά μεταξύ ενός οργανισμού που απαντά «πόσο απομονωμένοι είμαστε;» με σταυρωμένα δάχτυλα «εντελώς» και ενός που μπορεί να δείξει ένα επίπεδο, μια διαμόρφωση και μια αιτία. Τα containers δεν είναι μαγικός τοίχος. Οι εικονικές μηχανές δεν είναι μαγική σφαίρα. Ένα σύστημα επιπέδων είναι απλώς μια απόφαση που καταγράφετε και επαναχρησιμοποιείτε—και για έναν οργανισμό, το επαναλήψιμο είναι το όλο παιχνίδι.

