Գործարկել VPN-ին միանալուց հետո գործողությունը որպես օգտվող, ոչ որպես դեմոն
USER=alice ասող միջավայրի փոփոխականը չի փոխում, թե որ հաշվով է աշխատում hook-ը։ Առանձնացրեք իրադարձությունը, գործարկիչը և գործողությունը, ապա ապացուցեք UID-ը։
VPN դեմոնի միացման hook-երը աշխատում են դեմոնի անունից, և դա սովորաբար նշանակում է, որ աշխատում են root-ի իրավունքներով։ Այն պահին, երբ այդ hook-երից մեկը գրում է ինչ-որ մեկի տնային պանակում կամ վերագործարկում է աշխատասեղանի օգնական, դուք ցանցային իրադարձությանը տվել եք ցանկացած տեղական օգտվողի անունից գործելու հնարավորություն։ Սովորական կարճ ուղին՝ միջավայրի փոփոխականից օգտվողի անուն կարդալ և փոխանցել այն, դա չի շտկում։ Այն միայն վերապիտակավորում է գործողությունը՝ չփոխելով, թե որ հաշիվն է այն կատարում։ Աշխատում է եռամաս փոխանցումը, որտեղ արտոնյալ քայլը ասում է, թե ինչ է տեղի ունեցել, և առանձին միավորը կատարում է գործողությունը ճիշտ ինքնությամբ։
Միջավայրում օգտվողի անունը ինքնության անջատիչ չէ
Unix-ը որոշում է, թե ինչի կարող է դիպչել պրոցեսը, իր արդյունավետ օգտվողի ID-ով, ոչ իր միջավայրի տողերով։ USER=alice սահմանելը կամ LOGNAME արտահանելը փոխում է, թե ինչ է տպում անփույթ ծրագրաշարը իր ելքում, և ոչինչ չի փոխում փաստաթղթերի սեփականության ստուգումներում։ root-ով աշխատող hook-ը այդ փոփոխականով դեռևս բացում է 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-ի խնդրի և այդպիսին չէ։
Դեմոնը մնում է իր տեղում
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-ը, որն ամեն անգամ տող է ավելացնում, կարգավիճակի փաստաթուղթը վերածում է մատյանի, որը ոչ ոք չի կարող կարդալ։ Գործողությունը դարձրեք իդեմպոտենտ, կամ թույլ տվեք, որ այն փոխարինի նստաշրջանով բանալավորված մեկ գրառում։
Վերջապես, սահմանափակեք վնասի շառավիղը հենց միավորում. միայն կարդալու ֆայլային համակարգի տեսք՝ կարգավիճակի պանակից դուրս, առանց նոր արտոնությունների և բացահայտ ժամկետով։ Դեմոնի և օգտվողի գործողության բաժանումն ինքնին արժեքավոր է, բայց շատ ավելի արժեքավոր է, երբ գործողությունը չի կարող անել ոչինչ, բացի ձեր հաստատած մեկ բանից։