SELinux Management Guide#

Dokumentasi operasional pengelolaan SELinux — mental model, tooling harian, dan workflow troubleshooting.


1. Mental Model: Label-Based, Bukan Path-Based#

Permission Linux biasa (DAC — Discretionary Access Control) menjawab: user ini boleh akses file ini atau tidak?

SELinux (MAC — Mandatory Access Control) menjawab pertanyaan berbeda: proses jenis ini boleh akses objek jenis ini atau tidak?

Semua entitas di sistem punya label (context) dengan format:

user:role:type:level
system_u:object_r:mssql_db_t:s0

Bagian yang paling relevan untuk operasional sehari-hari adalah type (berakhiran _t). Model dominannya disebut type enforcement:

KonsepPenjelasanContoh
DomainType yang melekat pada proseshttpd_t, mssql_server_t, smbd_t
Object typeType yang melekat pada file/dir/port/sockethttpd_sys_content_t, cifs_t, http_port_t
Allow ruleRule di policy yang mengizinkan aksesallow httpd_t httpd_sys_content_t : file { read open getattr };

Prinsip utama: default deny. Kalau tidak ada allow rule yang match, akses ditolak — walaupun DAC (chmod/chown) sudah 777. DAC dan SELinux adalah dua layer independen dan keduanya harus lolos.

Contoh nyata: mssql_server_t tidak punya allow rule ke cifs_t, sehingga SQL Server on Linux ditolak membaca CIFS mount walaupun permission POSIX-nya sudah benar.


2. Mode Operasi#

getenforce            # Enforcing / Permissive / Disabled
setenforce 0          # permissive (runtime, tidak persist)
setenforce 1          # enforcing

Konfigurasi persist ada di /etc/selinux/config.

ModePerilaku
EnforcingDenial diblokir dan dilog
PermissiveDenial dilog tapi tidak diblokir — mode diagnosa, bukan “SELinux mati”
DisabledHindari. File baru dibuat tanpa label; saat dinyalakan kembali butuh full relabel (touch /.autorelabel && reboot)

Kolom permissive=0/1 di AVC log menunjukkan mode saat denial terjadi.

Permissive per-domain (lebih presisi)#

Daripada permissive seluruh sistem, buat satu domain saja yang permissive:

semanage permissive -a mssql_server_t    # hanya domain ini yang tidak di-enforce
semanage permissive -d mssql_server_t    # kembalikan ke enforcing
semanage permissive -l                   # list domain permissive

Kenapa: proteksi domain lain tetap jalan, dan semua denial dari satu service terkumpul sekaligus. Dalam mode enforcing, denial muncul satu per satu karena proses berhenti di denial pertama.


3. Membaca Denial (AVC)#

Semua denial masuk ke audit log:

ausearch -m avc -ts recent          # 10 menit terakhir
ausearch -m avc -ts today
sealert -a /var/log/audit/audit.log # butuh paket setroubleshoot-server; memberi saran solusi

Anatomi AVC#

avc: denied { read }                      ← permission yang ditolak
pid=20317 comm="\SystemRoot\Sys"          ← proses
scontext=...:mssql_server_t:s0            ← SOURCE: domain proses
tcontext=...:cifs_t:s0                    ← TARGET: type objek
tclass=dir                                ← class objek (dir/file/tcp_socket/dll)

Cara membacanya selalu: “domain X minta permission Y ke type Z, class W — dan tidak ada rule yang mengizinkan.”

Empat kemungkinan solusi (urutan prioritas)#

  1. Label objek salah → perbaiki label (~70% kasus)
  2. Ada boolean yang meng-cover use case → nyalakan boolean
  3. Memang butuh rule baru → custom policy module
  4. Memang serangan/bug → biarkan diblokir; SELinux sedang bekerja

4. Mengelola Label File#

Melihat label#

ls -Z file                  # label file
ls -Zd /dir                 # label directory-nya sendiri
ps -eZ | grep mssql         # domain proses
id -Z                       # context shell saat ini

Dua tempat label “hidup”#

  1. Label aktual — disimpan di extended attribute tiap file
  2. File context database — daftar mapping regex path → label default (policy + local customization)
chcon -t httpd_sys_content_t /web/file                      # ubah label AKTUAL saja
semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?"    # ubah DATABASE
restorecon -Rv /web                                          # apply database → label aktual

Jebakan umum: chcon saja tidak cukup. restorecon atau relabel apapun akan me-reset label aktual kembali sesuai database. Workflow yang benar: semanage fcontext dulu, lalu restorecon. Gunakan chcon hanya untuk eksperimen cepat.

Command pendukung#

semanage fcontext -l | grep httpd     # cari type yang tepat dari mapping existing
matchpathcon /some/path               # "path ini seharusnya label apa?"
restorecon -Rvn /dir                  # dry-run: preview perubahan tanpa mengubah

Pengecualian: network filesystem (CIFS / sebagian NFS)#

Network filesystem tidak menyimpan xattr SELinux per-file. Seluruh mount mendapat satu label dari mount option. chcon/restorecon tidak berpengaruh — satu-satunya kontrol lewat opsi context= di mount/fstab:

