Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
278 changes: 278 additions & 0 deletions meta/argument_specs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
# SPDX-License-Identifier: MIT
---
argument_specs:
main:
short_description: The sudo role.
description: >
The sudo role configures sudo by managing sudoers files.
It can manage the main `/etc/sudoers` file as well as
additional files in included directories such as
`/etc/sudoers.d`. The role supports configuring defaults,
user specifications, aliases, default overrides, and
include directives.
options:
sudo_rewrite_default_sudoers_file:
type: bool
default: true
description: >
Whether to overwrite the distribution-supplied
`/etc/sudoers` file with the role configuration.
Set to `false` to deploy only to included directories
without modifying `/etc/sudoers`.
sudo_remove_unauthorized_included_files:
type: bool
default: false
description: >
Whether to remove existing sudoers files in the
configured include directories that are not defined
in `sudo_sudoers_files`. This enforces a desired
state but is potentially dangerous.
sudo_check_if_configured:
type: bool
default: true
description: >
Whether to perform a semantic check of the already
configured sudoers and skip the role if the
configuration matches.
sudo_visudo_path:
type: path
default: /usr/sbin/visudo
description: >
Fully-qualified path to the `visudo` binary used to
validate sudoers configuration changes.
sudo_transactional_update_reboot_ok:
type: raw
default: null
description: >
Whether to allow reboots required by transactional
updates. Set to `true` to allow automatic reboots,
`false` to skip the reboot and allow custom handling,
or `null` to fail when a reboot is needed.
sudo_sudoers_files:
type: list
elements: dict
description: >
List of sudoers file configurations to deploy. Each
item defines the content and target path of a sudoers
file.
options:
path:
type: str
required: true
description: >
Filesystem path where the sudoers configuration
file is deployed, for example `/etc/sudoers` or
`/etc/sudoers.d/custom`.
defaults:
type: list
elements: raw
description: >
List of sudoers `Defaults` entries. Each item is
either a string such as `"!visiblepw"` or
`always_set_home`, or a mapping for options that
take lists of values such as
`secure_path: [/sbin, /bin]` or
`env_keep: [LANG, LC_ALL]`.
user_specifications:
type: list
elements: dict
description: >
List of user specification entries for the
sudoers file. Each entry maps users, hosts, and
commands with optional operators, SELinux
contexts, Solaris privileges, and tags.
options:
users:
type: list
elements: str
description: >
List of users or user aliases the
specification applies to.
hosts:
type: list
elements: str
description: >
List of hosts or host aliases the
specification applies to.
operators:
type: list
elements: str
description: >
List of runas operators or runas aliases
for the specification.
commands:
type: list
elements: str
description: >
List of commands or command aliases the
specification permits.
selinux_role:
type: raw
description: >
SELinux role for the user specification.
Accepts a string value. For historical
reasons a list is also accepted, but only
the first element is used.
selinux_type:
type: raw
description: >
SELinux type for the user specification.
Accepts a string value. For historical
reasons a list is also accepted, but only
the first element is used.
solaris_privs:
type: list
elements: str
description: >
List of Solaris privileges to assign via
the `PRIVS` tag.
solaris_limitprivs:
type: list
elements: str
description: >
List of Solaris limit privileges to assign
via the `LIMITPRIVS` tag.
tags:
type: list
elements: str
description: >
List of tags to apply to the user
specification, such as `NOPASSWD` or
`SETENV`.
default_overrides:
type: list
elements: dict
description: >
List of default override specifications. Each
entry overrides `Defaults` values for a specific
user, runas operator, host, or command scope.
options:
defaults:
type: list
elements: str
description: >
List of defaults to override.
type:
type: str
choices:
- command
- host
- runas
- user
description: >
The scope of the default override. Determines
which sudoers operator is used: `user` maps
to `:`, `runas` to `>`, `host` to `@`, and
`command` to `!`.
commands:
type: list
elements: str
description: >
List of commands for the override. Used when
`type` is `command`.
hosts:
type: list
elements: str
description: >
List of hosts for the override. Used when
`type` is `host`.
operators:
type: list
elements: str
description: >
List of runas operators for the override.
Used when `type` is `runas`.
users:
type: list
elements: str
description: >
List of users for the override. Used when
`type` is `user`.
include_files:
type: list
elements: path
description: >
List of fully-qualified paths to include via the
`#include` directive in the sudoers file.
include_directories:
type: list
elements: path
description: >
List of fully-qualified paths to directories to
include via the `#includedir` directive in the
sudoers file.
aliases:
type: dict
description: >
Dictionary of alias definitions for the sudoers
file. Supports `user_alias`, `runas_alias`,
`host_alias`, and `cmnd_alias` keys.
options:
user_alias:
type: list
elements: dict
description: >
List of `User_Alias` definitions.
options:
name:
type: str
required: true
description: >
The alias name.
users:
type: list
elements: str
required: true
description: >
List of users in the alias.
runas_alias:
type: list
elements: dict
description: >
List of `Runas_Alias` definitions.
options:
name:
type: str
required: true
description: >
The alias name.
users:
type: list
elements: str
required: true
description: >
List of users in the alias.
host_alias:
type: list
elements: dict
description: >
List of `Host_Alias` definitions.
options:
name:
type: str
required: true
description: >
The alias name.
hosts:
type: list
elements: str
required: true
description: >
List of hosts in the alias.
cmnd_alias:
type: list
elements: dict
description: >
List of `Cmnd_Alias` definitions.
options:
name:
type: str
required: true
description: >
The alias name.
commands:
type: list
elements: str
required: true
description: >
List of commands in the alias.
66 changes: 66 additions & 0 deletions tasks/assert_role_vars.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# SPDX-License-Identifier: MIT
---
- name: Assert sudo_transactional_update_reboot_ok is null or a boolean
ansible.builtin.assert:
that:
- >-
(sudo_transactional_update_reboot_ok is none)
or (sudo_transactional_update_reboot_ok is sameas true)
or (sudo_transactional_update_reboot_ok is sameas false)
fail_msg: >-
sudo_transactional_update_reboot_ok must be null or a boolean,
got {{ sudo_transactional_update_reboot_ok | type_debug }}

- name: Assert defaults items are strings or mappings
ansible.builtin.assert:
that:
- >-
item is string
or item is mapping
fail_msg: >-
sudo_sudoers_files defaults items must be strings or
mappings, got {{ item | type_debug }}
loop: "{{ sudo_sudoers_files | selectattr('defaults', 'defined')
| map(attribute='defaults') | flatten | list }}"
loop_control:
label: "{{ item if item is string else
(item.keys() | list | first if item is mapping
else item | string) }}"

- name: Assert selinux_role is a string or list of strings
ansible.builtin.assert:
that:
- >-
item.selinux_role is string
or (item.selinux_role is sequence
and item.selinux_role is not mapping
and item.selinux_role | reject('string') | list
| length == 0)
fail_msg: >-
selinux_role in user_specifications must be a string or
list of strings, got {{ item.selinux_role | type_debug }}
loop: "{{ sudo_sudoers_files
| selectattr('user_specifications', 'defined')
| map(attribute='user_specifications') | flatten | list }}"
loop_control:
label: "{{ item.users | d(['unnamed']) | first }}"
when: item.selinux_role is defined

- name: Assert selinux_type is a string or list of strings
ansible.builtin.assert:
that:
- >-
item.selinux_type is string
or (item.selinux_type is sequence
and item.selinux_type is not mapping
and item.selinux_type | reject('string') | list
| length == 0)
fail_msg: >-
selinux_type in user_specifications must be a string or
list of strings, got {{ item.selinux_type | type_debug }}
loop: "{{ sudo_sudoers_files
| selectattr('user_specifications', 'defined')
| map(attribute='user_specifications') | flatten | list }}"
loop_control:
label: "{{ item.users | d(['unnamed']) | first }}"
when: item.selinux_type is defined
3 changes: 3 additions & 0 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
- name: Set version specific variables
include_tasks: set_vars.yml

- name: Validate role parameters
ansible.builtin.include_tasks: assert_role_vars.yml

- name: Scan sudoers
scan_sudoers:
output_parsed_configs: true
Expand Down
Loading
Loading