Przejdź do treści

Konfiguracja journald - journald.conf

Wprowadzenie

Plik journald.conf to główny plik konfiguracyjny dla systemowego dziennika journald. Określa on wszystkie aspekty działania dziennika systemowego - od sposobu przechowywania logów, przez ich rotację, aż po kompresję i limity rozmiaru.

Lokalizacja pliku konfiguracyjnego

Konfiguracja journald znajduje się w kilku możliwych lokalizacjach, które są sprawdzane w następującej kolejności:

  1. /etc/systemd/journald.conf.d/*.conf - fragmenty konfiguracji w katalogu
  2. /etc/systemd/journald.conf - główny plik konfiguracyjny
  3. /usr/local/lib/systemd/journald.conf.d/*.conf - lokalne fragmenty konfiguracji
  4. /usr/lib/systemd/journald.conf.d/*.conf - systemowe fragmenty konfiguracji
  5. /etc/systemd/journald@NAMESPACE.conf - konfiguracja dla konkretnej przestrzeni nazw
  6. /etc/systemd/journald@NAMESPACE.conf.d/*.conf - fragmenty konfiguracji dla przestrzeni nazw
  7. /usr/local/lib/systemd/journald@NAMESPACE.conf.d/*.conf - lokalne fragmenty dla przestrzeni nazw
  8. /usr/lib/systemd/journald@NAMESPACE.conf.d/*.conf - systemowe fragmenty dla przestrzeni nazw

Tradycyjnie, zalecam tworzenie własnych plików konfiguracyjnych w katalogu /etc/systemd/journald.conf.d/ z rozszerzeniem .conf, zamiast bezpośredniej modyfikacji głównego pliku konfiguracyjnego.

Format pliku konfiguracyjnego

Plik journald.conf używa standardowego formatu plików konfiguracyjnych używanych przez systemd:

[Journal]
Storage=auto
Compress=yes

Wszystkie opcje konfiguracyjne znajdują się w sekcji [Journal].


Dostępne opcje konfiguracyjne

Poniżej przedstawiam wiekszość dostępnych opcji konfiguracyjnych w ostatniej wersji journald:

Opcje przechowywania danych

Storage=

Określa sposób przechowywania komunikatów dziennika:

  • volatile - przechowywanie tylko w pamięci (w /run/log/journal/)
  • persistent - przechowywanie na dysku (w /var/log/journal/)
  • auto - przechowywanie na dysku, jeśli katalog /var/log/journal/ istnieje, w przeciwnym razie w pamięci (domyślne)
  • none - brak przechowywania, wszystkie komunikaty są odrzucane
Storage=persistent

Compress=

Określa, czy zapisywane dane mają być kompresowane w celu oszczędzania miejsca:

  • yes - włącza kompresję (domyślne)
  • no - wyłącza kompresję
Compress=yes

CompressionLevel=

Poziom kompresji w skali od 1 (najniższa, najszybsza) do 9 (najwyższa, najwolniejsza), lub od -1 (domyślna) do 0 (brak):

CompressionLevel=6

Seal=

Określa, czy pliki dziennika powinny być zabezpieczone kryptograficznie:

  • yes - włącza zabezpieczenie (domyślne, jeśli dostępne są narzędzia kryptograficzne)
  • no - wyłącza zabezpieczenie
Seal=yes
Jak to działa?
Gdy Seal=yes, systemd używa kryptografii klucza publicznego (FSS - Forward Secure Sealing), aby:

- podpisywać logi - każdy wpis w dzienniku jest uwierzytelniany
- zabezpieczać przed zmianami - jeśli ktoś zmodyfikuje plik logu, system wykryje manipulację
- zapewniać integralność czasową - logi są chronione przed cofaniem czasu (backdating)

SplitMode=

Określa, jak dzielić pliki dziennika:

  • uid - tworzy oddzielne pliki dla każdego użytkownika
  • login - tworzy oddzielne pliki dla każdej sesji logowania
  • none - przechowuje wszystkie logi w jednym pliku (domyślne)
SplitMode=uid

Opcje ograniczające rozmiar dziennika

SystemMaxUse=, SystemKeepFree=

Określają maksymalną ilość miejsca na dysku dla dzienników systemowych (globalnych) oraz ilość wolnego miejsca, które powinno pozostać dostępne:

SystemMaxUse=10G
SystemKeepFree=15%

SystemMaxFileSize=

Maksymalny rozmiar pojedynczego pliku dziennika systemowego:

SystemMaxFileSize=100M

SystemMaxFiles=

Maksymalna liczba plików dziennika systemowego:

SystemMaxFiles=100

RuntimeMaxUse=, RuntimeKeepFree=

Określają maksymalną ilość miejsca w pamięci (/run) dla dzienników oraz ilość wolnego miejsca, które powinno pozostać dostępne:

RuntimeMaxUse=10%
RuntimeKeepFree=30%

RuntimeMaxFileSize=

Maksymalny rozmiar pojedynczego pliku dziennika w pamięci:

RuntimeMaxFileSize=100M

RuntimeMaxFiles=

Maksymalna liczba plików dziennika w pamięci:

RuntimeMaxFiles=100

MaxFileSec=

Maksymalny czas, przez jaki komunikaty są przechowywane w pojedynczym pliku dziennika przed rozpoczęciem rotacji:

MaxFileSec=1month

MaxRetentionSec=

Maksymalny czas przechowywania komunikatów dziennika (niezależnie od innych limitów):

MaxRetentionSec=1year

Opcje kontroli dostępu i polityki przesyłania

ForwardToSyslog=, ForwardToKMsg=, ForwardToConsole=, ForwardToWall=

Opcje określające, czy dziennik powinien przekazywać komunikaty do innych systemów logowania:

ForwardToSyslog=yes   # Przekazywanie do tradycyjnego syslog
ForwardToKMsg=no      # Przekazywanie do bufora kmsg jądra
ForwardToConsole=no   # Przekazywanie na konsolę
ForwardToWall=yes     # Przekazywanie do wszystkich zalogowanych użytkowników (wall)

MaxLevelStore=, MaxLevelSyslog=, MaxLevelKMsg=, MaxLevelConsole=, MaxLevelWall=

Określają maksymalny poziom ważności komunikatów przechowywanych lub przekazywanych do poszczególnych systemów:

MaxLevelStore=debug
MaxLevelSyslog=info
MaxLevelKMsg=notice
MaxLevelConsole=info
MaxLevelWall=emerg

Dostępne poziomy (od najniższego do najwyższego): debug, info, notice, warning, err, crit, alert, emerg

Opcje formatowania i identyfikacji

TTYPath=

Ścieżka do terminala, na który mają być wysyłane komunikaty dziennika:

TTYPath=/dev/console

LineMax=

Maksymalna długość linii komunikatu dziennika:

LineMax=48K

ReadKMsg=

Określa, czy komunikaty z bufora kmsg jądra mają być odczytywane i przechowywane:

ReadKMsg=yes

Audit=

Określa, czy system audytu jądra ma być używany:

Audit=yes

Opcje sieciowe

SyncIntervalSec=

Określa częstotliwość synchronizacji dziennika na dysk:

SyncIntervalSec=5m

RateLimitIntervalSec=, RateLimitBurst=

Opcje ograniczające liczbę komunikatów przyjmowanych w określonym czasie:

RateLimitIntervalSec=30s    # Okres czasu
RateLimitBurst=10000        # Maksymalna liczba komunikatów w okresie

SystemCallArchitectures=

Lista dozwolonych architektur wywołań systemowych:

SystemCallArchitectures=native
Jak to działa?
Parametr określający, które architektury wywołań systemowych są dozwolone dla danego procesu/kontenera.
native - oznacza, że proces może wykonywać tylko wywołania systemowe zgodne z architekturą systemu, na którym działa (np. x86_64, ARM64).

Każda operacja na poziomie jądra (np. otwarcie pliku, tworzenie procesu) wymaga wywołania systemowego.
Różne architektury procesorów (x86, ARM, RISC-V) mają różne numery i sposoby wywoływania syscalli.

Ograniczenie do native

Jeśli ustawisz SystemCallArchitectures=native, proces może używać tylko syscalli swojej architektury.
Próba wykonania syscalla z innej architektury (np. emulacja i386 na x86_64) zostanie zablokowana.

Przykładowo:

1. W systemd (np. dla usług/kontenerów)

[Service]
SystemCallArchitectures=native
RestrictAddressFamilies=AF_UNIX AF_INET

- blokuje wywołania systemowe spoza natywnej architektury
- powoduje uniemożliwienie exploitów wykorzystujących emulację

2. W Docker/Sandboxach

docker run --security-opt systemcalls=native ...

Kontener może wykonywać tylko syscalle zgodne z hostem (np. x86_64).

CapabilityBoundingSet=

Określa zestaw ograniczeń możliwości (capabilities) procesu journald:

CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ

MemoryDenyWriteExecute=

Zapobiega wykonywaniu kodu z obszarów pamięci ze znacznikiem do zapisu:

MemoryDenyWriteExecute=yes

SystemCallFilter=

Filtr wywołań systemowych, które są dozwolone lub zabronione:

SystemCallFilter=~@clock @cpu-emulation @debug @keyring @ipc @mount @obsolete @privileged @setuid

RestrictRealtime=

Zapobiega uzyskiwaniu priorytetów czasu rzeczywistego przez proces:

RestrictRealtime=yes
Co to oznacza?
Uniemożliwia procesowi (np. usłudze systemowej) ustawianie priorytetu czasu rzeczywistego (real-time scheduling) dla swoich wątków/zadań.

W Linuxie procesy mogą używać polityk planowania:

SCHED_OTHER (domyślna, współdzielony czas CPU),

SCHED_FIFO/SCHED_RR (czas rzeczywisty – proces ma wyższy priorytet niż nawet procesy jądra).

Dlaczego to ważne?
Bezpieczeństwo:
Proces z priorytetem SCHED_FIFO może zablokować cały system, jeśli wejdzie w nieskończoną pętlę (bo ma wyższy priorytet).

Atakujący mogą wykorzystać to do DoS (Denial of Service).

Stabilność:
Zapobiega przypadkowemu nadaniu RT przez błąd w oprogramowaniu.

Konfig w unit file

[Service]
RestrictRealtime=yes

Efekt: Proces usługi nie może użyć sched_setscheduler() do ustawienia SCHED_FIFO/SCHED_RR.

Jak sprawdzić priorytety procesów?

ps -eo pid,comm,cls,pri | grep -E 'FF|RR'  # wyświetli procesy RT
chrt -p <PID>                              # pokaże politykę planowania

RestrictNamespaces=

Ogranicza przestrzenie nazw, które mogą być tworzone:

RestrictNamespaces=yes
Co to oznacza?
Blokuje procesowi możliwość tworzenia nowych przestrzeni nazw (namespaces), które są podstawą konteneryzacji (Docker, LXC, podman).

Dotyczy m.in. tych przestrzeni:

PID (izolacja procesów),
NET (izolacja sieci),
UTS (izolacja hostname),
USER (izolacja UID/GID),

itd.

Dlaczego to ważne?

Tworzenie namespaces może być metodą ucieczki z kontenera (container breakout) lub eskalacji uprawnień.
Np. atakujący może próbować stworzyć nową przestrzeń PID/USER aby ominąć ograniczenia.

Zapobiega nieautoryzowanej konteneryzacji:
Jeśli usługa nie potrzebuje tworzyć kontenerów, możesz zablokować tę możliwość.

Konfig unit'a

[Service]
RestrictNamespaces=yes

Efekt: Wywołania takie jak unshare(2) lub clone(2) z flagami namespaces (CLONE_NEWPID, CLONE_NEWNET itd.) zostaną zablokowane.

Opcje szczegółowe
Można też blokować tylko wybrane przestrzenie nazw:

RestrictNamespaces=pid net user  # blokuje tylko te trzy

lub zezwalać na wszystkie:

RestrictNamespaces=no

Jak sprawdzić namespaces procesu?

ls -l /proc/<PID>/ns/  # lista przestrzeni nazw procesu

LockPersonality=

Zapobiega zmianie osobowości wykonywania:

LockPersonality=yes

SplitRoundRobin=

Włącza tryb rotacji dla podziału dzienników:

SplitRoundRobin=no

AutoFlush=

Określa, czy dane mają być automatycznie zapisywane na dysk w przypadku krytycznych błędów:

AutoFlush=yes

Weryfikacja konfiguracji

Po wprowadzeniu zmian w konfiguracji można je zastosować i zweryfikować:

Ponowne załadowanie konfiguracji

systemctl restart systemd-journald

Sprawdzenie statusu usługi

systemctl status systemd-journald

Sprawdzenie bieżących ustawień

journalctl -o json-pretty _SYSTEMD_UNIT=systemd-journald.service | less

Dobre praktyki

  1. Świadome ustalanie limitów - dopasuj limity rozmiaru dzienników do charakterystyki systemu
  2. Używanie kompresji - włącz kompresję nawet kosztem niewielkiego obciążenia CPU
  3. Zabezpieczenia - włącz opcję Seal=yes na serwerach produkcyjnych
  4. Przechowywanie - używaj Storage=persistent dla ważnych systemów
  5. Limity przepustowości - konfiguruj RateLimitIntervalSec i RateLimitBurst dla ochrony przed DoS
  6. Rotacja - ustaw odpowiednie wartości MaxRetentionSec i MaxFileSec do automatycznego zarządzania starymi dziennikami

Uwagi dla najnowszych wersji

W ostatnich wersjach journala (2024-2025) dodano szereg funkcji związanych z bezpieczeństwem, takich jak filtrowanie wywołań systemowych i ograniczenia możliwości. Te opcje pomagają zmniejszyć potencjalny wektor ataku.

[Journal]
MemoryDenyWriteExecute=yes
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG
SystemCallArchitectures=native
SystemCallFilter=~@mount @privileged @setuid
RestrictRealtime=yes
RestrictNamespaces=yes
LockPersonality=yes

Te ustawienia wzmacniają bezpieczeństwo procesu journald, ograniczając jego uprawnienia do niezbędnego minimum.

Podsumowanie

Konfiguracja journald oferuje wszechstronne możliwości dostosowania zachowania systemowego dziennika do różnych potrzeb - od małych systemów z ograniczonymi zasobami po duże serwery produkcyjne. Najnowsze wersje journald kładą szczególny nacisk na bezpieczeństwo i wydajność, dostarczając dodatkowych opcji konfiguracyjnych.

Właściwe skonfigurowanie journald pozwala na efektywne zarządzanie dziennikami systemowymi, jak i ich monitoringiem.