Johdanto: Miksi pelkkä DAC ei riitä?
Linux-järjestelmien tietoturva on perinteisesti nojannut harkinnanvaraiseen pääsynhallintaan (Discretionary Access Control, DAC). Käytännössä tämä tarkoittaa, että tiedostojen omistajat itse päättävät, kuka saa lukea, kirjoittaa tai suorittaa heidän tiedostojaan. Unix-käyttöoikeusbiteillä — käyttäjä, ryhmä ja muut — hallitaan pääsy, ja root-käyttäjällä on rajoittamaton valta koko järjestelmään.
Tuttu malli. Yksinkertainen. Mutta rehellisesti sanottuna: se on myös aika haavoittuva.
DAC-mallin isoin ongelma on siinä, että yksi kompromissoitu prosessi voi aiheuttaa laajaa tuhoa. Jos hyökkääjä onnistuu ajamaan mielivaltaista koodia web-palvelimen kontekstissa, hänellä on käytössään kaikki samat oikeudet kuin itse palvelimella. Tietokanta, konfiguraatiotiedostot, lokihakemistot — kaikki on auki. DAC ei oikeastaan tunne käsitettä "vähimmäisoikeus", vaan prosessit saavat kaiken sen mitä käyttäjätilillään tarvitsevat, ja yleensä paljon enemmän.
Pakollinen pääsynhallinta (Mandatory Access Control, MAC) ratkaisee tämän lisäämällä järjestelmään toisen, käyttäjistä riippumattoman hallintatason. MAC-järjestelmässä käyttöjärjestelmäydin itse valvoo jokaista resurssin käyttöyritystä ja vertaa sitä etukäteen määriteltyyn käytäntöön. Edes root-käyttäjä ei voi ohittaa näitä sääntöjä — käytäntö on kirjaimellisesti pakollinen.
MAC-järjestelmiä tarvitaan erityisesti ympäristöissä, joissa tietoturvaloukkauksen seuraukset ovat vakavat: julkishallinto, terveydenhuolto, finanssiala ja pilvipalveluiden isäntäkoneet. Vuoden 2025 tilastojen mukaan 55,6 prosenttia yritystason Linux-asennuksista käyttää SELinuxia tai AppArmoria pakottavassa tilassa. MAC on siis jo valtavirtaa.
Tässä oppaassa pureudutaan kahteen keskeiseen Linux-MAC-järjestelmään: SELinuxiin ja AppArmoriin. Käydään läpi molempien arkkitehtuuri, käyttöönotto, profiilien kirjoittaminen ja vertaillaan niitä tuotantokäytön näkökulmasta. Eli hypätään asiaan.
SELinux: Taustaa ja arkkitehtuuri
Mistä SELinux tuli?
SELinux syntyi Yhdysvaltain kansallisen turvallisuusviraston (NSA) tutkimusprojektina 1990-luvun lopulla. NSA:n tavoitteena oli luoda Linux-ytimelle pakollisen pääsynhallinnan mekanismi, joka toteuttaisi muun muassa Bell-LaPadulan formaalin tietoturvamallin periaatteet käytännössä. Vuonna 2000 NSA julkaisi SELinuxin avoimen lähdekoodin projektina, ja vuonna 2003 se integroitiin Linux-ytimen versioon 2.6.
Red Hat sisällytti SELinuxin RHEL 4:ään vuonna 2005, ja siitä lähtien se on ollut RHEL:n, CentOS:n ja Fedoran oletussuojausjärjestelmä.
SELinuxin ytimessä on Flask-arkkitehtuuri, joka erottaa käytäntöpäätökset järjestelmän muusta toiminnasta. Turvallisuuspäätökset tehdään siis erillisessä moduulissa, ja tulokset välimuistitetaan Access Vector Cache (AVC) -mekanismissa suorituskykyä varten. Tämä on hienoa suunnittelua — käytäntölogiikka pysyy erillään muusta ytimen koodista.
Turvakontekstit ja nimiavaruus
SELinuxin keskeisin käsite on turvakonteksti (security context). Jokaisella prosessilla, tiedostolla, socketilla ja muulla ytimen resurssilla on oma kontekstinsa, joka koostuu neljästä osasta:
käyttäjä:rooli:tyyppi:taso
user_u:system_r:httpd_t:s0
- Käyttäjä (user) — SELinux-käyttäjä, joka on eri asia kuin Unix-käyttäjä. Esimerkiksi
user_u,staff_utaisystem_u. - Rooli (role) — Määrittää, mihin tyyppeihin käyttäjä pääsee käsiksi. Vaikkapa
system_ron järjestelmäprosesseille jauser_rtavallisille käyttäjille. - Tyyppi (type) — Tärkein komponentti päivittäisessä hallinnassa. Tyypit kertovat, mihin resursseihin prosessi pääsee. Prosessin tyyppiä kutsutaan myös domaaniksi.
- Taso (level) — MLS/MCS-taso, esimerkiksi
s0tais0:c0,c1023. Tästä lisää myöhemmin.
Prosessien turvakonteksteja pääsee katsomaan näin:
ps auxZ | grep httpd
system_u:system_r:httpd_t:s0 root 1234 0.0 0.1 httpd
Ja tiedostojen kontekstit näkyvät ls -Z -komennolla:
ls -Z /var/www/html/
system_u:object_r:httpd_sys_content_t:s0 index.html
system_u:object_r:httpd_sys_content_t:s0 style.css
Tyypit, domeenit ja sääntörakenne
SELinuxin tyyppipakotus (Type Enforcement, TE) on käytännön ydin. Käytäntö määrittelee, minkä tyyppinen prosessi saa tehdä mitäkin minkä tyyppiselle resurssille:
allow httpd_t httpd_sys_content_t:file { read getattr open };
allow httpd_t http_port_t:tcp_socket name_bind;
Ensimmäinen sääntö sallii httpd_t-domaanissa toimivien prosessien lukea httpd_sys_content_t-tyyppisiä tiedostoja. Toinen sallii HTTP-palvelimen sitoutua HTTP-porttiin. Kaikki muu on oletuksena kiellettyä — tämä on se oleellinen asia.
Domeenimuutos (domain transition) tapahtuu, kun prosessi käynnistää toisen prosessin. SELinux valvoo näitä siirtymiä tarkasti: esimerkiksi init_t voi käynnistää httpd_t:n, mutta httpd_t ei voi suoraan siirtyä sshd_t-domaaniksi.
MLS ja MCS: Monitasoinen turvallisuus
Multi-Level Security (MLS) ja Multi-Category Security (MCS) ovat SELinuxin edistyneitä ominaisuuksia, joita AppArmorissa ei ole lainkaan. Tämä on merkittävä ero järjestelmien välillä.
MLS toteuttaa Bell-LaPadulan mallin: prosessit voivat lukea alemmilta tasoilta ja kirjoittaa ylemmille, mikä estää tiedon valumisen korkeammilta tasoilta alemmille. Tasot ilmaistaan muodossa s0 (Unclassified) — s3 (Top Secret).
MCS on puolestaan MLS:n yksinkertaistettu versio, jota käytetään erityisesti konttien eristämiseen. Jokaiselle kontille annetaan uniikki kategoriajoukko, jolloin konttien välinen tiedostopääsy estyy automaattisesti:
# Kontti 1
system_u:system_r:container_t:s0:c123,c456
# Kontti 2
system_u:system_r:container_t:s0:c789,c012
Nämä kontit eivät pysty lukemaan toistensa tiedostoja, vaikka molemmat pyörisivät samalla fyysisellä isäntäkoneella ja samassa käyttäjätilissä. Red Hat OpenShift hyödyntää juuri tätä mekanismia.
SELinuxin käyttöönotto ja hallinta
Tilan tarkistaminen
SELinuxin hallinnan ensimmäinen askel on selvittää, missä tilassa järjestelmä on. Kaksi hyödyllistä komentoa ovat getenforce ja sestatus:
# Nopea tilan tarkistus
getenforce
Enforcing
# Yksityiskohtainen tila
sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux mount point: /sys/fs/selinux
SELinuxfs: selinuxfs
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 33
SELinux toimii kolmessa tilassa:
- Enforcing — Pakottava tila. Käytäntörikkomukset estetään ja kirjataan lokiin.
- Permissive — Salliva tila. Rikkomukset kirjataan mutta ei estetä. Erinomainen vianetsintään.
- Disabled — SELinux kokonaan pois käytöstä. Tiedostoihin ei merkitä konteksteja, ja paluu pakottavaan tilaan vaatii koko tiedostojärjestelmän uudelleenmerkinnän.
Tilojen vaihtaminen
Ajonaikainen tilanvaihto onnistuu setenforce-komennolla:
# Vaihda pakottavaan tilaan
setenforce 1
# Vaihda sallivaan tilaan (vianetsintää varten)
setenforce 0
Pysyvä konfiguraatio määritetään tiedostossa /etc/selinux/config:
# /etc/selinux/config
SELINUX=enforcing
SELINUXTYPE=targeted
Tärkeä huomio: Älä ikinä poista SELinuxia käytöstä (SELINUX=disabled) tuotantoympäristöissä. Jos SELinux aiheuttaa ongelmia, käytä ensin sallivaa tilaa ongelman diagnosoimiseksi. Olen nähnyt liian monta kertaa, kun joku laittaa SELinuxin disabled-tilaan "väliaikaisesti" ja se jää sinne pysyvästi.
Booleanit: Joustava käytäntöhallinta
SELinux-booleanit ovat käteviä käytäntöparametreja, joita voidaan muuttaa ilman koko käytäntömoduulin uudelleenkääntämistä. Ne mahdollistavat yleisten palveluiden konfiguroinnin tarpeen mukaan:
# Listaa kaikki booleanit
getsebool -a
# Tarkista tietty booleani
getsebool httpd_can_network_connect
httpd_can_network_connect --> off
# Ota käyttöön ajonaikaisesti
setsebool httpd_can_network_connect on
# Ota käyttöön pysyvästi (-P tarkoittaa persistent)
setsebool -P httpd_can_network_connect on
# Yleisiä hyödyllisiä booleaneita
getsebool httpd_use_nfs # Salli NFS-hakemistot web-palvelimelle
getsebool samba_export_all_rw # Salli Samba kirjoittaa kaikkialle
getsebool ftp_home_dir # Salli FTP pääsy kotihakemistoihin
Tiedostokontekstien hallinta
Yksi yleisimmistä SELinux-ongelmista (ja uskokaa pois, tämä tulee vastaan usein) on väärä tiedostokonteksti. Kun siirrät tiedostoja tai luot hakemistoja tavallisilla Unix-komennoilla, SELinux-konteksti ei välttämättä ole oikein:
# Lisää pysyvä kontekstisääntö
semanage fcontext -a -t httpd_sys_content_t "/srv/verkkosivusto(/.*)?"
# Sovella säännöt tiedostojärjestelmään
restorecon -Rv /srv/verkkosivusto
# Tarkista tulos
ls -Z /srv/verkkosivusto/
system_u:object_r:httpd_sys_content_t:s0 index.html
# Muuta yksittäisen tiedoston konteksti
chcon -t httpd_sys_content_t /tmp/testisivu.html
# Listaa mukautetut kontekstisäännöt
semanage fcontext -l | grep /srv
Vianetsintä: audit2why ja audit2allow
Kun SELinux estää jotain, se kirjaa tapahtuman auditlokiin. Tiedosto /var/log/audit/audit.log sisältää kaikki AVC-kieltomerkinnät. Kaksi korvaamatonta työkalua näiden analysointiin ovat audit2why ja audit2allow:
# Etsi SELinux-kiellot lokista
ausearch -m avc -ts recent
# Selitä, miksi pyyntö kiellettiin
ausearch -m avc -ts recent | audit2why
# Tyypillinen tuloste:
# type=AVC msg=audit(1708300000.123:456): avc: denied { read } for
# pid=1234 comm="myapp" name="config.ini" dev="sda1" ino=5678
# scontext=system_u:system_r:myapp_t:s0
# tcontext=system_u:object_r:etc_t:s0
# tclass=file permissive=0
#
# Was caused by:
# Missing type enforcement (TE) allow rule.
# You can use audit2allow to generate a loadable module to allow this access.
# Generoi sallintasäännöt automaattisesti
ausearch -m avc -ts recent | audit2allow
# Generoi ladattava moduuli
ausearch -m avc -ts recent | audit2allow -M myapp_local
# Lataa moduuli ytimeen
semodule -i myapp_local.pp
Mukautettujen SELinux-käytäntöjen kirjoittaminen
Käytäntömoduulin rakenne
SELinux-käytäntömoduuli koostuu kolmesta tiedostosta:
- .te — Type Enforcement -tiedosto, varsinaiset sallintasäännöt
- .if — Interface-tiedosto, julkiset rajapinnat muille moduuleille
- .fc — File Context -tiedosto, tiedostokontekstien määrittelyt
Tässä yksinkertainen esimerkki mukautetusta sovelluksesta nimeltä myapp:
# myapp.te — Type Enforcement -tiedosto
policy_module(myapp, 1.0)
########################################
# Tyyppien määrittely
#
type myapp_t;
type myapp_exec_t;
type myapp_log_t;
type myapp_data_t;
########################################
# Käytäntösäännöt
#
# Salli myapp suoritua init:n käynnistämänä
init_daemon_domain(myapp_t, myapp_exec_t)
# Salli lokitiedostojen kirjoitus
logging_log_file(myapp_log_t)
allow myapp_t myapp_log_t:file { create write append getattr setattr open };
# Salli tietohakemiston hallinta
allow myapp_t myapp_data_t:dir { read write execute search add_name remove_name };
allow myapp_t myapp_data_t:file { create read write append unlink rename };
# Salli verkkoyhteydet (HTTP-portti)
corenet_tcp_connect_http_port(myapp_t)
# Salli DNS-kyselyt
sysnet_dns_name_resolve(myapp_t)
# myapp.fc — File Context -tiedosto
/usr/bin/myapp -- gen_context(system_u:object_r:myapp_exec_t,s0)
/var/lib/myapp(/.*)? gen_context(system_u:object_r:myapp_data_t,s0)
/var/log/myapp(/.*)? gen_context(system_u:object_r:myapp_log_t,s0)
/etc/myapp(/.*)? gen_context(system_u:object_r:myapp_data_t,s0)
Käytäntömoduulin kääntäminen ja lataaminen
# Käännä .te-tiedosto
checkmodule -M -m -o myapp.mod myapp.te
# Pakkaa .mod ja .fc yhteen .pp-pakettiin
semodule_package -o myapp.pp -m myapp.mod -f myapp.fc
# Lataa moduuli
semodule -i myapp.pp
# Tarkista, että moduuli on ladattu
semodule -l | grep myapp
myapp 1.0
# Päivitä tiedostokontekstit
restorecon -Rv /usr/bin/myapp /var/lib/myapp /var/log/myapp /etc/myapp
# Poista moduuli tarvittaessa
semodule -r myapp
audit2allow-pohjainen työnkulku
Käytännössä tehokkain tapa kehittää mukautettu käytäntö on tämä työnkulku:
- Suorita sovellus sallivassa tilassa tai aseta yksittäinen domaani permissive-tilaan
- Kerää kaikki AVC-kiellot lokista
- Analysoi kiellot
audit2why:llä - Generoi alustava käytäntö
audit2allow:lla - Tarkista generoidut säännöt manuaalisesti —
audit2allowei aina tuota minimaalisia oikeuksia (tämä on tärkeä kohta!) - Testaa käytäntö pakottavassa tilassa
# Aseta yksittäinen domaani permissive-tilaan testauksen ajaksi
semanage permissive -a myapp_t
# Suorita testit ja kerää lokit
journalctl -t setroubleshoot --since "1 hour ago"
# Generoi moduuli lokista
ausearch -m avc -c myapp | audit2allow -M myapp_local -l
# Tarkista generoitu .te-tiedosto ennen latausta
cat myapp_local.te
# Poista permissive-tila testin jälkeen
semanage permissive -d myapp_t
Parhaat käytännöt käytäntömoduuleissa
- Minimaalinen oikeusperiaate: Myönnä vain ne oikeudet, joita sovellus oikeasti tarvitsee. Vältä laajoja makroja kuten
unconfined_domain(). - Versionhallinta: Säilytä kaikki .te-, .if- ja .fc-tiedostot Gitissä. Dokumentoi jokainen muutos.
- Semanttiset versiot: Päivitä moduulin versiota jokaisella muutoksella.
policy_module(myapp, 1.0)muuttuu muotoonpolicy_module(myapp, 1.1). - Testausympäristö: Kehitä ja testaa käytännöt ensin permissive-tilassa erillisessä ympäristössä.
- Makrojen käyttö: Hyödynnä olemassa olevia käytäntömakroja sen sijaan, että kirjoitat kaiken alusta. Pyörää ei tarvitse keksiä uudelleen.
AppArmor: Taustaa ja arkkitehtuuri
Historia ja kehitys
AppArmor kehitettiin alun perin Immunix-yhtiössä 1990-luvun lopulla nimellä SubDomain. Novell osti teknologian vuonna 2005, ja kun Novell myöhemmin myytiin SUSE:lle, AppArmor siirtyi mukana. Canonical sisällytti AppArmorin Ubuntu 7.10:een vuonna 2007, ja siitä lähtien se on ollut Ubuntun oletussuojausjärjestelmä. Debian puolestaan otti AppArmorin oletukseksi versiossa 10 (Buster) vuonna 2019.
Mielenkiintoinen käänne tapahtui helmikuussa 2025: openSUSE Tumbleweed siirtyi AppArmorista SELinuxiin uusissa asennuksissa (snapshot 20250211). Tämä kertoo laajemmasta trendistä, jossa SELinuxin vakaampi ja laajempi käytäntökanta houkuttelee myös perinteisiä AppArmor-distribuutioita.
Polkupohjainen malli
AppArmorin perustavanlaatuinen ero SELinuxiin on sen polkupohjainen (path-based) malli. Siinä missä SELinux merkitsee jokaisen resurssin turvakontekstilla, AppArmor viittaa resursseihin niiden tiedostojärjestelmäpolun perusteella.
Tämä tekee AppArmorista huomattavasti helpomman ymmärtää — ja se näkyy heti profiileissa:
# Yksinkertainen AppArmor-profiili nginx:lle
#include <tunables/global>
/usr/sbin/nginx {
#include <abstractions/base>
#include <abstractions/nameservice>
capability net_bind_service,
capability setuid,
capability setgid,
/usr/sbin/nginx mr,
/etc/nginx/** r,
/var/log/nginx/*.log w,
/var/www/html/** r,
network inet stream,
network inet6 stream,
/run/nginx.pid rw,
/var/cache/nginx/** rw,
}
Profiilit ovat ihmisluettavia ja suoraviivaisia. Jokainen rivi kertoo selkeästi, mihin polkuun profiili viittaa ja mitä oikeuksia annetaan (r = read, w = write, x = execute, m = memory map, k = lock). SELinuxin käytäntöihin verrattuna tämä on kuin yö ja päivä luettavuuden kannalta.
Profiilit ja tilat
AppArmor-profiili voi olla kahdessa tilassa:
- Enforce (pakottava) — Profiilia sovelletaan täysimääräisesti. Kiellot estetään ja kirjataan lokiin.
- Complain (valittava) — Profiilia ei sovelleta, mutta rikkomukset kirjataan. Vastaa SELinuxin permissive-tilaa yksittäiselle sovellukselle.
AppArmor tukee myös abstraktioita, jotka ovat uudelleenkäytettäviä käytäntöpalasia. Esimerkiksi #include <abstractions/base> sisältää perussäännöt, joita käytännössä kaikki sovellukset tarvitsevat.
AppArmorin rajoitukset
AppArmorin polkupohjainen malli on selkeämpi, mutta siinä on omat rajoituksensa:
- Jos tiedosto siirretään toiseen polkuun, käytäntö voi lakata toimimasta oikein
- Symboliset linkit voivat johtaa yllättävään käyttäytymiseen
- MLS/MCS-tuki puuttuu kokonaan — monisalaustason ympäristöihin AppArmor ei sovellu
- Yksityiskohtainen verkkokäytäntö on rajatumpaa kuin SELinuxissa
- Konttien eristäminen jää vähemmän hienojakoiseksi ilman MCS-tukea
AppArmor-profiilien luominen ja hallinta
Profiilien luominen aa-genprof-työkalulla
AppArmorin hallintaan kuuluu apparmor-utils-paketti, joka sisältää olennaiset työkalut. Profiilien luominen aloitetaan aa-genprof-komennolla:
# Asenna tarvittavat työkalut
apt install apparmor-utils apparmor-profiles # Debian/Ubuntu
zypper install apparmor-utils # openSUSE (vanhempi)
# Aloita profiiligenerointi
aa-genprof /usr/bin/myapp
# aa-genprof:
# 1. Asettaa sovelluksen complain-tilaan
# 2. Pyytää sinua suorittamaan sovelluksen normaalissa käytössä
# 3. Kun painat S(can), se analysoi lokit
# 4. Ehdottaa sääntöjä ja pyytää hyväksyntää
# 5. Tallentaa profiilin /etc/apparmor.d/:hen
Profiilien jalostaminen aa-logprof-työkalulla
Kun profiili on luotu ja sovellus on pyörinyt complain-tilassa jonkin aikaa, aa-logprof analysoi lokit ja ehdottaa parannuksia:
# Analysoi lokit ja päivitä profiili
aa-logprof
# Tyypillinen vuorovaikutus:
# Reading log entries from /var/log/syslog.
# Updating AppArmor profiles in /etc/apparmor.d.
#
# Profile: /usr/bin/myapp
# Path: /etc/myapp/config.ini
# Mode: r
# Severity: 4
#
# [1 - #include <abstractions/base>]
# 2 - /etc/myapp/config.ini r,
# 3 - /etc/myapp/** r,
# (A)llow / [(D)eny] / (I)gnore / (G)lob / Glob with (E)xt / (N)ew / Audi(t) / (O)wner / (Q)uit?
Tilojen hallinta
# Aseta profiili pakottavaan tilaan
aa-enforce /usr/bin/myapp
# tai
aa-enforce /etc/apparmor.d/usr.bin.myapp
# Aseta profiili complain-tilaan
aa-complain /usr/bin/myapp
# Poista profiili käytöstä
aa-disable /usr/bin/myapp
# Lataa profiili uudelleen muutosten jälkeen
apparmor_parser -r /etc/apparmor.d/usr.bin.myapp
# Tarkista kaikkien profiilien tila
aa-status
# Tyypillinen aa-status -tuloste:
# apparmor module is loaded.
# 127 profiles are loaded.
# 120 profiles are in enforce mode.
# 7 profiles are in complain mode.
# 52 processes have profiles defined.
# 51 processes are in enforce mode.
# 1 process is in complain mode.
Profiilien elinkaari
Hyvän AppArmor-profiilin kehittäminen noudattaa selkeää elinkaarta:
- Generointi:
aa-genprofluo alustavan profiilin tarkkailemalla sovelluksen toimintaa - Complain-tila: Profiili pyörii complain-tilassa normaalin käytön ajan
- Jalostaminen:
aa-logprofanalysoi lokit ja ehdottaa tarvittavia sallintoja - Testaus: Profiili testataan kattavasti ennen pakottavaan tilaan siirtämistä
- Pakottaminen:
aa-enforceaktivoi täysimääräisen valvonnan - Ylläpito: Sovelluspäivitysten yhteydessä palataan complain-tilaan ja jalostetaan uudelleen
# Täydellinen profiiliesimerkki: Python-sovellus
# /etc/apparmor.d/usr.bin.python3-myapp
#include <tunables/global>
/usr/bin/python3 {
#include <abstractions/base>
#include <abstractions/python>
#include <abstractions/nameservice>
/usr/bin/python3 mr,
/usr/lib/python3/** r,
/usr/lib/python3-dist-packages/** r,
# Sovelluksen tiedostot
/opt/myapp/** r,
/opt/myapp/main.py rix,
# Konfiguraatio
/etc/myapp/settings.conf r,
# Data ja lokit
/var/lib/myapp/ r,
/var/lib/myapp/** rw,
/var/log/myapp.log w,
# Väliaikaiset tiedostot
/tmp/myapp-* rw,
# Verkko
network inet stream,
network inet dgram,
# Mahdollistaa signaalit
signal receive set=(term kill),
}
SELinux vs. AppArmor: Kattava vertailu
Tietoturvamallit
Kahden järjestelmän fundamentaalinen ero on tietoturvamallissa:
- SELinux käyttää etikettipohjasta (label-based) mallia. Jokainen resurssi saa turvakontekstin, joka on pysyvä ominaisuus. Päätökset perustuvat kontekstien välisiin suhteisiin.
- AppArmor käyttää polkupohjasta (path-based) mallia. Käytännöt viittaavat tiedostojärjestelmäpolkuihin.
Granulariteetti ja ilmaisuvoima
SELinux tarjoaa selvästi hienorakeisemman kontrollin:
- SELinux erottelee tiedosto-operaatiot tarkasti:
read,write,append,create,unlink,rename,getattr,setattr,ioctljne. - SELinux valvoo verkkoa socketin tasolla: mitkä tyypit voivat luoda TCP-socketin, sitoutua tiettyyn porttiin, hyväksyä yhteyksiä
- SELinux valvoo IPC-mekanismeja: jaettu muisti, semafoorit, viestijonot
- AppArmor tukee perusoikeuksia (r/w/x/m/k/l) ja muutamia verkkoprotokollia, mutta ei yhtä yksityiskohtaisesti
Monimutkaisuus ja oppimiskynnys
AppArmor on selvästi helpompi ottaa käyttöön. Ei siinä mitään kiertelemistä:
- Profiilit ovat ihmisluettavia tekstitiedostoja tutuilla polunimillä
aa-genprofjaaa-logprofautomatisoivat ison osan profiilin luomisesta- Virhediagnostiikka on suoraviivaisempaa: "prosessi yritti lukea tiedostoa X, mutta se ei ole profiilissa"
SELinux vaatii enemmän perehtymistä:
- Turvakontekstien, domainien, tyyppien ja roolien konseptit on omaksuttava
- Käytäntömoduulien kirjoittaminen vaatii SELinux-politiikkakielen tuntemusta
- AVC-kiellot eivät aina kerro suoraan, mikä käytäntösääntö puuttuu
- Onneksi
audit2whyjaaudit2allowhelpottavat merkittävästi vianetsintää
Distribuutiokohtaiset oletukset
MAC-oletukset vaihtelevat jakeluittain:
- RHEL 8, 9 ja 10 — SELinux pakottavassa tilassa
- CentOS Stream — SELinux pakottavassa tilassa, seuraa RHEL:ää
- Fedora — SELinux pakottavassa tilassa, usein edellä RHEL:ää uusissa ominaisuuksissa
- Ubuntu 20.04+ — AppArmor pakottavassa tilassa, laaja profiilikirjasto mukana
- Debian 10+ — AppArmor pakottavassa tilassa Buster-versiosta lähtien
- openSUSE Leap — AppArmor (perinteinen valinta)
- openSUSE Tumbleweed — SELinux uusissa asennuksissa vuodesta 2025
- SLES — AppArmor, mutta siirtymistä harkitaan
Konttituki
SELinux on vahvempi konttiympäristöissä, eikä tämä ole edes kovin kiistanalainen väite:
- MCS-kategoriat mahdollistavat jokaisen kontin eristämisen uniikilla kategoriaparilla
- Kubernetes ja OpenShift integroituvat syvällisesti SELinuxin kanssa
- Podman ja Docker käyttävät SELinux-konteksteja konttien eristämiseen (
:Zja:zmount-lipuilla)
# Kontin käynnistys SELinux-kontekstilla
podman run -v /data/myapp:/app:Z -it myapp:latest
# :Z asettaa hakemistolle konttispesifisen MCS-kontekstin
# :z (pienellä) jakaa kontekstin kaikkien konttien kesken
AppArmor tukee Docker-kontteja profiileilla, mutta ilman MCS:ää konttien välinen eristäminen ei ole yhtä vahvaa.
Suorituskyky
Molemmat järjestelmät aiheuttavat jonkin verran suorituskykyrasitetta, mutta käytännössä ero on häviävän pieni:
- SELinuxin AVC välimuistittaa päätökset tehokkaasti — tyypillinen rasitus on 1–3 prosenttia
- AppArmorin polkupohjaiset tarkistukset ovat yksinkertaisempia, mutta polkujen normalisointi lisää hieman ylimääräistä työtä
- Nykyaikaisilla järjestelmillä kummankin suorituskykyero on merkityksetön
Tilastot ja trendit vuonna 2025
Muutamia kiinnostavia lukuja:
- 55,6 % yritystason Linux-asennuksista käyttää SELinuxia tai AppArmoria pakottavassa tilassa — selvää kasvua vuodesta 2020, jolloin luku oli alle 40 %
- SELinux dominoi palvelinkeskuksissa, AppArmor on yleisempi kehittäjien ja pienempien ympäristöjen parissa
- Konttipohjaisten ympäristöjen yleistyminen on kasvattanut SELinuxin osuutta
- openSUSE Tumbleweedin siirtyminen SELinuxiin on symbolisesti merkittävä: AppArmor menettää vanhan tukijansa
Parhaat käytännöt tuotantoympäristöissä
CI/CD-integraatio
MAC-käytäntöjen hallinta kannattaa ehdottomasti integroida osaksi CI/CD-putkea. Käytäntömuutokset ansaitsevat saman laadunvarmistuksen kuin sovelluskoodi:
# Esimerkki GitLab CI/CD -putkesta SELinux-moduuleille
# .gitlab-ci.yml
stages:
- validate
- test
- deploy
validate-selinux-policy:
stage: validate
image: fedora:latest
script:
- dnf install -y selinux-policy-devel checkpolicy policycoreutils
- cd selinux-policies/myapp
- checkmodule -M -m -o myapp.mod myapp.te
- echo "SELinux policy syntax valid"
test-selinux-policy:
stage: test
image: registry.example.com/rhel9-selinux-test:latest
script:
- semodule_package -o myapp.pp -m myapp.mod -f myapp.fc
- semodule -i myapp.pp
- ./run_selinux_tests.sh
- ausearch -m avc -ts recent | grep -c "myapp" | \
awk '{ if($1 > 0) exit 1 }'
deploy-selinux-policy:
stage: deploy
script:
- ansible-playbook deploy-selinux.yml --extra-vars "version=$CI_COMMIT_SHA"
only:
- main
SIEM-monitorointi
SELinux- ja AppArmor-kielloista tulee generoida hälytyksiä SIEM-järjestelmään. Pelkät kiellot eivät riitä — olennaista on erottaa odotettavissa olevat kiellot (joille on jo avoin tiketti) uusista kielloista, jotka voivat indikoida hyökkäystä tai uutta sovelluskäyttäytymistä:
# Logstash-konfiguraatio SELinux-tapahtumille
# /etc/logstash/conf.d/selinux.conf
input {
file {
path => "/var/log/audit/audit.log"
type => "audit"
}
}
filter {
if [type] == "audit" {
grok {
match => { "message" => "type=AVC.*avc: %{WORD:action} \{ %{DATA:permissions} \} for pid=%{NUMBER:pid} comm=\"%{DATA:command}\".*scontext=%{DATA:source_context} tcontext=%{DATA:target_context}" }
}
if [action] == "denied" {
mutate { add_tag => ["selinux_denial"] }
}
}
}
output {
if "selinux_denial" in [tags] {
elasticsearch {
hosts => ["elasticsearch:9200"]
index => "selinux-denials-%{+YYYY.MM.dd}"
}
}
}
Golden image -käytäntö
Yksi tehokkaimmista tuotantokäytännöistä on golden image -malli, jossa MAC-käytäntö sisältyy peruslevykuvaan. Olen havainnut, että tämä lähestymistapa vähentää konfiguraatiovirheitä merkittävästi:
- Rakenna peruslevykuva: Luo VM- tai konttikuvan perusversio, johon sisältyy kaikki tarvittavat SELinux/AppArmor-moduulit pakottavassa tilassa.
- Testaa peruslevykuva: Aja kattava testisarja, joka varmistaa kaiken toimivan MAC:n kanssa.
- Jäädytä levykuva: Merkitse testattu versio golden imageksi ja käytä sitä kaikkien tuotantoinstanssien pohjana.
- Päivitä hallitusti: Kun sovellus tai käytäntö päivittyy, toista prosessi ja luo uusi golden image.
# Packer-konfiguraatio SELinux-golden imagelle
# golden-image.pkr.hcl
source "amazon-ebs" "rhel9-selinux" {
ami_name = "golden-rhel9-selinux-${local.timestamp}"
instance_type = "t3.medium"
source_ami = data.amazon-ami.rhel9.id
ssh_username = "ec2-user"
}
build {
sources = ["source.amazon-ebs.rhel9-selinux"]
provisioner "shell" {
inline = [
"sestatus | grep -q 'enforcing' || (echo 'SELinux ei pakottavassa tilassa!' && exit 1)",
"dnf install -y myapp myapp-selinux",
"semodule -i /tmp/myapp_custom.pp",
"restorecon -Rv /opt/myapp /var/lib/myapp /var/log/myapp",
]
}
provisioner "shell" {
script = "scripts/validate-selinux.sh"
}
}
Permissive-tila käyttöönotossa
Kun otat uutta sovellusta käyttöön tai päivität olemassa olevaa, käytä permissive-tilaa keräämään tarvittavat sallinnot ennen pakottavaan tilaan siirtymistä. Tässä on hyvä työnkulku:
# Työnkulku uuden sovelluksen käyttöönottoon
# 1. Asenna sovellus
dnf install -y newapp
# 2. Aseta domaani permissive-tilaan
semanage permissive -a newapp_t
# 3. Suorita sovellus normaalissa käytössä (vähintään 24-48h)
systemctl start newapp
systemctl enable newapp
# 4. Kerää kaikki AVC-viestit
ausearch -m avc -c newapp --start today > /tmp/newapp_avc.txt
# 5. Analysoi kiellot
cat /tmp/newapp_avc.txt | audit2why
# 6. Generoi käytäntömoduuli
cat /tmp/newapp_avc.txt | audit2allow -M newapp_local
# 7. Tarkista generoitu moduuli (ÄLÄ OHITA TÄTÄ VAIHETTA)
cat newapp_local.te
# 8. Lataa moduuli ja poista permissive-tila
semodule -i newapp_local.pp
semanage permissive -d newapp_t
# 9. Testaa pakottavassa tilassa
journalctl -f | grep -i selinux
Dokumentaatio ja auditointiketju
Kaikki MAC-käytäntömuutokset tulee dokumentoida. Tämä voi tuntua ylimääräiseltä byrokratialta, mutta se maksaa itsensä takaisin moninkertaisesti ongelmatilanteissa:
- Versionhallinta: Kaikki .te-, .fc-, .if-tiedostot ja AppArmor-profiilit Gitiin. Jokainen commit sisältää selkeän kuvauksen muutoksen syystä.
- Tikettijärjestelmä: Jokaiselle käytäntömuutokselle oma tiketti, jossa dokumentoidaan muutoksen tarve ja hyväksyjä.
- Muutosloki: Tuotantoon menevät moduulit sisältävät versiointilokin .te-tiedoston kommenteissa.
- Säännöllinen auditointi: Kvartaaleittain tarkistetaan ladatut moduulit ja varmistetaan, ettei käytössä ole tarpeettomia sallintoja.
#!/bin/bash
# Auditointiskripti — listaa kaikki ladatut SELinux-moduulit ja niiden tilat
echo "=== SELinux-moduulien auditointi $(date) ==="
echo ""
echo "Ladatut moduulit:"
semodule -l | sort
echo ""
echo "Mukautetut tiedostokontekstit:"
semanage fcontext -l -C
echo ""
echo "Mukautetut portit:"
semanage port -l -C
echo ""
echo "Permissive-domainit (TARKISTA NÄMÄ!):"
semanage permissive -l
echo ""
echo "Aktiiviset booleanit (ei-oletusarvot):"
semanage boolean -l -C
Konttikäytännöt
Kubernetes-ympäristöissä SELinux-kontekstit määritetään Pod Security Context -asetuksissa:
# Kubernetes Pod -määrittely SELinux-kontekstilla
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
spec:
securityContext:
seLinuxOptions:
level: "s0:c123,c456"
type: container_t
containers:
- name: myapp
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
Hälytyssäännöt ja reagointi
Määrittele selkeät hälytyssäännöt MAC-kielloille:
- Kriittinen hälytys: Kielto, jossa lähdedomainina on
unconfined_ttai kielto kohdistuushadow_t- taietc_t-tyyppeihin - Korkea prioriteetti: Uusi, toistuvasti esiintyvä kieltotyyppi jota ei ole nähty aiemmin
- Matala prioriteetti: Tunnettu kielto, jolle on avoin kehitystiketti
Yhteenveto ja suositukset
Kumpi järjestelmä kannattaa valita?
SELinux ja AppArmor ovat molemmat kypsiä, tuotantokelpoisiksi todistettuja MAC-järjestelmiä. Oikea valinta riippuu kontekstista.
Valitse SELinux, jos:
- Käytät RHEL-, CentOS- tai Fedora-pohjaisia järjestelmiä
- Tarvitset MLS/MCS-tukea (valtiohallinto, korkeaturvallisuusympäristöt)
- Konttialustasi on Kubernetes tai OpenShift
- Haluat maksimaalisen granulariteetin käytäntöhallinnassa
- Tiimilläsi on resursseja investoida oppimiskäyrän ylittämiseen
Valitse AppArmor, jos:
- Käytät Ubuntu- tai Debian-pohjaisia järjestelmiä
- Tiimillä on rajallinen MAC-kokemus ja tarvitset nopean käyttöönoton
- Profiilien ylläpito tapahtuu pienellä tiimillä
- MLS/MCS ei ole vaatimus
Yleiset periaatteet
Järjestelmästä riippumatta nämä periaatteet pätevät aina:
- Älä koskaan poista MAC:ia käytöstä tuotannossa. Jos ongelmia ilmenee, käytä permissive/complain-tilaa diagnosointiin.
- Aloita permissive/complain-tilasta ja kerää riittävästi lokidataa ennen pakottavaan tilaan siirtymistä.
- Integroi käytäntöhallinta CI/CD-putkeen. Käytäntömuutokset ovat koodia.
- Seuraa kieltoja SIEM:ssä. MAC:n arvo toteutuu vain, jos poikkeamiin reagoidaan.
- Dokumentoi kaikki poikkeukset. Jos myönnät laajan oikeuden, kirjaa syy ja suunnitelma sen kaventamiseksi.
- Rakenna golden imagen päälle. Testaa MAC-käytäntö perusteellisesti ennen levitystä tuotantoon.
Tulevaisuuden näkymät
MAC-järjestelmien merkitys vain kasvaa. Pilvinatiivin infrastruktuurin yleistyminen, konttiorkestraation kasvu ja yhä monimutkaisempi uhkakuva tekevät pakollisesta pääsynhallinnasta entistä kriittisemmän suojakerroksen.
Se, että 55,6 % yritystason Linux-asennuksista käyttää MAC:ia pakottavassa tilassa vuonna 2025, kertoo alan kypsymisestä. Mutta se kertoo myös siitä, että lähes puolessa asennuksista tärkeä suojakerros on vielä käyttämättä.
openSUSE Tumbleweedin siirtyminen SELinuxiin helmikuussa 2025 on merkki siitä, että konsensus kallistuu yhä enemmän SELinuxin puolelle — parempi ekosysteemituki, konttioptimointi ja laajempi käytäntökanta painavat vaakakupissa. Tämä ei tarkoita, että AppArmor olisi väistymässä (se pysyy vahvana Debian/Ubuntu-ekosysteemissä), mutta SELinuxin asema de facto -standardina yrityslinuxissa vahvistuu.
Tärkeintä on kuitenkin se, että jokin MAC-järjestelmä on käytössä pakottavassa tilassa. Hyvin konfiguroidulla AppArmorilla tai SELinuxilla varustettu järjestelmä on merkittävästi turvallisempi kuin järjestelmä ilman MAC:ia — vaikka käytäntö ei olisikaan täydellinen. Aloita tänään, kehitä jatkuvasti, ja tee MAC:sta erottamaton osa Linux-infrastruktuurisi tietoturvarakennetta.