VPN-ის დაკავშირების შემდგომი მოქმედება შეასრულე როგორც მომხმარებელმა, და არა როგორც დემონმა
USER=alice მქონე გარემოს ცვლადი არ ცვლის, რომელი ანგარიშით მუშაობს hook. გაყავი მოვლენა, ტრიგერი და მოქმედება, შემდეგ დაამტკიცე UID.
VPN დემონის დაკავშირების hook-ები დემონის სახელით მუშაობს და ეს ჩვეულებრივ ნიშნავს, რომ root-ის უფლებებით მუშაობს. იმ წუთს, როცა ერთი ასეთი hook ვიღაცის სახლის კატალოგში წერს ან სამუშაო მაგიდის დამხმარეს გადატვირთავს, თქვენ ქსელურ მოვლენას მისცეთ ნებისმიერი ლოკალური მომხმარებლის სახელით მოქმედების შესაძლებლობა. ჩვეულებრივი მოკლე გზა, გარემოს ცვლადიდან მომხმარებლის სახელის წაკითხვა და მისი გადაცემა, ამას არ ასწორებს. ის მხოლოდ ხელახლა აჭდობს მოქმედებას და არ ცვლის, რომელი ანგარიში ასრულებს მას. რაც მუშაობს, არის სამნაწილიანი გადაცემა, სადაც პრივილეგირებული ნაბიჯი ამბობს, რა მოხდა, და ცალკე ერთეული ასრულებს მოქმედებას სწორი იდენტობით.
მომხმარებლის სახელი გარემოში იდენტობის გადამრთველი არ არის
Unix წყვეტს, რას შეიძლება შეეხოს პროცესი, მისი ეფექტური მომხმარებლის ID-ით და არა გარემოში არსებული სტრიქონებით. USER=alice-ის დაყენება ან LOGNAME-ის ექსპორტი ცვლის, რას ბეჭდავს უყურადღებო პროგრამა თავის გამოსავალში; ფაილების საკუთრების შემოწმებაში არაფერს ცვლის. root-ით მომუშავე hook ამ ცვლადით მაინც root-ით ხსნის Alice-ის ფაილებს.
სახელებიც ერთი და იგივე სახელი არ არის. დისტანციური წვდომის შესვლა, ლოკალური 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-ის პრობლემას ჰგავს და არ არის.
დემონი რჩება იქ, სადაც არის
VPN სერვისის საკუთარი User=-ის 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 მოქმედების ერთეულისთვის და არა კლიენტის კიდევ ერთი ხელახალი დაკავშირება.
რასაც დაკავშირების მოვლენა ჯერ კიდევ არ ამტკიცებს
დამყარებული გვირაბი ერთი ფაქტია. ეს არ ნიშნავს, რომ სამუშაო მაგიდის სესია გახსნილია, სესიის ავტობუსი მისადგომია ან მოქმედების სასურველი კერძო რესურსი უკვე ხელმისაწვდომია. Alice-ის UID-ის ქვეშ მყოფ oneshot ერთეულს აქვს მისი იდენტობა და არაფერი მისი სესიიდან, ამიტომ ყველაფერმა, რაც გრაფიკულ ავტობუსს მოითხოვს, მხარდაჭერილ მომხმარებლის სესიის მექანიზმში უნდა გაიაროს და განსაზღვროს, რა ხდება, როცა ის გასულია.
ხელახალი დაკავშირებებიც მეორდება. მატარებელში მძინარე ლეპტოპს შეუძლია საათში ათეული დაკავშირების მოვლენა წარმოქმნას, და hook, რომელიც ყოველ ჯერზე სტრიქონს ამატებს, მდგომარეობის ფაილს აქცევს ჟურნალად, რომელსაც ვერავინ წაიკითხავს. მოქმედება იდემპოტენტური გახადე, ან მისცე უფლება სესიით გასაღებული ერთი ჩანაწერი შეცვალოს.
ბოლოს, შეზღუდე ზიანის რადიუსი თავად ერთეულში: მხოლოდ-წაკითხვადი ფაილური სისტემის ხედი მდგომარეობის კატალოგის გარეთ, ახალი პრივილეგიების გარეშე და ცხადი ვადით. დემონისა და მომხმარებლის მოქმედების გაყოფა თავისთავად ღირებულია, მაგრამ გაცილებით უფრო ღირებულია, როცა მოქმედებას სხვა ვერაფერი შეუძლია გარდა იმ ერთისა, რაც დაამტკიცე.