//nas-ip/share  /Public  cifs  credentials=/root/.smbcreds,uid=mssql,gid=mssql,file_mode=0770,dir_mode=0770,context="system_u:object_r:mssql_db_t:s0"  0 0

Pilih type yang memang sudah diizinkan untuk domain yang butuh akses (contoh: mssql_db_t untuk mssql_server_t), sehingga tidak perlu custom rule.


5. Booleans — Tombol On/Off Policy#

Policy writer sudah mengantisipasi banyak use case umum dalam bentuk toggle:

getsebool -a                                 # semua boolean
getsebool -a | grep httpd                    # filter
semanage boolean -l                          # sama, plus deskripsi singkat
setsebool httpd_can_network_connect on       # runtime saja
setsebool -P httpd_can_network_connect on    # -P = persist

Contoh klasik: reverse proxy nginx/httpd ke backend gagal dengan connect() permission denied → bukan bug, tapi httpd_can_network_connect default off.

Selalu cek boolean sebelum membuat custom rule — boolean sudah di-review scope-nya oleh policy maintainer.

Contoh boolean terkait network filesystem:

setsebool -P samba_export_all_rw on    # Samba boleh export semua path (longgar)
setsebool -P httpd_use_cifs on         # Apache boleh baca CIFS mount
setsebool -P virt_use_samba on         # virt/container boleh akses CIFS

6. Port Labels#

Service hanya boleh bind ke port dengan type yang sesuai domain-nya:

semanage port -l | grep http
# http_port_t    tcp    80, 81, 443, 488, 8008, 8009, 8443, 9000

# izinkan nginx listen di 8888:
semanage port -a -t http_port_t -p tcp 8888

# kalau port sudah punya type lain, gunakan -m (modify), bukan -a
semanage port -m -t http_port_t -p tcp 8888

Gejala khas: service gagal start dengan bind: permission denied padahal port kosong. Cek AVC — tclass=tcp_socket.


7. Custom Policy Module — Jalan Terakhir#

Gunakan hanya jika label sudah benar dan tidak ada boolean yang cocok:

# kumpulkan denial (idealnya dalam mode permissive agar lengkap), lalu:
ausearch -m avc -ts recent | audit2allow -M mymodule

cat mymodule.te                     # BACA DULU sebelum install!

semodule -i mymodule.pp             # install
semodule -l | grep mymodule         # verifikasi
semodule -r mymodule                # remove

Kenapa harus dibaca dulu: audit2allow membuat rule yang persis mengizinkan apa yang ditolak, tanpa mempertimbangkan scope. Kalau denial-nya httpd_t membaca shadow_t, dia akan membuatkan rule-nya — dan web server jadi boleh membaca /etc/shadow. Kalau .te yang dihasilkan terlihat terlalu lebar, mundur dan tanya: “apa sebenarnya label yang salah?”

audit2why menjelaskan kenapa akses ditolak dan kadang menunjuk boolean yang relevan:

ausearch -m avc -ts recent | audit2why

8. Workflow Troubleshooting Standar#

1. Service error aneh → curiga SELinux?
   ausearch -m avc -ts recent

2. Tidak ada AVC tapi masih curiga?
   → kemungkinan dontaudit rule menyembunyikan denial:
   semodule -DB        # disable dontaudit, semua denial terlihat
   (reproduce masalah)
   semodule -B         # kembalikan

3. Ada AVC → baca scontext / tcontext / tclass
   → target type terlihat "generik" (default_t, cifs_t,
     user_home_t di tempat aneh)?
        → masalah LABEL → semanage fcontext + restorecon,
          atau context= di mount option (network fs)
   → audit2why menyebut boolean?
        → setsebool -P <boolean> on
   → keduanya tidak?
        → audit2allow, REVIEW .te, semodule -i

4. Verifikasi: reproduce masalah, pastikan AVC bersih

9. Kenapa Tidak setenforce 0 Permanen#

SELinux adalah containment layer. Kalau service (SQL Server, nginx, dll) kena RCE, attacker hanya bisa bergerak sebatas allow rule domain tersebut — tidak bisa membaca SSH key, menulis ke /etc, atau pivot ke service lain.

setenforce 0 permanen = membuka semua pintu karena satu kunci macet. Perbaiki labelnya, bukan matikan sistemnya.


Cheat Sheet#

TujuanCommand
Cek modegetenforce
Lihat denial terbaruausearch -m avc -ts recent
Lihat label file/dirls -Z file / ls -Zd /dir
Lihat domain prosesps -eZ | grep <svc>
Label seharusnyamatchpathcon /path
Set label persistsemanage fcontext -a -t <type> "/path(/.*)?" lalu restorecon -Rv /path
Cari booleansemanage boolean -l | grep <kw>
Set boolean persistsetsebool -P <bool> on
Izinkan port barusemanage port -a -t <type> -p tcp <port>
Permissive satu domainsemanage permissive -a <domain_t>
Penjelasan denialausearch -m avc -ts recent | audit2why
Custom moduleaudit2allow -M mod → review .tesemodule -i mod.pp
Tampilkan denial tersembunyisemodule -DB (kembalikan: semodule -B)