mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-06-10 18:15:39 +00:00
Merge 049bf53f64 into 877f20f278
This commit is contained in:
commit
099de8ecfe
3 changed files with 76 additions and 1 deletions
2
changelogs/fragments/sudoers-defaults.yml
Normal file
2
changelogs/fragments/sudoers-defaults.yml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
minor_changes:
|
||||
- sudoers - add ``defaults`` parameter to allow specifying ``Defaults`` directives scoped to the user or group in the generated sudoers file (https://github.com/ansible-collections/community.general/pull/12186).
|
||||
|
|
@ -87,6 +87,16 @@ options:
|
|||
- The name of the user for the sudoers rule.
|
||||
- This option cannot be used in conjunction with O(group).
|
||||
type: str
|
||||
defaults:
|
||||
description:
|
||||
- A list of C(Defaults) directives to include in the sudoers rule file.
|
||||
- Each entry is written as a C(Defaults) line scoped to the user or group specified in the rule.
|
||||
- For example, V(!targetpw) becomes C(Defaults:%group !targetpw) for a group rule
|
||||
or C(Defaults:user !targetpw) for a user rule.
|
||||
- The directives are placed before the privilege rule in the generated file.
|
||||
type: list
|
||||
elements: str
|
||||
version_added: 13.1.0
|
||||
validation:
|
||||
description:
|
||||
- If V(absent), the sudoers rule is added without validation.
|
||||
|
|
@ -154,6 +164,15 @@ EXAMPLES = r"""
|
|||
user: alice
|
||||
commands: /usr/bin/less
|
||||
noexec: true
|
||||
|
||||
- name: Allow members of the operators group to sudo with their user password, overriding targetpw default
|
||||
community.general.sudoers:
|
||||
name: operators
|
||||
group: operators
|
||||
commands: ALL
|
||||
nopassword: false
|
||||
defaults:
|
||||
- "!targetpw"
|
||||
"""
|
||||
|
||||
import os
|
||||
|
|
@ -180,6 +199,7 @@ class Sudoers:
|
|||
self.sudoers_path = module.params["sudoers_path"]
|
||||
self.file = os.path.join(self.sudoers_path, self.name)
|
||||
self.commands = module.params["commands"]
|
||||
self.defaults = module.params["defaults"]
|
||||
self.validation = module.params["validation"]
|
||||
|
||||
def write(self):
|
||||
|
|
@ -215,12 +235,18 @@ class Sudoers:
|
|||
elif self.group:
|
||||
owner = f"%{self.group}"
|
||||
|
||||
if self.defaults:
|
||||
defaults_lines = [f"Defaults:{owner} {d}" for d in self.defaults]
|
||||
defaults_str = "\n".join(defaults_lines) + "\n"
|
||||
else:
|
||||
defaults_str = ""
|
||||
|
||||
commands_str = ", ".join(self.commands)
|
||||
noexec_str = "NOEXEC:" if self.noexec else ""
|
||||
nopasswd_str = "NOPASSWD:" if self.nopassword else ""
|
||||
setenv_str = "SETENV:" if self.setenv else ""
|
||||
runas_str = f"({self.runas})" if self.runas is not None else ""
|
||||
return f"{owner} {self.host}={runas_str}{noexec_str}{nopasswd_str}{setenv_str} {commands_str}\n"
|
||||
return f"{defaults_str}{owner} {self.host}={runas_str}{noexec_str}{nopasswd_str}{setenv_str} {commands_str}\n"
|
||||
|
||||
def validate(self):
|
||||
if self.validation == "absent":
|
||||
|
|
@ -261,6 +287,10 @@ def main():
|
|||
"type": "list",
|
||||
"elements": "str",
|
||||
},
|
||||
"defaults": {
|
||||
"type": "list",
|
||||
"elements": "str",
|
||||
},
|
||||
"group": {},
|
||||
"name": {
|
||||
"required": True,
|
||||
|
|
|
|||
|
|
@ -173,6 +173,39 @@
|
|||
src: "{{ sudoers_path }}/my-sudo-rule-9"
|
||||
register: rule_9_contents
|
||||
|
||||
- name: Create rule with defaults directives for a group
|
||||
community.general.sudoers:
|
||||
name: my-sudo-rule-10
|
||||
state: present
|
||||
group: operators
|
||||
commands: ALL
|
||||
nopassword: false
|
||||
defaults:
|
||||
- "!targetpw"
|
||||
register: rule_10
|
||||
|
||||
- name: Grab contents of my-sudo-rule-10
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ sudoers_path }}/my-sudo-rule-10"
|
||||
register: rule_10_contents
|
||||
|
||||
- name: Create rule with defaults directives for a user
|
||||
community.general.sudoers:
|
||||
name: my-sudo-rule-11
|
||||
state: present
|
||||
user: alice
|
||||
commands: ALL
|
||||
nopassword: false
|
||||
defaults:
|
||||
- "!targetpw"
|
||||
- "env_reset"
|
||||
register: rule_11
|
||||
|
||||
- name: Grab contents of my-sudo-rule-11
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ sudoers_path }}/my-sudo-rule-11"
|
||||
register: rule_11_contents
|
||||
|
||||
- name: Revoke rule 1
|
||||
community.general.sudoers:
|
||||
name: my-sudo-rule-1
|
||||
|
|
@ -261,6 +294,14 @@
|
|||
- revoke_non_existing_rule is not changed
|
||||
|
||||
- name: Check contents
|
||||
vars:
|
||||
expected_result_rule10: |
|
||||
Defaults:%operators !targetpw
|
||||
%operators ALL= ALL
|
||||
expected_result_rule11: |
|
||||
Defaults:alice !targetpw
|
||||
Defaults:alice env_reset
|
||||
alice ALL= ALL
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "rule_1_contents['content'] | b64decode == 'alice ALL=NOPASSWD: /usr/local/bin/command\n'"
|
||||
|
|
@ -272,6 +313,8 @@
|
|||
- "rule_7_contents['content'] | b64decode == 'alice host-1=NOPASSWD: /usr/local/bin/command\n'"
|
||||
- "rule_8_contents['content'] | b64decode == 'alice ALL=NOPASSWD:SETENV: /usr/local/bin/command\n'"
|
||||
- "rule_9_contents['content'] | b64decode == 'alice ALL=NOEXEC:NOPASSWD: /usr/local/bin/command\n'"
|
||||
- "rule_10_contents['content'] | b64decode == expected_result_rule10"
|
||||
- "rule_11_contents['content'] | b64decode == expected_result_rule11"
|
||||
|
||||
- name: Check revocation stat
|
||||
ansible.builtin.assert:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue