Εκτελέστε μια ενέργεια μετά τη σύνδεση VPN ως χρήστης, όχι ως δαίμονας
Μια μεταβλητή περιβάλλοντος με USER=alice δεν αλλάζει με ποιον λογαριασμό εκτελείται ένα hook. Διαχωρίστε το συμβάν, το έναυσμα και την ενέργεια και μετά αποδείξτε το UID.
Τα hooks σύνδεσης ενός δαίμονα VPN εκτελούνται ως ο δαίμονας, και συνήθως αυτό σημαίνει ότι εκτελούνται ως root. Τη στιγμή που ένα από αυτά τα hooks γράφει στον προσωπικό κατάλογο κάποιου ή επανεκκινεί έναν βοηθό επιφάνειας εργασίας, έχετε δώσει σε ένα συμβάν δικτύου τη δυνατότητα να δρα ως αυθαίρετος τοπικός χρήστης. Η συνήθης συντόμευση, να διαβάζετε ένα όνομα χρήστη από μια μεταβλητή περιβάλλοντος και να το προωθείτε, δεν το διορθώνει. Επαναχαρακτηρίζει την ενέργεια χωρίς να αλλάζει ποιος λογαριασμός την εκτελεί. Αυτό που λειτουργεί είναι μια παράδοση τριών μερών, όπου το προνομιακό βήμα λέει τι συνέβη και μια ξεχωριστή μονάδα εκτελεί τη δράση υπό τη σωστή ταυτότητα.
Ένα όνομα χρήστη στο περιβάλλον δεν είναι διακόπτης ταυτότητας
Το Unix αποφασίζει τι μπορεί να αγγίξει μια διεργασία από το ενεργό αναγνωριστικό χρήστη της, όχι από τα αλφαριθμητικά στο περιβάλλον της. Η ρύθμιση USER=alice ή η εξαγωγή LOGNAME αλλάζει τι τυπώνει ένα απρόσεκτο λογισμικό στην έξοδό του· δεν αλλάζει τίποτα στους ελέγχους ιδιοκτησίας αρχείων. Ένα hook που εκτελείται ως root με αυτή τη μεταβλητή ορισμένη ανοίγει ακόμη τα αρχεία της Alice ως root.
Ούτε τα ονόματα είναι το ίδιο όνομα. Η σύνδεση απομακρυσμένης πρόσβασης, ο τοπικός λογαριασμός Unix και το κοινό όνομα του πιστοποιητικού είναι τρία αναγνωριστικά που συχνά συμπίπτουν και περιστασιακά όχι. Ένας χρήστης που πιστοποιείται ως a.smith μπορεί να μην έχει καθόλου τοπικό λογαριασμό ή να αντιστοιχίζεται σε asmith μέσω υπηρεσίας καταλόγου. Οποιοσδήποτε σχεδιασμός υποθέτει ότι ένα αλφαριθμητικό εξυπηρετεί και τους τρεις ρόλους θα σπάσει στον πρώτο εργολάβο.
Άρα το πρώτο ερώτημα δεν είναι «ποιος χρήστης είναι συνδεδεμένος» αλλά «ποιος τοπικός λογαριασμός επιτρέπεται να εκτελέσει αυτή την ενέργεια». Απαντήστε το από τη δική σας βάση λογαριασμών, όχι από ό,τι έστειλε ο πελάτης:
id -u alice
getent passwd alice | cut -d: -f1,3,6
stat -c '%U:%G %a %n' /home/alice/.local/state/vpn-status.json
Η τρίτη εντολή είναι αυτή που οι άνθρωποι παραλείπουν. Αν το αρχείο-στόχος ανήκει στο root επειδή το δημιούργησε το προηγούμενο hook, μια σωστά ρυθμισμένη ενέργεια χρήστη θα αποτύχει με σφάλμα άδειας που μοιάζει με πρόβλημα του systemd και δεν είναι.
Ο δαίμονας μένει εκεί που είναι
Το να αλλάξετε το δικό του User= της υπηρεσίας VPN σε Alice είναι ο λάθος μοχλός. Αλλάζει πώς ο δαίμονας δεσμεύει διεπαφές, διαβάζει κλειδιά, γράφει το αρχείο κατάστασής του και διαχειρίζεται διαδρομές, και μεταφέρει όλο αυτόν τον κίνδυνο σε μια μονάδα που δούλευε. Ο δαίμονας χρειάζεται τα προνόμιά του· η επόμενη ενέργεια όχι.
Δείτε τι κάνει πραγματικά η μονάδα πριν την αγγίξετε. Δύο εντολές σας λένε την ταυτότητα εκτέλεσης και τις ακριβείς γραμμές εντολών σε ισχύ, μαζί με ό,τι πρόσθεσε ένα αρχείο παράκαμψης:
systemctl show -p User -p Group -p ExecStart openvpn-server@server
systemctl cat openvpn-server@server
Σε μια προεπιλεγμένη εγκατάσταση πακέτου ο δαίμονας είναι root και το σενάριο --up το κληρονομεί. Επιβεβαιώστε το αντί να το υποθέσετε, γιατί μια σκληρυμένη διανομή μπορεί να το έχει μετακινήσει σε ειδικό λογαριασμό, και ένα χειρόγραφο drop-in μπορεί να εκτελεί το hook μέσω περιτυλίγματος με διαφορετικούς κανόνες.
Τρία ονομασμένα μέρη, ένα στενό έναυσμα
Η διάταξη που επιβιώνει στη συντήρηση έχει ένα συμβάν, ένα έναυσμα και μια ενέργεια. Ο δαίμονας αναφέρει ότι ανέβηκε μια ονομασμένη συνεδρία. Ένα έναυσμα δέχεται αυτό το μικρό γεγονός και ζητά μια σταθερή ενέργεια. Η ενέργεια εκτελείται υπό τον τοπικό λογαριασμό που κατέχει τα αρχεία που αγγίζει. Τίποτα στην αλυσίδα δεν δέχεται αυθαίρετη διαδρομή εντολής.
Η ίδια η ενέργεια είναι μια συνηθισμένη μονάδα υπηρεσίας, και η ταυτότητα είναι μία οδηγία μέσα της:
[Service]
Type=oneshot
User=alice
Group=alice
ExecStart=/usr/local/bin/refresh-vpn-status --slot %i
Σημειώστε ότι το User=alice ισχύει για ολόκληρη τη μονάδα, και το systemd τεκμηριώνει μία εξαίρεση που αξίζει να ξέρετε: μια εντολή με πρόθεμα + εκτελείται με πλήρη προνόμια ανεξάρτητα. Αυτό το πρόθεμα είναι νόμιμο εργαλείο για ένα μόνο προνομιακό βήμα και βολικός τρόπος να ακυρώσετε τον διαχωρισμό που μόλις φτιάξατε, οπότε θεωρήστε οποιοδήποτε + σε αυτή τη μονάδα ως κάτι που πρέπει να δικαιολογηθεί στην ανασκόπηση.
Κρατήστε την είσοδο του εναύσματος ελάχιστη και μη μυστική. Το αναγνωριστικό συνεδρίας, ο αντιστοιχισμένος λογαριασμός και μια χρονική σφραγίδα είναι συνήθως όλα όσα χρειάζονται. Μη μεταφέρετε ποτέ θραύσμα shell, διαδρομή εκτελέσιμου ή μπλοκ περιβάλλοντος από τον πελάτη πέρα από το όριο, γιατί η πλευρά που λαμβάνει δεν έχει τρόπο να ξεχωρίσει μια νόμιμη τιμή από μια έγχυτη.
Επαληθεύστε την ταυτότητα που εκτελέστηκε πραγματικά
Η ανασκόπηση διαμόρφωσης δεν είναι απόδειξη. Μετά από εγκεκριμένη δοκιμαστική σύνδεση, επιβεβαιώστε το UID που άγγιξε το αρχείο και το UID που ο δαίμονας εξακολουθεί να χρησιμοποιεί:
stat -c '%U %G %y %n' /home/alice/.local/state/vpn-status.json
ps -o user=,pid=,cmd= -p "$(pgrep -o -f 'openvpn --daemon')"
systemd-run --uid=alice --pipe /usr/local/bin/refresh-vpn-status --dry-run
Η πρώτη γραμμή πρέπει να δείχνει την Alice και μια χρονική σφραγίδα μέσα στο παράθυρο δοκιμής σας. Η δεύτερη πρέπει να δείχνει ακόμη root ή τον λογαριασμό υπηρεσίας του πακέτου, που αποδεικνύει ότι ο δαίμονας δεν μετακινήθηκε. Η τρίτη είναι ο φθηνότερος τρόπος να δοκιμάσετε τα δικαιώματα της ενέργειας χωρίς να περιμένετε πραγματική επανασύνδεση.
Αν ο ιδιοκτήτης του αρχείου είναι η Alice αλλά η ομάδα ή η λειτουργία του άλλαξε μεταξύ εκτελέσεων, ψάξτε για UMask= ή διαφορά δικαιωμάτων καταλόγου αντί για λογικό σφάλμα. Αν η χρονική σφραγίδα δεν κουνήθηκε καθόλου, το έναυσμα δεν ενεργοποιήθηκε ποτέ, και το χρήσιμο επόμενο βήμα είναι journalctl -u για τη μονάδα ενέργειας αντί για άλλη επανασύνδεση πελάτη.
Τι δεν αποδεικνύει ακόμη ένα συμβάν σύνδεσης
Μια εδραιωμένη σήραγγα είναι ένα γεγονός. Δεν σημαίνει ότι η συνεδρία επιφάνειας εργασίας είναι ξεκλείδωτη, ότι ο δίαυλος συνεδρίας είναι προσβάσιμος ή ότι ο ιδιωτικός πόρος που θέλει η ενέργεια είναι ήδη διαθέσιμος. Μια μονάδα oneshot υπό το UID της Alice έχει την ταυτότητά της και τίποτα από τη συνεδρία της, άρα ό,τι απαιτεί γραφικό δίαυλο πρέπει να περάσει από τον υποστηριζόμενο μηχανισμό συνεδρίας χρήστη και να ορίσει τι συμβαίνει όταν αυτή αποσυνδεθεί.
Οι επανασυνδέσεις επαναλαμβάνονται επίσης. Ένας φορητός που κοιμάται σε ένα τρένο μπορεί να παράγει δώδεκα συμβάντα σύνδεσης σε μια ώρα, και ένα hook που προσθέτει μια γραμμή κάθε φορά μετατρέπει ένα αρχείο κατάστασης σε αρχείο καταγραφής που κανείς δεν μπορεί να διαβάσει. Κάντε την ενέργεια αδρανή ως προς επαναλήψεις, ή αφήστε την να αντικαθιστά μία εγγραφή με κλειδί τη συνεδρία.
Τέλος, περιορίστε την ακτίνα ζημιάς στην ίδια τη μονάδα: μια προβολή συστήματος αρχείων μόνο για ανάγνωση πέρα από τον κατάλογο κατάστασης, χωρίς νέα προνόμια, και με ρητό χρονικό όριο. Ο διαχωρισμός δαίμονα και ενέργειας χρήστη αξίζει από μόνος του, αλλά αξίζει πολύ περισσότερο όταν η ενέργεια δεν μπορεί να κάνει τίποτα εκτός από το ένα πράγμα που εγκρίνατε.