V AlmaLinux, Rocky Linux in drugih sistemih na osnovi RHEL je SELinux (Security-Enhanced Linux) privzeto vklopljen. Poleg običajnih dovoljenj datotek (glej: Dovoljenja datotek (chmod, chown) v Linuxu) vsaki datoteki, procesu in vratom dodeli varnostno oznako (context) in dovoli le tisto, kar pravilnik izrecno dovoljuje. Če na primer kdo vdre v spletni strežnik, SELinux napadalcu prepreči, da bi v imenu spletnega strežnika dostopal do drugih delov sistema.
Cena za to je, da lahko nastavitve, ki odstopajo od običajnih (lasten spletni imenik, nestandardna vrata, odhodne povezave spletnega strežnika), vrnejo napako „Permission denied”, tudi če so nastavitve chmod in chown pravilne. Takrat mnogi SELinux izklopijo, čeprav je napako običajno mogoče odpraviti z enim ukazom.
Ubuntu in Debian ne uporabljata SELinuxa, temveč AppArmor; tam ta članek ne velja. Na strežnikih cPanel mora biti SELinux izklopljen, ker ga cPanel ne podpira.
Ali je vklopljen?
getenforce
sestatus
Enforcing: SELinux deluje in prepoveduje operacije, ki kršijo pravila.Permissive: kršitve pravil le beleži, a jih ne prepoveduje.Disabled: izklopljen.
Ali napako povzroča SELinux?
SELinux vsako prepoved zabeleži kot sporočilo AVC. Zadnje prepovedi:
sudo ausearch -m AVC -ts recent
Če se tu sočasno z napako pojavi vrstica denied, napako povzroča SELinux. Značilen vnos:
type=AVC msg=audit(...): avc: denied { read } for pid=1234 comm="httpd"
name="index.html" scontext=system_u:system_r:httpd_t:s0
tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file
Iz tega je razvidno, da spletni strežnik (httpd_t) ni smel brati datoteke index.html, ker je njena oznaka admin_home_t (nastala je v imeniku uporabnika root).
ausearch dnevnik bere sam le, če ga zaženeš iz terminala. Iz skripta ali opravila cron dodaj tudi stikalo --input-logs (sudo ausearch --input-logs -m AVC -ts recent), sicer bere standardni vhod in vrne odgovor <no matches>. -ts recent pomeni zadnjih 10 minut.
Za hiter preizkus lahko začasno preklopiš tudi v permisivni način; če napaka tako izgine, jo zagotovo povzroča SELinux:
sudo setenforce 0 # Permissive
# ... poskusi znova ...
sudo setenforce 1 # nazaj v način Enforcing
Program audit2why razloge za prepovedi razloži tudi v človeškem jeziku:
sudo ausearch -m AVC -ts recent | audit2why
Spodnji ukazi semanage, audit2why in audit2allow so v paketu policycoreutils-python-utils:
sudo dnf install policycoreutils-python-utils
1. Napačne oznake datotek
Najpogostejši primer: datoteko si ustvaril drugje (na primer v imeniku /root ali /home), nato pa jo z ukazom mv premaknil v spletni imenik. mv ohrani izvirno oznako, zato je spletni strežnik ne more brati. (cp kopiji da oznako ciljnega imenika.)
Ogled oznak:
ls -Z /var/www/html
Ponastavitev oznak na privzete:
sudo restorecon -Rv /var/www/html
Na testnem računalniku z AlmaLinux 10 je index.html, ustvarjen v imeniku /root in nato z ukazom mv premaknjen v spletni imenik, vrnil napako 403, v dnevniku je bila prepoved, po restorecon pa se je stran naložila s kodo 200:
Lasten spletni imenik
Če spletna stran ni pod /var/www (na primer /srv/www), SELinuxu povej, da je tudi to spletna vsebina, nato nastavi oznake:
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
sudo restorecon -Rv /srv/www
Za imenike, v katere mora spletna aplikacija tudi pisati (nalaganja, predpomnilnik), nastavi oznako za pisanje:
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/wp-content/uploads(/.*)?"
sudo restorecon -Rv /var/www/html/wp-content/uploads
Oznake je mogoče spremeniti tudi z ukazom chcon, vendar se tako nastavljena oznaka po naslednjem restorecon ali celotnem ponovnem označevanju izgubi; za trajno nastavitev je pravilna metoda semanage fcontext.
2. Stikala (booleans)
Veliko pogostih potreb SELinux dovoli s stikali. Stikala za spletni strežnik:
getsebool -a | grep httpd
Najpogosteje potrebna:
| Stikalo | Kdaj je potrebno? |
|---|---|
httpd_can_network_connect |
PHP odpre zunanjo povezavo (klici API, cURL) ali Nginx/Apache kot proxy posreduje aplikaciji (Node.js, Python) |
httpd_can_network_connect_db |
PHP se poveže s podatkovno bazo na drugem strežniku |
httpd_can_sendmail |
PHP pošilja pošto s funkcijo mail() |
httpd_unified |
spletni strežnik lahko piše tudi v vso spletno vsebino (udobno, a manj varno) |
Trajni vklop (brez -P se ob ponovnem zagonu ponastavi):
sudo setsebool -P httpd_can_network_connect on
V preizkusu je skript PHP s cURL poskušal doseči zunanjo stran HTTPS. Z izklopljenim stikalom (httpd_can_network_connect --> off, to je osnovna vrednost) je cURL vrnil napako 7 („Failed to connect to … port 443 … Could not connect to server”), po vklopu pa je bil odgovor 200. V WordPressu se to pokaže kot sporočilo „cURL error 7” (glej: cURL error 28 in 60 v WordPressu).
3. Nestandardna vrata
Če storitev ne poganjaš na njenih privzetih vratih, je treba to sporočiti tudi SELinuxu. Najpogostejši primer je sprememba vrat SSH (glej: Varnostne nastavitve strežnika SSH): če to izpustiš, se sshd po ponovnem zagonu ne zažene in se lahko zakleneš iz strežnika.
sudo semanage port -a -t ssh_port_t -p tcp 2255
Pri spletnem strežniku (na primer 8888 namesto 8080):
sudo semanage port -a -t http_port_t -p tcp 8888
Že dovoljena vrata: sudo semanage port -l | grep -E "ssh|http".
4. Lastno pravilo, če nič drugega ne pomaga
Če nobena od zgornjih ni rešitev, audit2allow iz zabeleženih prepovedi naredi lasten modul pravil:
sudo ausearch -m AVC -ts recent | audit2allow -M sajat_szabaly
sudo semodule -i sajat_szabaly.pp
Pred namestitvijo si oglej ustvarjeno datoteko sajat_szabaly.te in dovoli le tisto, kar res potrebuješ.
Ali je treba SELinux izklopiti?
Ne priporočamo. Če aplikacija z njim vseeno ne deluje, lahko namesto popolnega izklopa v permisivni način preklopiš le določeno storitev, na primer spletni strežnik:
sudo semanage permissive -a httpd_t
Če ga moraš vseeno izklopiti, od AlmaLinux 9 SELINUX=disabled, nastavljen v datoteki /etc/selinux/config, ne izklopi več popolnoma; namesto tega ga navedi kot parameter jedra, nato strežnik znova zaženi:
sudo grubby --update-kernel ALL --args selinux=0
Če ga pozneje znova vklopiš, je treba celoten datotečni sistem znova označiti (sudo touch /.autorelabel, nato ponovni zagon), kar lahko traja dlje časa.
