Cum auditezi și securizezi un serviciu Linux folosind systemd-analyze

systemd-analyze are două comenzi foarte utile pentru securizarea unui serviciu:

  • verify verifică sintaxa și problemele de configurare ale unității.
  • security analizează mecanismele de sandboxing și calculează un nivel de expunere. O valoare mai mică înseamnă, în general, mai puține privilegii și o izolare mai strictă.

Vom folosi serviciul fictiv myapp.service. Înlocuiește numele cu serviciul pe care vrei să îl verifici.

1. Verifică serviciul

Începe cu:

systemctl status myapp.service

Vezi configurația efectivă:

systemctl cat myapp.service

Și verifică proprietățile importante:

systemctl show myapp.service \
  -p User \
  -p Group \
  -p ExecStart \
  -p AmbientCapabilities \
  -p CapabilityBoundingSet \
  -p NoNewPrivileges

Scopul este să afli cu ce utilizator rulează serviciul, ce executabil pornește și ce privilegii primește.

2. Rulează auditul de securitate

systemd-analyze security --no-pager myapp.service

Vei primi o listă cu verificări de tipul:

NAME                         DESCRIPTION                         EXPOSURE
✗ User=/DynamicUser=         Service runs as root user            ...
✗ PrivateTmp=                Service has access to /tmp           ...
✓ ProtectSystem=             Service has limited filesystem       ...
...

La final apare nivelul general de expunere. Acest scor trebuie folosit ca instrument de audit, nu ca verdict absolut. systemd verifică mecanismele sale de izolare, nu securitatea internă a aplicației.

3. Verifică fișierul unității înainte de modificări

systemd-analyze verify /etc/systemd/system/myapp.service

Comanda poate identifica directive necunoscute, probleme de sintaxă și alte erori de configurare. Pentru unitățile existente, poți verifica și configurația instalată de distribuție:

systemd-analyze verify myapp.service

4. Rulează serviciul cu un utilizator dedicat

Un serviciu care nu are nevoie de privilegii administrative nu ar trebui să ruleze ca root.

Exemplu:

[Service]
User=myapp
Group=myapp

Verifică mai întâi că utilizatorul există:

id myapp

Separarea utilizatorului este una dintre primele măsuri de reducere a impactului unei eventuale compromiteri.

5. Activează NoNewPrivileges

Adaugă:

[Service]
NoNewPrivileges=yes

Această opțiune împiedică procesul și procesele sale copil să obțină privilegii suplimentare prin mecanisme precum setuid, setgid sau file capabilities. La nivel de kernel, flag-ul devine permanent pentru procesele care îl moștenesc.

6. Izolează filesystem-ul

O configurație uzuală pentru un serviciu care nu trebuie să modifice sistemul este:

[Service]
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes

ProtectSystem=strict face ierarhia filesystem-ului în principal read-only pentru serviciu. ProtectHome ascunde sau restricționează accesul la directoarele utilizatorilor. PrivateTmp oferă serviciului un spațiu separat pentru /tmp și /var/tmp.

Dacă aplicația trebuie să scrie într-un director precis, nu transforma întregul filesystem în writable. Permite doar acea zonă:

[Service]
ProtectSystem=strict
ReadWritePaths=/var/lib/myapp

7. Restricționează accesul la dispozitive

Pentru un serviciu obișnuit care nu are nevoie de dispozitive hardware:

[Service]
PrivateDevices=yes

Acest lucru reduce accesul procesului la dispozitivele sistemului.

8. Protejează interfața kernelului

Pentru servicii normale:

[Service]
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes

Ideea este ca procesul să nu poată modifica facilități ale kernelului sau configurația control groups de care nu are nevoie. Documentația systemd recomandă folosirea acestor mecanisme de sandboxing atunci când compatibilitatea aplicației permite acest lucru.

9. Limitează rețeaua

Dacă aplicația folosește numai conexiuni TCP/IP obișnuite și socketuri Unix:

[Service]
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6

Astfel limitezi familiile de adrese pe care procesul le poate folosi prin socket. Nu aplica această regulă unui serviciu înainte să verifici ce tipuri de socket folosește.

10. Limitează capabilities

Verifică mai întâi ce capabilities sunt necesare:

systemctl show myapp.service -p CapabilityBoundingSet

Dacă aplicația nu are nevoie de capabilities, acestea pot fi eliminate:

[Service]
CapabilityBoundingSet=
AmbientCapabilities=

Capability bounding set limitează capabilities care pot fi moștenite de procesele executate ulterior. Nu elimina capabilities necesare pentru operația normală a serviciului.

11. Aplică modificările printr-un drop-in

Pentru un serviciu instalat de distribuție, evită modificarea directă a fișierului original.

Folosește:

sudo systemctl edit myapp.service

Poți introduce, de exemplu:

[Service]
User=myapp
Group=myapp

NoNewPrivileges=yes

ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes

PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes

RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6

Acesta este un punct de pornire. Nu toate serviciile acceptă toate restricțiile.

12. Reîncarcă systemd

sudo systemctl daemon-reload

Apoi verifică din nou unitatea:

systemd-analyze verify myapp.service

13. Repornește serviciul

sudo systemctl restart myapp.service

Verifică imediat:

systemctl status myapp.service

Dacă serviciul nu mai pornește, consultă logurile:

journalctl -u myapp.service -b

Pentru urmărire live:

journalctl -u myapp.service -f

14. Rulează din nou auditul

systemd-analyze security --no-pager myapp.service

Compară rezultatul cu cel inițial.

