Mengelola SELinux seperti kode: policy module tersimpan di git, didistribusikan lewat Ansible, templating boolean dan fcontext, pengujian di CI, hingga pipeline build ber-version dengan rollback terstruktur.

Setelah di episode 19 kalian mengisolasi aplikasi yang tidak tepercaya dengan sandbox, sekarang kita menjawab pertanyaan yang jauh lebih strategis: bagaimana mengelola SELinux di infrastruktur yang bukan satu server? Di episode 18 kita sudah menyentuh pentingnya policy yang seragam. Episode 20 ini mengubah itu menjadi praktik nyata dengan policy-as-code: seluruh policy SELinux — module, boolean, fcontext — diperlakukan seperti kode aplikasi, dengan git, review, CI, dan rilis ber-version.
Pernah melihat server yang konfigurasi SELinux-nya cuma ada di kepala admin yang sudah resign? Itu kebalikan dari policy-as-code. Bayangkan kalau source code aplikasi kalian disimpan hanya di ingatan orang — tidak ada yang bisa memverifikasi, menguji, atau mengembalikan versi. Policy SELinux yang dijalankan lewat semanage dan semodule -l langsung di shell mengalami nasib yang sama: tidak terdokumentasi, tidak bisa diaudit, dan mudah drift.
Solusinya: jadikan tree source module sebagai repositori git. Struktur tipikalnya:
myapp/
├── myapp.te # type enforcement rules
├── myapp.fc # file context
├── myapp.if # interface (opsional)
└── MakefileDengan ini, setiap perubahan adalah commit, setiap commit bisa di-review, dan setiap rilis bisa di-tag.
Module yang pernah kalian tulis di episode-episode sebelumnya bisa dibuat ulang kapan pun dari source tree. File .te misalnya:
policy_module(myapp, 1.0.0)
type myapp_t;
type myapp_exec_t;
domain_type(myapp_t)
domain_entry_file(myapp_t, myapp_exec_t)
allow myapp_t self:tcp_socket create_socket_perms;
allow myapp_t myapp_conf_t:file read_file_perms;
allow myapp_t myapp_log_t:file { create append_file_perms };
allow myapp_t myapp_log_t:dir { create read search add_name };File context untuk memberi label path:
/opt/myapp(/.*)? gen_context(system_u:object_r:myapp_exec_t,s0)
/etc/myapp(/.*)? gen_context(system_u:object_r:myapp_conf_t,s0)
/var/log/myapp(/.*)? gen_context(system_u:object_r:myapp_log_t,s0)Catatan penting: kolom pada .fc dipisahkan dengan tab, dan kolom kedua harus diperlakukan sebagai satu field — jangan mengganti tab dengan spasi. Membangun module dari tree source memakai Makefile standar:
make -f /usr/share/selinux/devel/Makefilesemodule -i myapp.ppsemodule -l | grep myappYang menarik: perintah make ini bekerja juga di CI — sebuah pipeline bisa menolak module yang tidak lolos kompilasi tanpa pernah menyentuh server produksi.
Distribusi policy ke banyak host adalah pekerjaan yang membosankan dan rawan salah kalau dikerjakan manual. Ansible menjawabnya dengan idempotensi: playbook yang sama dijalankan berkali-kali memberikan hasil yang sama. Untuk SELinux ada tiga module utama yang perlu kalian kenal:
ansible.posix.selinux — mengatur state (enforcing/permissive) dan boolean.community.general.selinux_fcontext — mengelola file context.community.general.selinux_permissive — mengelola domain permissive.Contoh playbook untuk menerapkan boolean dan fcontext secara seragam:
- name: Terapkan policy SELinux seragam
hosts: webservers
become: true
vars:
httpd_booleans:
- name: httpd_can_network_connect
state: true
fcontexts:
- target: /var/www/myapp(/.*)?
setype: httpd_sys_content_t
state: present
tasks:
- name: Setel mode SELinux
ansible.posix.selinux:
policy: targeted
state: enforcing
- name: Atur boolean httpd
ansible.posix.selinux:
name: "{{ item.name }}"
state: "{{ 'on' if item.state else 'off' }}"
persistent: true
loop: "{{ httpd_booleans }}"
- name: Terapkan file context
community.general.selinux_fcontext:
target: "{{ item.target }}"
setype: "{{ item.setype }}"
state: "{{ item.state }}"
loop: "{{ fcontexts }}"Perhatikan dua hal. Pertama, persistent: true pada boolean memastikan nilainya bertahan setelah reboot — tanpa itu, perubahan boolean hanya berlaku sampai restart. Kedua, module fcontext tidak menjalankan restorecon otomatis; kalian tetap perlu memanggil restorecon untuk file yang sudah ada agar labelnya diperbarui:
restorecon -Rv /var/www/myappTip
Gabungkan playbook di atas dengan verifikasi baseline dari episode 18: setelah menjalankan restorecon, playbook yang sama bisa mengecek semodule -l dan membandingkan daftar module terhadap yang diharapkan. Ansible bukan hanya alat menerapkan, tapi juga alat memastikan — dan itulah yang membuat policy tetap seragam di seluruh fleet.
Build yang sukses belum berarti policy itu aman. Di CI, tambahkan lapisan pengujian:
name: Policy SELinux
on:
push:
paths: ["policy/**"]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Bangun module
run: make -f /usr/share/selinux/devel/Makefile
- name: Analisis dengan SETools
run: |
seinfo -x myapp.pp
sesearch --allow -t shell_exec_t myapp.pp || true
- name: Instalasi percobaan di container
run: ./tests/install-and-smoke-test.shDua lapis di atas layak diperhatikan:
seinfo dan sesearch dari SETools membacai .pp tanpa perlu booting — misalnya untuk memastikan tidak ada aturan yang mengizinkan domain aplikasi mengeksekusi shell (shell_exec_t).tests/install-and-smoke-test.sh memuat module di container atau mesin uji, menjalankan aplikasi sebentar, lalu menegaskan bahwa ausearch -m avc tidak berisi deny yang tidak diharapkan. Ini membuat deny baru ketahuan di CI, bukan di produksi.Artifak module yang dihasilkan CI harus punya versi yang jelas — misalnya myapp-v1.2.0.pp — dan setiap versi tersimpan (Nexus, GitHub Release, atau bucket storage). Perintah semodule -l menampilkan daftar module aktif untuk mencocokkan versi yang terpasang. Mengapa? Karena rollback harus dilakukan ke versi yang diketahui, bukan menebak.
semodule -r myapp
semodule -i myapp-v1.1.0.pp
restorecon -Rv /opt/myapp /etc/myappWarning
Jangan pernah menghapus module lama tanpa menyimpan versi sebelumnya. Rollback yang "rebuild dari ingatan" adalah kontra-rollback: di saat genting kalian justru berimprovisasi. Simpan .pp ber-version sebagai artefak CI, catat versi mana yang terpasang di host mana, dan jadikan semodule -r yang diikuti pemasangan versi lama sebagai prosedur standar — bukan satu langkah dramatis yang dihapal.
Ringkasan praktik yang membuat pendekatan ini bertahan lama:
seinfo, sesearch) sebelum deploy.ausearch -m avc) pada mesin uji.Pada episode 20 ini kalian telah belajar memperlakukan SELinux sebagai kode sungguhan: source module di git, build dan uji di CI, distribusi idempoten dengan Ansible (boolean, fcontext, dan permissive lewat module ansible.posix.selinux, community.general.selinux_fcontext, dan community.general.selinux_permissive), serta pipeline ber-version dengan rollback terstruktur. Dengan pola ini, "SELinux sulit dikelola di skala besar" bukan lagi alasan — karena semua keputusan terdokumentasi, dapat diaudit, dan bisa dikembalikan.
Di episode 21 berikutnya kita melihat ke depan: rilis SELinux userspace 3.11 (Juli 2026) dengan secilcheck, restorecon -F, setfiles -A dan -U, perbaikan keamanan libselinux dan dbus, serta peta jalan rilis 3.12 pada 2027. Sampai jumpa!