Ինչպես պարզել, թե որ systemd սենդբոքսն է մերժել ձեր OpenVPN կեռիկը
Կեռիկը աշխատում է root-ի իրավունքներով և ձախողվում է systemd-ի տակ, քանի որ unit-ը պահում է ավելի քիչ հնարավորություններ, ավելի փոքր /dev և միայն-ընթեռնելի ուղիներ։
Կեռիկը աշխատում է, երբ այն ձեռքով գործարկում եք որպես root, և վերադարձնում է Operation not permitted այն պահին, երբ ծառայությունը սկսում է այն։ Ֆայլն այդ գործարկումների միջև չի փոխվել. փոխվել է միջավայրը։ systemd-ը գործընթացին տալիս է ավելի փոքր աշխարհ՝ ավելի քիչ հնարավորություններ, այլ /dev, միայն-ընթեռնելի ֆայլային համակարգի ուղիներ և առաջադրանքների սահմանաչափ։ Կարդացեք ձախողումը որպես սահման, որը մերժել է մեկ կոնկրետ գործողություն, ոչ որպես կոտրված սկրիպտ։
Սկսեք այն գործողությունից, որը մերժվել է
Գրանցամատյանի տողը, որն ասում է, թե unit-ը ձախողվել է, գրեթե ոչինչ չի ասում։ Օգտակար տողը նշում է այն կանչը, որը մերժվել է՝ սարքի հանգույց, որը չի բացվել, թղթապանակ, որում չի գրվել, անվանատարածք, որը չի ստեղծվել։ Գտեք այդ կանչը նախքան որևէ հրահանգի դիպչելը, որովհետև յուրաքանչյուրը համապատասխանում է տարբեր սահմանափակման։ Այնուհետև կարդացեք այն unit-ը, որն իրականում աշխատել է, ներառյալ drop-in-ները, փոխանակ փաթեթի ուղարկած ֆայլի։
Ստորև հարցումը տպում է հատվածի ուղին, drop-in թղթապանակները և այն հատկանիշները, որոնք կարևոր են սարքի կամ ֆայլային համակարգի մերժման համար։ Կարդացեք բոլորը նախքան որոշելը, թե որ սահմանն է համապատասխան։
systemctl show "[email protected]" -p FragmentPath -p DropInPaths -p PrivateDevices -p DevicePolicy -p DeviceAllow -p ProtectHome -p ProtectSystem -p TasksMax
journalctl -u "[email protected]" -b --no-pager | grep -iE 'operation not permitted|permission denied|cannot open|failed'Այդ բլոկում ոչինչ չի գրում։ Եթե մերժված կանչը բացակայում է մատյանում, մեկ գործարկման համար բարձրացրեք հաճախորդի մանրամասնությունը՝ հրահանգներ գուշակելու փոխարեն։ Աշխատող գործընթացը ապացուցում է, որ unit-ը սկսվել է, ոչ թե որ կեռիկն աշխատել է անհրաժեշտ արտոնություններով։
Անվանատարածքը պահանջում է mount իրավունքներ, որոնք TUN սարքը երբեք չի օգտագործում
Մեկ կեռիկի ներսում նման երևացող երկու գործողություններ ունեն տարբեր թույլտվությունների պրոֆիլներ։ /dev/net/tun բացելը և միջերեսը ստեղծելը պահանջում է ցանցային կառավարում և հասանելիություն այդ հանգույցին։ Անվանված ցանցային անվանատարածք ստեղծելը նույնպես պահանջում է mount աշխատանք, որովհետև անվանատարածքի գործիքը mount է անում նոր /sys տեսք և կապում է վիճակի թղթապանակը իր տեղում։ վերին մակարդակի հաճախորդի unit-ը դիտավորյալ թողնում է mount կառավարումը իր սահմանների հավաքածուից դուրս, ուստի անվանատարածքի քայլը մերժվում է, մինչդեռ թունելն ինքը կաշխատեր։
Այդ պատճառով սարքի հանգույցը տալը չի փրկում սկրիպտը։ Սարքի թույլտվությունը պատասխանում է մեկ հարցի՝ կարո՞ղ է այս գործընթացը բացել այս հանգույցը, իսկ անվանատարածքի հարցը այլ է։ Համապատասխանեցրեք ձախողվող կանչը իր հնարավորությանը նախքան որևէ բան լայնացնելը։
Ձեր shell-ում արված փորձարկումը ժառանգում է բոլոր հնարավորությունները, որ ունի անսահմանափակ root-ը, իսկ unit-ը ժառանգում է այն, ինչ պահել է իր սահմանների հավաքածուն։ Այդ երկու գործարկումները տարբեր փորձեր են նույնիսկ երբ երկուականը նույնն է։
Սարքեր, պաշտպանված ուղիներ և առաջադրանքների սահմանաչափեր
Երբ մերժված գործողությունը հայտնի է, հրահանգների երեք խումբ բացատրում են ձախողումների մեծ մասը։ Սարքերի հասանելիությունը կարգավորում է PrivateDevices, որը փոխարինում է /dev -ը նվազագույն կեղծ սարքերի հավաքածուով, և DevicePolicy -ի հետ DeviceAllow, որոնք որոշում են, թե cgroup-ը ինչ է թույլատրում։ /dev/net/tun այդ նվազագույն հավաքածուի մասը չէ, ուստի PrivateDevices=yes ունեցող unit-ը չի կարող բացել այն, ինչ էլ ասի սարքերի քաղաքականությունը։
Ֆայլային համակարգի պաշտպանությունը պատասխանում է երկրորդ հարցին։ ProtectHome=yes դարձնում է /home, /root և /run/user անհասանելի, և ProtectSystem=full դարձնում է /usr, /boot և /etc միայն-ընթեռնելի։ Այդ պատճառով այն կեռիկը, որը գրում է իր իսկ կարգավորումների ֆայլի կողքին, աշխատում է ձեր shell-ում և ձախողվում unit-ի տակ, նույն թույլտվության ձևով, ինչ բացակայող հնարավորությունը։ Տեղափոխեք գրելի մուտքը քաղաքականության թույլատրած ուղի, կամ ավելացրեք նեղ ReadWritePaths= գրառում։
Ռեսուրսների սահմանափակումները երրորդ խումբն են և ամենաքիչ ակնհայտը։ TasksMax= սահմանափակում է, թե քանի առաջադրանք կարող է ստեղծել unit-ը, իսկ ֆայլային նկարագրիչների սահմանաչափը նույն ձևով է վարվում socket-ների և բռնակների համար։ Տեղադրումը, որն անցել է սահմանաչափից, ձախողվում է ռեսուրսի սխալով, ոչ թե թույլտվության սխալով, և այդ պատճառով ճշգրիտ հաղորդագրությունը դեռ կարևոր է։
Հանեք անվանատարածքի քայլը կեռիկից
Նախապատրաստությունը, որը պահանջում է արտոնություն, որը հաճախորդը չպետք է ունենա, պատկանում է իր սեփական unit-ին։ oneshot-ը, որն աշխատում է հաճախորդից առաջ, պահում է իր արդյունքը և դասավորված է կապից առաջ, տալիս է անվանատարածքի քայլին անհրաժեշտը՝ առանց այդ իրավունքները թունելի գործընթացին հանձնելու։ Այնուհետև հաճախորդը հղում է այդ unit-ին՝ սկրիպտը իր up կեռիկից կանչելու փոխարեն։
Ստորև ձևանմուշը մեկնարկային ձև է, ոչ թե մի բան, որ կիրառվում է չկարդացած։ Այն պահում է նախապատրաստությունը այնտեղ, որտեղ ապրում է արտոնությունը, և թողնում է թունելի unit-ը անձեռնմխելի։
# /etc/systemd/system/[email protected]
[Unit]
Description=Namespace preparation for %i
Before=openvpn-client@%i.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/netns-up.sh %i
CapabilityBoundingSet=CAP_NET_ADMIN CAP_SYS_ADMIN
[Install]
WantedBy=multi-user.targetԱվելացրեք հերթականությունը drop-in-ով՝ փաթեթավորված unit-ը խմբագրելու փոխարեն, որպեսզի թարմացումը չկարողանա լուռ գցել ձեր փոփոխությունը։ Թղթապանակը կապված է օրինակի անվան հետ, ուստի երկրորդ պրոֆիլին պետք է իր ֆայլը։
sudo mkdir -p /etc/systemd/system/[email protected]
sudo tee /etc/systemd/system/[email protected]/10-namespace.conf >/dev/null <<'CONF'
[Unit]
[email protected]
[email protected]
CONF
sudo systemctl daemon-reloadԿրկնեք նույն կանչը փոփոխությունից հետո
Վերանորոգումը հաստատվում է միայն այն ժամանակ, երբ նույն կանչը տալիս է այլ արդյունք։ Վերագործարկեք երկու unit-երը, կատարեք այն գործողությունը, որը ձախողվել է, և համեմատեք դրա արդյունքը փոփոխությունից առաջ պահված մատյանի տողի հետ։ unit-ը, որը սկսվում է, մինչ կեռիկն այլևս երբեք չի աշխատում, վերանորոգում չէ։
Ստորև հաջորդականությունը պահում է համեմատությունը ազնիվ, որովհետև ստուգում է մերժված կանչը, ոչ թե unit-ի գույնը։ Պահեք դրա ելքը փոփոխությունից առաջ որսված մատյանի տողի կողքին։
sudo systemctl restart "[email protected]" "[email protected]"
systemctl status "[email protected]" --no-pager
journalctl -u "[email protected]" -b --no-pager | grep -c 'Operation not permitted'
ip -brief addr show tun0Հաշվեք մերժումները՝ վերջին տողը կարդալու փոխարեն, որովհետև կեռիկը կարող է ձախողվել, նորից փորձել և հաջողել, և միայն հաշիվն է ցույց տալիս, թե արդյոք սահմանը շարժվել է։ Թողեք մեկնաբանություն drop-in-ում՝ նշելով այն հրահանգը, որը թուլացրել եք, և պատճառը, քանի որ հաջորդ թարմացումը համեմատում է ձեր կարգավորումը փաթեթավորված լռելյայնի հետ։ unit-ը, որը սկսվում է միայն այն բանից հետո, երբ անջատված է ամեն պաշտպանություն, ուղղված չէ։