Important: nu urmări doar reducerea scorului. O restricție care face serviciul inutilizabil nu este o îmbunătățire practică. Auditul trebuie să fie urmat de testarea funcționalității. systemd însuși recomandă activarea cât mai multor mecanisme de sandboxing fără a afecta funcționarea serviciului.

Workflow recomandat

systemctl cat
      ↓
systemd-analyze verify
      ↓
systemd-analyze security
      ↓
systemctl edit
      ↓
daemon-reload
      ↓
restart
      ↓
journalctl
      ↓
systemd-analyze security

Checklist rapid

[ ] Nu rulează ca root fără motiv
[ ] NoNewPrivileges=yes
[ ] ProtectSystem=strict
[ ] ProtectHome=yes
[ ] PrivateTmp=yes
[ ] PrivateDevices=yes
[ ] ProtectKernelTunables=yes
[ ] ProtectKernelModules=yes
[ ] ProtectControlGroups=yes
[ ] RestrictAddressFamilies configurat
[ ] Capabilities limitate
[ ] systemd-analyze verify trece
[ ] Serviciul funcționează după restart
[ ] Logurile nu arată erori
[ ] systemd-analyze security a fost rulat din nou

Auditarea cu systemd-analyze nu înseamnă doar să obții un scor. Procesul corect este:

identifici privilegiile → reduci suprafața de atac → verifici compatibilitatea → testezi serviciul → rulezi auditul din nou.

[mai mult...]

Cum rulezi containere Podman automat cu Quadlet și systemd

Quadlet îți permite să definești containere Podman în fișiere simple, iar systemd se ocupă de pornire, oprire și restart automat. Un fișier de tip .container este transformat de Podman într-un serviciu systemd.

1. Verifică Podman

Pe sistemul unde rulezi containerul:

podman --version
podman info --format '{{.Host.CgroupsVersion}}'

Quadlet necesită cgroups v2.

2. Creează directorul Quadlet

Pentru un container rootless, folosește:

mkdir -p ~/.config/containers/systemd

Acesta este unul dintre directoarele standard în care Quadlet caută configurațiile utilizatorului.

3. Creează definiția containerului

Exemplu: un server Nginx care ascultă pe portul 8080.

Creează fișierul:

nano ~/.config/containers/systemd/nginx.container

Conținut:

[Unit]
Description=NGINX container

[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80

[Service]
Restart=always

Cheia Image definește imaginea, iar PublishPort mapează portul 8080 al sistemului la portul 80 din container. Pentru imagine este recomandată folosirea unui nume complet calificat.

4. Reîncarcă systemd

systemctl --user daemon-reload

Quadlet generează serviciul systemd pornind de la fișierul .container.

5. Pornește containerul

systemctl --user start nginx.service

Verifică starea:

systemctl --user status nginx.service

Și verifică direct containerul:

podman ps

6. Testează aplicația

Pe aceeași mașină:

curl http://localhost:8080

Ar trebui să primești pagina implicită Nginx.

7. Pornește automat după restart

Pentru Quadlet nu este necesar să activezi manual serviciul generat cu systemctl enable. Pornirea automată se configurează în fișierul Quadlet prin secțiunea Install.

Modifică fișierul astfel:

[Unit]
Description=NGINX container

[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80

[Service]
Restart=always

[Install]
WantedBy=default.target

Apoi:

systemctl --user daemon-reload

Pentru un serviciu rootless care trebuie să ruleze și atunci când utilizatorul nu este autentificat, activează lingering:

sudo loginctl enable-linger $USER

Lingering permite instanței systemd a utilizatorului să rămână activă după logout și după reboot.

8. Vezi logurile

journalctl --user -u nginx.service

Pentru urmărire în timp real:

journalctl --user -u nginx.service -f

Podman recomandă journalctl pentru verificarea logurilor serviciilor Quadlet.

9. Dacă serviciul nu este găsit

Dacă primești o eroare de tip „Unit not found”, verifică generarea unității:

systemd-analyze --user --generators=true verify nginx.service

Pentru o analiză mai detaliată poți rula generatorul Quadlet în mod dry-run:

/usr/lib/systemd/system-generators/podman-system-generator --user --dryrun

Aceste comenzi ajută la identificarea erorilor de sintaxă sau a opțiunilor Quadlet incompatibile.

Fluxul de bază

În practică, ciclul este:

nginx.container
      ↓
systemd --user daemon-reload
      ↓
nginx.service
      ↓
podman run
      ↓
containerul rulează

Avantajul principal este că configurația containerului rămâne declarativă și este gestionată de systemd, inclusiv restartul și pornirea automată.

Rootless vs. rootful

Pentru rootless:

~/.config/containers/systemd/
systemctl --user
podman ps

Pentru rootful:

/etc/containers/systemd/
sudo systemctl
sudo podman ps

Directorul rootless și cel rootful sunt diferite, iar comenzile systemd trebuie executate în contextul corespunzător.

Pe scurt: scrii un fișier .container, îl pui în directorul Quadlet, rulezi daemon-reload, apoi gestionezi containerul cu systemctl. Asta elimină nevoia de scripturi separate pentru pornire și restart.

[mai mult...]

Cum repari problema de “High Encoding / Rendering Lag” (Sacadări și cadre pierdute) în OBS Studio

Această problemă apare atunci când computerul (procesorul sau placa video) este suprasolicitat în timpul înregistrării sau al unui stream. OBS nu reușește să randeze sau să encodeze cadrele la timp, ceea ce duce la imagini sacadate (lag), cadre pierdute din cauza suprasolicitării encoderului (Encoding Overloaded) sau a randării (Rendering Lag).

[mai mult...]