From 9963be4d28c21fbcad6d75be6d1ca49cf934419c Mon Sep 17 00:00:00 2001 From: Rich Megginson Date: Tue, 16 Jul 2024 10:55:50 -0600 Subject: [PATCH] feat: add support for file and directory mode/owner/group for output files Feature: Add support for specifying the mode, owner, and group for files and directories created by `logging_output` type `files`. The new variables are `mode`, `owner`, `group`, `dir_mode`, `dir_owner`, `dir_group` and these correspond to the Ansible `file` et. al. modules parameters. Reason: Users must be able to set ownership/permissions for files and directories created by rsyslog. Result: Users are able to set ownership/permissions for files and directories created by rsyslog. Signed-off-by: Rich Megginson --- README.md | 27 +++++++++++++-- roles/rsyslog/templates/output_files.j2 | 38 +++++++++++++++++++++ tests/tests_files_files.yml | 44 ++++++++++++++++++++++++- 3 files changed, 105 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1d51387c..87e3c56e 100644 --- a/README.md +++ b/README.md @@ -285,9 +285,19 @@ Available options: * `property_op`: Operation in property-based filter; In case of not `!`, put the `property_op` value in quotes; default to `contains` * `property_value`: Value in property-based filter; default to `error` * `path`: Path to the output file. - -logging_files_template_format: Set default template for the files output. -Allowed values are `traditional`, `syslog`, and `modern`. Default to `modern`. +* `logging_files_template_format`: Set default template for the files output. + Allowed values are `traditional`, `syslog`, and `modern`. Default to `modern`. +* File/Directory properties - same as corresponding variables of the Ansible `file` module: + * `mode` - sets the rsyslog `omfile` module `FileCreateMode` parameter + * `owner` - sets the rsyslog `omfile` module `fileOwner` or `fileOwnerNum` parameter. If the value + is an integer, set `fileOwnerNum`, otherwise, set `fileOwner`. + * `group` - sets the rsyslog `omfile` module `fileGroup` or `fileGroupNum` parameter. If the value + is an integer, set `fileGroupNum`, otherwise, set `fileGroup`. + * `dir_mode` - sets the rsyslog `omfile` module `DirCreateMode` parameter + * `dir_owner` - sets the rsyslog `omfile` module `dirOwner` or `dirOwnerNum` parameter. If the value + is an integer, set `dirOwnerNum`, otherwise, set `dirOwner`. + * `dir_group` - sets the rsyslog `omfile` module `dirGroup` or `dirGroupNum` parameter. If the value + is an integer, set `dirGroupNum`, otherwise, set `dirGroup`. **Note:** Selector options and property-based filter options are exclusive. If Property-based filter options are defined, selector options will be ignored. @@ -645,6 +655,7 @@ Deploying `basics input` reading logs from systemd unix socket and `files output ``` Deploying `basics input` reading logs from systemd journal and `files output` to write to the individually configured local files. +This also shows how to specify ownership/permission for log files/directories created by the logger. ```yaml --- @@ -670,6 +681,16 @@ Deploying `basics input` reading logs from systemd journal and `files output` to type: files facility: authpriv,auth path: /var/log/secure + - name: files_output2 + type: files + severity: info + path: /var/log/myapp/my_app.log + mode: "0600" + owner: logowner + group: loggroup + dir_mode: "0700" + dir_owner: logowner + dir_group: loggroup logging_flows: - name: flow0 inputs: [system_input] diff --git a/roles/rsyslog/templates/output_files.j2 b/roles/rsyslog/templates/output_files.j2 index b725cebc..ce21484e 100644 --- a/roles/rsyslog/templates/output_files.j2 +++ b/roles/rsyslog/templates/output_files.j2 @@ -1,3 +1,39 @@ +{% macro print_file_attrs(__rsyslog_output) %} +{% if __rsyslog_output.mode is defined %} + $FileCreateMode {{ __rsyslog_output.mode }} +{% endif %} +{% if __rsyslog_output.dir_mode is defined %} + $DirCreateMode {{ __rsyslog_output.dir_mode }} +{% endif %} +{% if __rsyslog_output.owner is defined %} +{% if __rsyslog_output.owner is match("^[0-9]+$") %} + $fileOwnerNum {{ __rsyslog_output.owner }} +{% else %} + $fileOwner {{ __rsyslog_output.owner }} +{% endif %} +{% endif %} +{% if __rsyslog_output.dir_owner is defined %} +{% if __rsyslog_output.dir_owner is match("^[0-9]+$") %} + $dirOwnerNum {{ __rsyslog_output.dir_owner }} +{% else %} + $dirOwner {{ __rsyslog_output.dir_owner }} +{% endif %} +{% endif %} +{% if __rsyslog_output.group is defined %} +{% if __rsyslog_output.group is match("^[0-9]+$") %} + $fileGroupNum {{ __rsyslog_output.group }} +{% else %} + $fileGroup {{ __rsyslog_output.group }} +{% endif %} +{% endif %} +{% if __rsyslog_output.dir_group is defined %} +{% if __rsyslog_output.dir_group is match("^[0-9]+$") %} + $dirGroupNum {{ __rsyslog_output.dir_group }} +{% else %} + $dirGroup {{ __rsyslog_output.dir_group }} +{% endif %} +{% endif %} +{% endmacro %} {% if __rsyslog_output.path is defined %} {% if __rsyslog_output.queue is defined %} ruleset(name="{{ __rsyslog_output.name }}" @@ -5,6 +41,7 @@ ruleset(name="{{ __rsyslog_output.name }}" {% else %} ruleset(name="{{ __rsyslog_output.name }}") { {% endif %} +{{ print_file_attrs(__rsyslog_output) -}} {% if __rsyslog_output.property | d() %} :{{ __rsyslog_output.property }}, {{ __rsyslog_output.property_op | d('contains') }}, "{{ __rsyslog_output.property_value | d('error') }}" {{ __rsyslog_output.path }} {% elif __rsyslog_output.exclude | d([]) %} @@ -25,6 +62,7 @@ ruleset(name="{{ __rsyslog_output.name }}") { kern.* /dev/console # Log anything (except mail) of level info or higher. # Don't log private authentication messages! +{{ print_file_attrs(__rsyslog_output) -}} *.info;mail.none;authpriv.none;cron.none {{ __rsyslog_system_log_dir }}/messages # The authpriv file has restricted access. authpriv.* {{ __rsyslog_system_log_dir }}/secure diff --git a/tests/tests_files_files.yml b/tests/tests_files_files.yml index b7e07a2d..3b9aebe4 100644 --- a/tests/tests_files_files.yml +++ b/tests/tests_files_files.yml @@ -35,11 +35,20 @@ __test_inputfiles_conf1: /etc/rsyslog.d/90-input-files-php:.conf __test_inputfiles_conf2: /etc/rsyslog.d/90-input-files-files_input2.conf __test_outputfiles_conf: /etc/rsyslog.d/30-output-files-files_output0.conf + __test_outputfiles1_conf: /etc/rsyslog.d/30-output-files-files_output1.conf + __test_outputfiles2_conf: /etc/rsyslog.d/30-output-files-files_output2.conf __default_system_log: /var/log/messages __test_outputfiles_module_conf: /etc/rsyslog.d/10-output-files-modules.conf __test_template: RSYSLOG_TraditionalFileFormat tasks: + - name: Create tempdir for tests + tempfile: + prefix: logging_ + suffix: _lsr + state: directory + register: __logging_tmpdir + # TEST CASE 0 - name: "TEST CASE 0; Ensure that the role runs with parameters from two files inputs to two files outputs" @@ -59,6 +68,16 @@ type: files facility: authpriv,auth path: /var/log/secure + - name: files_output2 + type: files + severity: info + path: "{{ __logging_tmpdir.path }}/test2/test.log" + mode: "0660" + owner: 0 + group: root + dir_mode: "0770" + dir_owner: root + dir_group: 0 logging_inputs: - name: files_input0 type: files @@ -88,12 +107,14 @@ - name: Ensure config file size and counts vars: - __conf_count: 8 + __conf_count: 9 __conf_size: less __conf_files: - "{{ __test_inputfiles_conf0 }}" - "{{ __test_inputfiles_conf1 }}" - "{{ __test_outputfiles_conf }}" + - "{{ __test_outputfiles1_conf }}" + - "{{ __test_outputfiles2_conf }}" __check_systemctl_status: true include_tasks: tasks/check_daemon_config_files.yml @@ -155,6 +176,22 @@ - tag="php:" - reopenOnTruncate="off" + - name: Check files_output2 + lineinfile: + path: "{{ __test_outputfiles2_conf }}" + line: " {{ item }}" + state: present + check_mode: true + register: _result + failed_when: _result.changed + loop: + - "$FileCreateMode 0660" + - "$DirCreateMode 0770" + - "$fileOwnerNum 0" + - "$dirOwner root" + - "$fileGroup root" + - "$dirGroupNum 0" + - name: Check ports managed by firewall and selinux include_tasks: tasks/check_firewall_selinux.yml @@ -168,6 +205,11 @@ name: linux-system-roles.logging public: true + - name: Remove tempdir + file: + path: "{{ __logging_tmpdir.path }}" + state: absent + # notify Restart rsyslogd is executed at the end of this test task. # thus we have to force to invoke handlers - name: "Force all notified handlers to run at this point,