Cara Menjalankan Servis Linux Sebagai Pengguna Biasa
Menjalankan servis sebagai root berisiko tinggi terhadap keselamatan pelayan. Gunakan akaun tanpa keistimewaan atau tetapan DynamicUser pada systemd untuk mengehadkan akses.
Mengapa tidak jalankan segala-galanya sebagai root
Akaun root mempunyai kuasa penuh ke atas mesin: membaca setiap fail, mengubah sebarang tetapan, dan memadam keseluruhan sistem. Apabila anda menjalankan servis sebagai root, anda menyerahkan semua kuasa tersebut kepada servis berkenaan. Jika servis itu mempunyai pepijat yang boleh dieksploitasi oleh penyerang, mereka bukan sahaja mendapat akses kepada servis tersebut, malah mereka mendapat akses root, dan root bermakna keseluruhan pelayan. Menjalankan servis sebagai pengguna tanpa keistimewaan (unprivileged user) akan mengehadkan kerosakan. Pepijat dalam servis yang dijalankan sebagai akaun terhad hanya memberikan penyerang akses kepada apa yang boleh disentuh oleh akaun tersebut, yang sepatutnya hampir tiada apa-apa.
Ini adalah prinsip keistimewaan minimum (principle of least privilege): berikan setiap bahagian sistem akses yang tepat untuk menjalankan tugasnya, dan tidak lebih daripada itu. Ini merupakan tabiat paling berkesan untuk mengehadkan kesan kerosakan sekiranya berlaku pencerobohan, dan pada pelayan moden, ia hampir tidak memerlukan sebarang kos untuk dilaksanakan.
Akaun khusus bagi setiap servis
Pendekatan klasik adalah dengan mencipta pengguna sistem yang berasingan bagi setiap servis, yang hanya memiliki fail servis tersebut dan tidak boleh log masuk. Akaun sistem untuk aplikasi web mungkin kelihatan seperti ini:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin appsvcSetiap flag adalah penting. --system menjadikannya akaun servis, bukan log masuk manusia. --no-create-home melangkau direktori home yang tidak diperlukan. --shell /usr/sbin/nologin bermaksud walaupun penyerang entah bagaimana berjaya menguasai akaun tersebut, mereka tidak boleh membuka shell dengannya. Akaun ini wujud hanya untuk memiliki proses dan failnya.
Kemudian, berikan pengguna tersebut hanya fail yang diperlukan, dan tiada yang lain:
sudo chown -R appsvc:appsvc /opt/myappKini, servis tersebut membaca dan menulis dalam direktorinya sendiri dan tidak mempunyai akses di mana-mana bahagian lain pada cakera. Jika ia pernah dieksploitasi, fail yang boleh diubah oleh penyerang adalah terhad kepada /opt/myapp; akaun tersebut masih boleh membaca apa-apa yang boleh dibaca oleh semua orang (world-readable), tetapi ia tidak boleh mengubah suai bahagian sistem yang lain.
Benarkan systemd menjalankannya sebagai pengguna tersebut
Setelah akaun wujud, arahkan systemd untuk menjalankan servis tersebut menggunakan akaun itu. Dalam fail unit, satu baris sahaja diperlukan:
[Service]
ExecStart=/opt/myapp/bin/server
User=appsvc
Group=appsvcUser=appsvc bermaksud proses bermula dengan keistimewaan terhad akaun tersebut dan bukannya keistimewaan root. Ini merupakan cara biasa dan standard untuk menjalankan aplikasi di bawah systemd, dan ia wajar dilakukan bagi setiap servis yang anda tulis unitnya. Walau bagaimanapun, pengurangan keistimewaan tidak akan membantu jika systemd memantau proses yang salah. Oleh itu, jika unit masih melaporkan status active selepas daemon berhenti secara senyap, pastikan anda telah memilih Type= yang betul untuk cara proses anda bermula.
Atau langkau akaun sepenuhnya dengan DynamicUser
systemd boleh melangkah lebih jauh dengan mencipta pengguna sementara untuk anda, iaitu pengguna yang hanya wujud semasa servis berjalan. Tetapkan DynamicUser=yes dan anda tidak perlu mengurus akaun sama sekali:
[Service]
ExecStart=/opt/myapp/bin/server
DynamicUser=yes
StateDirectory=myappSemasa bermula, systemd memperuntukkan ID pengguna yang tidak digunakan; semasa berhenti, ia melepaskannya. Servis tersebut juga mendapat /tmp peribadi, pandangan baca-sahaja bagi kebanyakan sistem fail, dan direktori status boleh-tulis di bawah /var/lib/myapp yang disediakan oleh StateDirectory= dan diserahkan kepadanya. Tiada perkara seperti ini yang mungkin dilakukan di bawah SysV init, di mana penurunan keistimewaan diserahkan kepada apa sahaja yang dilakukan oleh skrip permulaan servis itu sendiri, dan jurang tersebut merupakan sebahagian besar daripada sebab pengedaran beralih kepada systemd pada mulanya. Bagi servis kendiri yang hanya memerlukan direktori statusnya sendiri, DynamicUser=yes ialah cara paling mudah untuk mendapatkan pengasingan yang kukuh, kerana tiada akaun jangka panjang untuk disasarkan oleh penyerang.
Menulis unit secara manual adalah rumit, dan mendapatkan arahan pengukuhan (hardening) yang betul adalah nilai yang paling utama. Penjana dalam panduan servis dan pemasa systemd boleh mengisi pilihan ini untuk anda supaya unit tersebut betul pada kali pertama.
Bagaimana ini disepadukan dengan komponen lain
Prinsip keistimewaan minimum (least privilege) hanyalah satu lapisan, dan ia berfungsi bersama lapisan lain dan bukannya menggantikannya. Firewall default-deny mengawal perkara yang boleh mencapai servis; menjalankan servis sebagai pengguna tanpa keistimewaan (unprivileged user) mengawal perkara yang boleh dilakukan oleh servis tersebut jika ia diceroboh; dan SSH yang diperkukuh (hardened SSH) menghalang penyerang daripada memasuki pelayan sejak awal lagi. Tiada satu pun daripada langkah ini mencukupi secara sendirian, dan secara kolektif, ia memastikan pepijat dalam satu servis tidak menyebabkan keseluruhan pelayan terjejas. Mengehoskan sesuatu yang menyimpan rahsia menunjukkan had lapisan ini: akaun terhad mengehadkan perkara yang boleh dicapai oleh proses yang diceroboh, namun pengurus kata laluan yang dihoskan sendiri seperti Vaultwarden masih bergantung pada cara anda melindungi token pentadbir dan fail sandarannya, yang mana kedua-duanya tidak dilindungi oleh pengasingan pengguna (user isolation).
Sebelum anda meneruskan, jalankan senarai semak pengukuhan untuk keseluruhan pelayan dan jana salinan peribadi untuk dijadikan rujukan:
FAQ
Mengapa saya tidak patut menjalankan servis sebagai root?
Kerana root boleh melakukan apa sahaja pada mesin, servis yang berjalan sebagai root yang dieksploitasi akan memberikan seluruh pelayan kepada penyerang, bukan sekadar servis tersebut. Menjalankan servis sebagai akaun terhad dan tanpa keistimewaan mengehadkan kerosakan kepada apa sahaja yang boleh diakses oleh akaun tersebut. Simpan root untuk pentadbiran, dan jalankan setiap servis yang berjalan lama sebagai pengguna yang disekat.
Bagaimanakah cara saya mencipta pengguna yang tidak boleh log masuk?
Jalankan sudo useradd --system --no-create-home --shell /usr/sbin/nologin NAME. Shell nologin bermaksud akaun tersebut tidak boleh membuka sesi interaktif walaupun kelayakannya dicuri, --system menandakannya sebagai akaun servis, dan --no-create-home melangkau direktori rumah yang tidak diperlukannya. Berikan hak milik hanya kepada failnya sendiri dengan chown.
Apakah itu systemd DynamicUser?
DynamicUser=yes memberitahu systemd untuk mencipta pengguna sementara bagi servis yang hanya wujud semasa ia berjalan, jadi anda tidak perlu mengurus akaun yang kekal lama. Ia juga memberikan servis /tmp peribadi, pandangan sistem fail yang kebanyakannya baca-sahaja, dan direktori status yang diuruskan. Ini adalah cara paling mudah untuk menjalankan servis yang lengkap di bawah identiti pakai buang yang berkeistimewaan rendah.
Adakah menjalankan sebagai pengguna bukan-root menggantikan firewall?
Tidak. Ia melindungi perkara yang berbeza. Menjalankan sebagai pengguna tanpa keistimewaan mengehadkan apa yang boleh dilakukan oleh servis jika ia dicerobohi, manakala firewall mengehadkan apa yang boleh mencapai servis tersebut. Gunakan kedua-duanya, bersama-sama dengan SSH yang diperkukuh, supaya setiap lapisan meliputi apa yang tidak dapat dilindungi oleh lapisan lain.
Fail manakah yang patut dimiliki oleh pengguna servis?
Hanya fail yang benar-benar diperlukan oleh servis, dan tiada yang lain. Berikan akaun tersebut hak milik ke atas direktori kerjanya sendiri dan datanya, dan biarkan segala-galanya dimiliki oleh root. Corak yang baik ialah sudo chown -R svc-app:svc-app /opt/svc-app untuk direktori aplikasi, manakala konfigurasi di bawah /etc kekal dimiliki oleh root dan hanya boleh dibaca oleh servis tersebut. Matlamatnya adalah jika proses tersebut pernah dicerobohi, fail yang boleh diubahnya terhad kepada datanya sendiri, bukan seluruh sistem.