From 2d1e58663c510e1cb4c90744102a657afed0bbc4 Mon Sep 17 00:00:00 2001 From: Jon Ellis Date: Sun, 12 Jun 2022 07:17:56 +0100 Subject: [PATCH] Ensure managed sudoers config files have 0440 permissions (#4814) * Ensure sudoers config files are created with 0440 permissions to appease visudo validation * Remove change not required by the bugfix * Add changelog fragment for 4814 sudoers file permissions * Update changelogs/fragments/4814-sudoers-file-permissions.yml Co-authored-by: Felix Fontein * Have less oct casting Co-authored-by: Felix Fontein Co-authored-by: Felix Fontein --- .../fragments/4814-sudoers-file-permissions.yml | 2 ++ plugins/modules/system/sudoers.py | 11 ++++++++++- tests/integration/targets/sudoers/tasks/main.yml | 12 ++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/4814-sudoers-file-permissions.yml diff --git a/changelogs/fragments/4814-sudoers-file-permissions.yml b/changelogs/fragments/4814-sudoers-file-permissions.yml new file mode 100644 index 0000000000..be24e12e6e --- /dev/null +++ b/changelogs/fragments/4814-sudoers-file-permissions.yml @@ -0,0 +1,2 @@ +bugfixes: + - sudoers - ensure sudoers config files are created with the permissions requested by sudoers (0440) (https://github.com/ansible-collections/community.general/pull/4814). diff --git a/plugins/modules/system/sudoers.py b/plugins/modules/system/sudoers.py index 86d8306c26..8b8ad50405 100644 --- a/plugins/modules/system/sudoers.py +++ b/plugins/modules/system/sudoers.py @@ -115,6 +115,8 @@ from ansible.module_utils.common.text.converters import to_native class Sudoers(object): + FILE_MODE = 0o440 + def __init__(self, module): self.check_mode = module.check_mode self.name = module.params['name'] @@ -134,6 +136,8 @@ class Sudoers(object): with open(self.file, 'w') as f: f.write(self.content()) + os.chmod(self.file, self.FILE_MODE) + def delete(self): if self.check_mode: return @@ -145,7 +149,12 @@ class Sudoers(object): def matches(self): with open(self.file, 'r') as f: - return f.read() == self.content() + content_matches = f.read() == self.content() + + current_mode = os.stat(self.file).st_mode & 0o777 + mode_matches = current_mode == self.FILE_MODE + + return content_matches and mode_matches def content(self): if self.user: diff --git a/tests/integration/targets/sudoers/tasks/main.yml b/tests/integration/targets/sudoers/tasks/main.yml index 9a632c4de4..634eded779 100644 --- a/tests/integration/targets/sudoers/tasks/main.yml +++ b/tests/integration/targets/sudoers/tasks/main.yml @@ -29,6 +29,11 @@ commands: /usr/local/bin/command register: rule_1 +- name: Stat my-sudo-rule-1 file + ansible.builtin.stat: + path: "{{ sudoers_path }}/my-sudo-rule-1" + register: rule_1_stat + - name: Grab contents of my-sudo-rule-1 ansible.builtin.slurp: src: "{{ sudoers_path }}/my-sudo-rule-1" @@ -132,6 +137,13 @@ # Run assertions +- name: Check rule 1 file stat + ansible.builtin.assert: + that: + - rule_1_stat.stat.exists + - rule_1_stat.stat.isreg + - rule_1_stat.stat.mode == '0440' + - name: Check changed status ansible.builtin.assert: that: