Data from journald may be stored in volatile memory or persisted locally.
Utilities exist to accept remote export of journald logs.
Rationale
Storing log data on a remote host protects log integrity from local attacks. If an attacker gains root access on the local system, they could tamper with or remove log data that is stored on the local system.
- name: Ensure journald is configured to send logs to rsyslog - Search for a section
in files
ansible.builtin.find:
paths: '{{item.path}}'
patterns: '{{item.pattern}}'
contains: ^\s*\[Journal\]
read_whole_file: true
use_regex: true
register: systemd_dropin_files_with_section
loop:
- path: '{{ ''/etc/systemd/journald.conf'' | dirname }}'
pattern: '{{ ''/etc/systemd/journald.conf'' | basename | regex_escape }}'
- path: /etc/systemd/journald.conf.d
pattern: .*\.conf
when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
tags:
- journald_forward_to_syslog
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure journald is configured to send logs to rsyslog - Count number of files
which contain the correct section
ansible.builtin.set_fact:
count_of_systemd_dropin_files_with_section: '{{systemd_dropin_files_with_section.results
| map(attribute=''matched'') | list | map(''int'') | sum}}'
when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
tags:
- journald_forward_to_syslog
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure journald is configured to send logs to rsyslog - Add missing configuration
to correct section
ini_file:
path: '{{item}}'
section: Journal
option: ForwardToSyslog
value: 'yes'
state: present
no_extra_spaces: true
when:
- ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
- count_of_systemd_dropin_files_with_section | int > 0
loop: '{{systemd_dropin_files_with_section.results | sum(attribute=''files'', start=[])
| map(attribute=''path'') | list }}'
tags:
- journald_forward_to_syslog
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure journald is configured to send logs to rsyslog - Add configuration
to new remediation file
ini_file:
path: /etc/systemd/journald.conf.d/complianceascode_hardening.conf
section: Journal
option: ForwardToSyslog
value: 'yes'
state: present
no_extra_spaces: true
create: true
when:
- ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
- count_of_systemd_dropin_files_with_section | int == 0
tags:
- journald_forward_to_syslog
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
Remediation - Shell Script
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then
found=false
# set value in all files if they contain section or key
for f in $(echo -n "/etc/systemd/journald.conf.d/complianceascode_hardening.conf /etc/systemd/journald.conf.d/*.conf /etc/systemd/journald.conf"); do
if [ ! -e "$f" ]; then
continue
fi
# find key in section and change value
if grep -qzosP "[[:space:]]*\[Journal\]([^\n\[]*\n+)+?[[:space:]]*ForwardToSyslog" "$f"; then
sed -i "s/ForwardToSyslog[^(\n)]*/ForwardToSyslog=yes/" "$f"
found=true
# find section and add key = value to it
elif grep -qs "[[:space:]]*\[Journal\]" "$f"; then
sed -i "/[[:space:]]*\[Journal\]/a ForwardToSyslog=yes" "$f"
found=true
fi
done
# if section not in any file, append section with key = value to FIRST file in files parameter
if ! $found ; then
file=$(echo "/etc/systemd/journald.conf.d/complianceascode_hardening.conf /etc/systemd/journald.conf.d/*.conf /etc/systemd/journald.conf" | cut -f1 -d ' ')
mkdir -p "$(dirname "$file")"
echo -e "[Journal]\nForwardToSyslog=yes" >> "$file"
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi