Günümüzde tüm büyük Linux dağıtımları Systemd’yi başlangıç sistemi/hizmet yöneticisi olarak benimsemiştir. Bir systemd hizmeti oluşturmak, uygun dizine bir “.service” birimi yazmak ve bunu systemctl yardımcı programını kullanarak yönetmek meselesidir. Bir hizmeti başlatırken veya genel olarak bir süreci başlatırken, görevi gerçekleştirmek için ihtiyaç duyduğu mümkün olan en düşük ayrıcalıklarla çalıştığından emin olmak istiyoruz. Systemd, bir hizmetin davranışına ince ayar yapmak, ayrıcalıkları ayrıntılı bir şekilde vermek veya reddetmek ve sistemin geri kalanından belirli bir düzeyde izolasyon sağlamak için kullanabileceğimiz bir dizi seçenek sunar.
Bu makalede, bir systemd hizmetinin güvenliğinin nasıl artırılacağını ve systemd-analyze yardımcı programını kullanarak maruz kalma düzeyine ilişkin bir tahminin nasıl alınacağını görüyoruz.
Bir test senaryosu: yedekleme hizmeti yazma
Bu makalenin amacına uygun olarak, systemd-timer aracılığıyla bir yedeklemeyi planlamak için servis yazmak istediğimizi varsayalım. “Birim” bölümünü yazarak başlıyoruz:
[Unit] Description=restic backup Wants=network-online.target After=network-online.target
İlk olarak Açıklama seçeneğini kullanarak bir hizmet açıklaması sağladık. Yedeklemelerimiz için uzak depoları kullanabilmek istediğimizden, İstekler ve Sonra seçeneklerini kullanarak sırasıyla hizmetin network-online.target’e (zayıf) bağımlılığını ilan ettik ve hizmetin ancak söylenenden sonra başlatılması gerektiğini belirledik. hedefe ulaşıldı ve ağ arayüzleri yapılandırıldı.
Şimdi ünitenin “Servis” bölümünü dolduralım. Hizmet davranışımızı burada tanımlıyoruz:
[Service] Type=oneshot User=restic ExecStart=/usr/local/bin/restic_backup.sh
Hizmetimizi “oneshot” olarak tanımlamak için “Type” seçeneğini kullandık. Bu, systemd’nin hizmete nasıl davrandığını etkiler: yalnızca ana süreç çıktıktan sonra onu “çalışıyor” olarak kabul eder.
Güvenlik açığı nedeniyle, hizmeti root olarak çalıştırmaktan kaçınmak istiyoruz, bu nedenle “restic” ayrıcalıksız kullanıcıyı oluşturduk ve Kullanıcı seçeneğiyle işlemin ayrıcalıklarıyla başlatılması gerektiğini belirttik. Son olarak ExecStart seçeneği ile servis başlatıldığında çağrılması gereken komutu/yürütülebilir dosyayı tanımladık; bu durumda ana yedekleme mantığını içeren /usr/local/bin/restic_backup.sh betiğidir.
Ünitenin “Hizmet” bölümünde, hizmetimizin ayrıcalıklarını daha da ayarlamak için diğer birçok seçeneği kullanabiliriz. Bunlardan bazılarını görelim.
Süreci yeteneklerle yürütmeHizmetimiz “restic” kullanıcısının ayrıcalıklarıyla çalışacaktır. Bu iyi bir güvenlik önlemidir, ancak restic’in tüm dosya sistemini okuyabildiğinden emin olmalıyız. Hedefimize ulaşmak için sürecin uygun yeteneklerle ilerlemesini sağlayabiliriz:
AmbientCapabilities=CAP_DAC_READ_SEARCH CapabilityBoundingSet=CAP_DAC_READ_SEARCH
AmbientCapability seçeneği, değer olarak sürecin ortam yetenek kümesine dahil etmek istediğimiz yeteneklerin virgülle ayrılmış listesini alır. Bu durumda, dosyaların ve dizinlerin okuma izni kontrollerini atlamaya izin veren “CAP_DAC_READ_SEARCH” özelliğini kullandık. Bir güvenlik önlemi olarak, sürecin elde etmesine izin verilen yetenek kümesini sınırlamak için CapabilityBoundingSet seçeneğini de kullandık.
Hizmeti Güvenli Hale Getirme
Yukarıda kullandığımız yeteneklerle ilgili iki seçenek, hizmeti “izole etmek” için kullanabileceğimiz seçeneklerin yalnızca küçük bir alt kümesidir. Çoğu bir boole değeri kabul eder. Hadi bazı örneklere bakalım.
PrivateTmp
“PrivateTmp” seçeneği, hizmet tarafından oluşturulan geçici dosyaları korur, böylece diğer işlemler bunlara erişemez. Seçenek etkin olduğunda, systemd yalıtılmış /tmp ve /var/tmp dizinleri oluşturur ve bunları özel bir ad alanına bağlar.
ProtectKernelModules, ProtectKernelLogs and ProtectKernelTunables
Bu seçenekler çekirdek durumunu korur. KorumaKernelModules etkin olduğunda hizmetin çekirdek modüllerini yükleme ve kaldırma yeteneğini reddeder, KorumaKernelLogs ise çekirdek günlük arabelleğine erişimi reddeder. Belirli çekirdek modüllerinin davranışı, /proc ve /sys sözde dosya sistemlerinde gösterilen dosyalara uygun değerler yazılarak değiştirilebilir; KorumaKernelTunables seçeneği etkin olduğunda bu tür eylemleri reddeder.
NoNewPrivileges
Bu seçenek, hizmetin ve alt işlemlerinin, standart C kitaplığının bir parçası olan execve sistem çağrısı aracılığıyla diğer programları çalıştırarak yeni ayrıcalıklar kazanamayacağından emin olmak için kullanılabilir. Bu seçenek aktif olduğunda, SETUID veya SETGID bitleri ayarlıyken ikili dosyaların yürütülmesini reddeder.
RestrictSUIDSGID
Bu seçenek doğru olduğunda, hizmet tarafından başlatılan işlemin dosyalar ve dizinler üzerinde SETUID veya SETGID bitlerini ayarlamasını engeller.
RestrictAddressFamilies
Bu seçenek, sürecin erişebileceği adres ailesi adlarının boşlukla ayrılmış listesini kabul eder (örneğin: AF_UNIX, AF_INET, AF_INET6); “Yok” da geçerli bir değerdir: hepsine erişimi reddeder.
PrivateDevices
Bu seçenek etkin olduğunda, /dev/sda veya /dev/mem gibi ham aygıtlara işlem erişimini reddeder.
ProtectClock
True olarak ayarlandığında sistem saatine erişimi reddeder.
ProtectHostname
Bu seçenek, sistemin ana bilgisayar adını koruyarak işlemin onu değiştirememesini sağlar.
RemoveIPC
Etkin olduğunda, hizmete tahsis edilen IPC (İşlemlerarası İletişim) kaynaklarının otomatik olarak kaldırılmasına neden olur.
PrivateMounts
Bu seçenek aktif olduğunda süreç, ana bilgisayardan erişilemeyen, kendi özel ve yalıtılmış dosya sisteminde çalışır.
Hizmetin tahmini güvenlik düzeyini elde etme
Sonunda hizmetimiz şu şekilde görünüyor:
[Unit] Description=restic backup Wants=network-online.target After=network-online.target [Service] Type=oneshot User=restic ExecStart=/usr/local/bin/restic_backup.sh AmbientCapabilities=CAP_DAC_READ_SEARCH CapabilityBoundingSet=CAP_DAC_READ_SEARCH PrivateTmp=yes ProtectKernelModules=yes ProtectKernelLogs=yes ProtectKernelTunables=yes NoNewPrivileges=yes RestrictSUIDSGID=yes RestrictAddressFamilies=yes PrivateDevices=yes ProtectClock=yes ProtectHostname=yes RemoveIPC=yes PrivateMounts=yes
Üniteyi systemd tarafından tanınan dizinlerden birine yerleştirdikten sonra (örneğin, /etc/systemd/system), tahmini güvenlik seviyesini elde etmek için, “security” komutuyla “systemd-analyze”yi başlatmamız yeterlidir. argüman olarak birim adı. Birimi “restic.service” olarak kaydettiğimizi varsayalım:
$ systemd-analyze security restic.service
Komut, ünitede mevcut olan ve olmayanları işaretleyerek mevcut güvenlik seçeneklerinin bir listesini ve genel maruz kalma düzeyini döndürür: bu ne kadar düşükse o kadar iyidir. Kullanılmayan her seçenek, maruz kalma değerini “POZLAMA” sütununda bildirilen miktar kadar artırır. Komutu servis birimimize karşı çalıştırdığımızda elde ettiğimiz çıktı şu şekildedir:
NAME DESCRIPTION EXPOSURE ✓ RemoveIPC= Service user cannot leave SysV IPC objects around ✗ RootDirectory=/RootImage= Service runs within the host's root directory 0.1 ✓ User=/DynamicUser= Service runs under a static non-root user identity ✓ CapabilityBoundingSet=~CAP_SYS_TIME Service processes cannot change the system clock ✓ NoNewPrivileges= Service processes cannot acquire new privileges ✗ AmbientCapabilities= Service process receives ambient capabilities 0.1 ✗ CapabilityBoundingSet=~CAP_(DAC_*|FOWNER|IPC_OWNER) Service may override UNIX file/IPC permission checks 0.2 ✗ ProtectControlGroups= Service may modify the control group file system 0.2 ✓ CapabilityBoundingSet=~CAP_BPF Service may load BPF programs ✗ SystemCallArchitectures= Service may execute system calls with all ABIs 0.2 ✗ MemoryDenyWriteExecute= Service may create writable executable memory mappings 0.1 ✗ RestrictNamespaces=~user Service may create user namespaces 0.3 ✗ RestrictNamespaces=~pid Service may create process namespaces 0.1 ✗ RestrictNamespaces=~net Service may create network namespaces 0.1 ✗ RestrictNamespaces=~uts Service may create hostname namespaces 0.1 ✗ RestrictNamespaces=~mnt Service may create file system namespaces 0.1 ✗ RestrictNamespaces=~cgroup Service may create cgroup namespaces 0.1 ✗ RestrictNamespaces=~ipc Service may create IPC namespaces 0.1 ✗ LockPersonality= Service may change ABI personality 0.1 ✗ RestrictRealtime= Service may acquire realtime scheduling 0.1 ✓ SupplementaryGroups= Service has no supplementary groups ✓ CapabilityBoundingSet=~CAP_SYS_RAWIO Service has no raw I/O access ✓ CapabilityBoundingSet=~CAP_SYS_PTRACE Service has no ptrace() debugging abilities ✓ CapabilityBoundingSet=~CAP_SYS_(NICE|RESOURCE) Service has no privileges to change resource use parameters ✓ CapabilityBoundingSet=~CAP_NET_ADMIN Service has no network configuration privileges ✓ CapabilityBoundingSet=~CAP_NET_(BIND_SERVICE|BROADCAST|RAW) Service has no elevated networking privileges ✓ CapabilityBoundingSet=~CAP_AUDIT_* Service has no audit subsystem access ✓ CapabilityBoundingSet=~CAP_SYS_ADMIN Service has no administrator privileges ✓ PrivateTmp= Service has no access to other software's temporary files ✓ CapabilityBoundingSet=~CAP_SYSLOG Service has no access to kernel logging ✓ PrivateDevices= Service has no access to hardware devices ✗ ProtectSystem= Service has full access to the OS file hierarchy 0.2 ✗ ProtectProc= Service has full access to process tree (/proc hidepid=) 0.2 ✗ ProcSubset= Service has full access to non-process /proc files (/proc subset=) 0.1 ✗ ProtectHome= Service has full access to home directories 0.2 ✗ PrivateNetwork= Service has access to the host's network 0.5 ✗ PrivateUsers= Service has access to other users 0.2 ✗ DeviceAllow= Service has a device ACL with some special devices: char-rtc:r 0.1 ✓ KeyringMode= Service doesn't share key material with other services ✓ Delegate= Service does not maintain its own delegated control group subtree ✗ SystemCallFilter=~@clock Service does not filter system calls 0.2 ✗ SystemCallFilter=~@cpu-emulation Service does not filter system calls 0.1 ✗ SystemCallFilter=~@debug Service does not filter system calls 0.2 ✗ SystemCallFilter=~@module Service does not filter system calls 0.2 ✗ SystemCallFilter=~@mount Service does not filter system calls 0.2 ✗ SystemCallFilter=~@obsolete Service does not filter system calls 0.1 ✗ SystemCallFilter=~@privileged Service does not filter system calls 0.2 ✗ SystemCallFilter=~@raw-io Service does not filter system calls 0.2 ✗ SystemCallFilter=~@reboot Service does not filter system calls 0.2 ✗ SystemCallFilter=~@resources Service does not filter system calls 0.2 ✗ SystemCallFilter=~@swap Service does not filter system calls 0.2 ✗ IPAddressDeny= Service does not define an IP address allow list 0.2 ✓ NotifyAccess= Service child processes cannot alter service state ✓ ProtectClock= Service cannot write to the hardware clock or system clock ✓ CapabilityBoundingSet=~CAP_SYS_PACCT Service cannot use acct() ✓ CapabilityBoundingSet=~CAP_KILL Service cannot send UNIX signals to arbitrary processes ✓ ProtectKernelLogs= Service cannot read from or write to the kernel log ring buffer ✓ CapabilityBoundingSet=~CAP_WAKE_ALARM Service cannot program timers that wake up the system ✓ CapabilityBoundingSet=~CAP_LINUX_IMMUTABLE Service cannot mark files immutable ✓ CapabilityBoundingSet=~CAP_IPC_LOCK Service cannot lock memory into RAM ✓ ProtectKernelModules= Service cannot load or read kernel modules ✓ CapabilityBoundingSet=~CAP_SYS_MODULE Service cannot load kernel modules ✓ CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG Service cannot issue vhangup() ✓ CapabilityBoundingSet=~CAP_SYS_BOOT Service cannot issue reboot() ✓ CapabilityBoundingSet=~CAP_SYS_CHROOT Service cannot issue chroot() ✓ PrivateMounts= Service cannot install system mounts ✓ CapabilityBoundingSet=~CAP_BLOCK_SUSPEND Service cannot establish wake locks ✓ CapabilityBoundingSet=~CAP_LEASE Service cannot create file leases ✓ CapabilityBoundingSet=~CAP_MKNOD Service cannot create device nodes ✓ ProtectHostname= Service cannot change system host/domainname ✓ CapabilityBoundingSet=~CAP_(CHOWN|FSETID|SETFCAP) Service cannot change file ownership/access mode/capabilities ✓ CapabilityBoundingSet=~CAP_SET(UID|GID|PCAP) Service cannot change UID/GID identities/capabilities ✓ ProtectKernelTunables= Service cannot alter kernel tunables (/proc/sys, …) ✓ RestrictAddressFamilies=~AF_PACKET Service cannot allocate packet sockets ✓ RestrictAddressFamilies=~AF_NETLINK Service cannot allocate netlink sockets ✓ RestrictAddressFamilies=~AF_UNIX Service cannot allocate local sockets ✓ RestrictAddressFamilies=~… Service cannot allocate exotic sockets ✓ RestrictAddressFamilies=~AF_(INET|INET6) Service cannot allocate Internet sockets ✓ CapabilityBoundingSet=~CAP_MAC_* Service cannot adjust SMACK MAC ✓ RestrictSUIDSGID= SUID/SGID file creation by service is restricted ✗ UMask= Files created by service are world-readable by default 0.1 → Overall exposure level for restic.service: 4.6 OK 🙂
Puanımız “4,6”: fena değil ama yine de artırabiliriz!
Yazının orijinalini buradan okuyabilirsiniz.
Kariyerime 26 yıl önce başladım. Windows ve Linux sistemlerinin kurulumu, yapılandırılması, yönetimi ve bakımı dahil olmak üzere birden fazla sistem üzerinde uzmanlaştım.
Açık kaynak dünyasındaki en son gelişmelerden haberdar olmaktan ve Linux hakkındaki en son araçları, özellikleri ve hizmetleri denemekten hoşlanıyorum.
Son 6 yıldır sistem ve ağ yöneticisi olarak görev yapıyorum ayrıca Pardus Dönüşüm Projesini yönetiyorum ve Pardus İşletim Sisteminin yaygınlaşması adına uğraş gösteriyorum.
Boş zamanlarımda açık kaynaklı uygulamaların Türkçe çevirisine katılıyorum ve The Document Foundation üyesiyim.