{"id":14984447,"url":"https://github.com/ahuffman/ansible-sudoers","last_synced_at":"2025-07-01T22:32:04.716Z","repository":{"id":56660962,"uuid":"50736990","full_name":"ahuffman/ansible-sudoers","owner":"ahuffman","description":"Controls the configuration of the default /etc/sudoers file and included files/directories.","archived":false,"fork":false,"pushed_at":"2024-02-12T15:17:13.000Z","size":74,"stargazers_count":107,"open_issues_count":3,"forks_count":45,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-04-08T20:03:33.521Z","etag":null,"topics":["ansible","ansible-role","sudo","sudoers","sudoers-configuration"],"latest_commit_sha":null,"homepage":"","language":"Jinja","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ahuffman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-01-30T17:55:38.000Z","updated_at":"2024-12-30T22:22:28.000Z","dependencies_parsed_at":"2024-09-25T00:30:20.550Z","dependency_job_id":null,"html_url":"https://github.com/ahuffman/ansible-sudoers","commit_stats":{"total_commits":61,"total_committers":19,"mean_commits":3.210526315789474,"dds":0.7377049180327868,"last_synced_commit":"81ce24a43ed4ca9fb9ed4b11631ad01bbf89ffde"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/ahuffman/ansible-sudoers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahuffman%2Fansible-sudoers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahuffman%2Fansible-sudoers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahuffman%2Fansible-sudoers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahuffman%2Fansible-sudoers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ahuffman","download_url":"https://codeload.github.com/ahuffman/ansible-sudoers/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahuffman%2Fansible-sudoers/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263046253,"owners_count":23405160,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ansible-role","sudo","sudoers","sudoers-configuration"],"created_at":"2024-09-24T14:09:04.659Z","updated_at":"2025-07-01T22:32:04.643Z","avatar_url":"https://github.com/ahuffman.png","language":"Jinja","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Ansible Role](https://img.shields.io/ansible/role/d/38958)\n\n# ahuffman.sudoers\n\nControls the configuration of the default `/etc/sudoers` file and included files/directories.\n\n---\n***Please note, release 2.0.0+ is a major re-write of the role.  Please read the documentation to ensure you understand the changes prior to installation and use if coming from prior versions.***\n\n---\n\n## Table of Contents\n\u003c!-- TOC depthFrom:2 depthTo:6 withLinks:1 updateOnSave:0 orderedList:1 --\u003e\n\n1. [Table of Contents](#table-of-contents)\n2. [Tips](#tips)\n3. [Role Variables](#role-variables)\n4. [sudoers_files Dictionary Fields](#sudoers_files-dictionary-fields)\n\t1. [sudoers_files.aliases Dictionary Fields](#sudoers_filesaliases-dictionary-fields)\n\t\t1. [cmnd_alias Dictionary Fields](#cmnd_alias-dictionary-fields)\n\t\t2. [host_alias Dictionary Fields](#host_alias-dictionary-fields)\n\t\t3. [runas_alias Dictionary Fields](#runas_alias-dictionary-fields)\n\t\t4. [user_alias Dictionary Fields](#user_alias-dictionary-fields)\n\t2. [user_specifications Dictionary Fields](#user_specifications-dictionary-fields)\n\t\t1. [Standard user_specifications](#standard-user_specifications)\n\t\t2. [Default Override user_specifications](#default-override-user_specifications)\n5. [Automatically Generating the Sudoers Files Data from an Existing Configuration](#automatically-generating-the-sudoers-files-data-from-an-existing-configuration)\n6. [Example Playbooks](#example-playbooks)\n\t1. [RHEL7.6 Default Sudoers Configuration](#rhel76-default-sudoers-configuration)\n\t\t1. [Results: /etc/sudoers](#results-etcsudoers)\n\t2. [Sudoers Configuration (multiple files)](#sudoers-configuration-multiple-files)\n\t\t1. [Results: /etc/sudoers](#results-etcsudoers)\n\t\t2. [Results: /etc/sudoers.d/pingers](#results-etcsudoersdpingers)\n\t\t3. [Results: /etc/sudoers.d/root](#results-etcsudoersdroot)\n\t3. [Migrating a Running Sudoers Configuration to Another Host](#migrating-a-running-sudoers-configuration-to-another-host)\n11. [License](#license)\n12. [Author Information](#author-information)\n\n\u003c!-- /TOC --\u003e\n\n## Tips\n|*Tip:* Here's a few excellent resources on sudoers configuration:|\n|---|\n|[Start here](https://help.ubuntu.com/community/Sudoers) - Provides a great run-down on basic sudoers file configurations and terminology|\n|[Sudoers Manual](https://www.sudo.ws/man/1.8.15/sudoers.man.html) - If you want to know all the details, this is for you.|\n\n## Role Variables\nThe defaults defined for this role are based on a default RHEL7.6 `/etc/sudoers` configuration.  Please check the defaults in [`defaults/main.yml`](defaults/main.yml) prior to running for OS compatibility.\n\n| Variable Name | Description | Default Value | Variable Type |\n| --- | --- | :---: | :---: |\n| sudoers_rewrite_default_sudoers_file | Use role default or user defined `sudoers_files` definition, replacing your distribution supplied `/etc/sudoers` file.  Useful when attempting to deploy new configuration files to the `include_directories` and you do not wish to modify the `/etc/sudoers` file. | True | boolean |\n| sudoers_remove_unauthorized_included_files | ***Very Dangerous!*** Each existing sudoer file found in the `include_directories` dictionary which have not been defined in `sudoers_files` will be removed. This allows for enforcing a desired state. | False | boolean |\n| sudoers_backup | Whether or not to create a backup of the current state of the existing `/etc/sudoers` file as well as any files defined in `sudoers_files`.  The files get backed up to the Ansible control node (Server you are executing Ansible from) and avoids accidentally leaving files behind in your `include_directories` that may be evaluated by the sudoers configuration(s).| True | boolean |\n| sudoers_backup_path | Path relative to where you are executing your playbook to backup the remote copies of defined `sudoers_files` to. | \"sudoers_backups\" | string |\n| sudoers_backup_become | Whether or not to use sudo when creating local sudoers backup directory and sudoers file backups | True | boolean |\n| sudoers_visudo_path | Fully-qualified path to the `visudo` binary required for validation of sudoers configuration changes. Added for Operating System compatibility. | \"/usr/sbin/visudo\" | string |\n| sudoers_files | Definition of all your sudoers configurations | see [defaults/main.yml](defaults/main.yml)| list of dictionaries |\n\n## sudoers_files Dictionary Fields\n| Variable Name | Description | Variable Type |\n| --- | --- | :---: |\n| path | Where to deploy the configuration file to on the filesystem. | string |\n| aliases | Optional definition of `cmnd_alias`, `host_alias`, `runas_alias`, or `user_alias` items. | dictionary |\n| defaults | This allows you to define the defaults of your sudoers configuration. Default overrides can be perfomed via the [`user_specifications`](#default-override-user_specifications) key.| list |\n| include_files | Optional specific files that you would like your configuration to include.  This is a list of fully-qualified paths to include via the `#include` option of a sudoers configuration. | list |\n| include_directories | Optional specific directories that you would like your configurations to include.  This is a list of fully-qualified paths to directories to include via the `#includedir` option of a sudoers configuration. | list |\n| user_specifications | List of user specifications and default overrides to apply to a sudoers file configuration. | list |\n\n### sudoers_files.aliases Dictionary Fields\n| Variable Name | Description | Variable Type |\n| --- | --- | :---: |\n| cmnd_alias | List of command alias definitions. | list of dictionaries |\n| host_alias | List of host alias definitions | list of dictionaries |\n| runas_alias | List of runas alias definitions | list of dictionaries |\n| user_alias | List of user alias definitions | list of dictionaries |\n\n#### cmnd_alias Dictionary Fields\n| Variable Name | Description | Variable Type |\n| --- | --- | :---: |\n| name | Name of the command alias. | string |\n| commands | List of commands to apply to the alias | list |\n\n#### host_alias Dictionary Fields\n| Variable Name | Description | Variable Type |\n| --- | --- | :---: |\n| name | Name of the host alias. | string |\n| hosts | List of hosts to apply to the alias | list |\n\n#### runas_alias Dictionary Fields\n| Variable Name | Description | Variable Type |\n| --- | --- | :---: |\n| name | Name of the runas alias | string |\n| users | List of users to apply to the alias | list |\n\n#### user_alias Dictionary Fields\n| Variable Name | Description | Variable Type |\n| --- | --- | :---: |\n| name | Name of the user_alias | string |\n| users | List of users to apply to the alias | list |\n\n### user_specifications Dictionary Fields\nThis dictionary can be used to assign either user specifications or default overrides.\n\n#### Standard user_specifications\n| Variable Name | Description | Variable Type |\n| --- | --- | :---: |\n| users | List of users to apply the specification to. You can use a `user_alias` name as well as user names. | list |\n| hosts | List of hosts to apply the specification to.  You can use a defined `host_alias` name as well as host names. | list |\n| operators | List of operators to apply the specification to. You can use a defined `runas_alias` name as well as user names. | list |\n| selinux_role | Optional selinux role to apply to the specification | list |\n| selinux_type | Optional selinux type to apply to the specification | list |\n| solaris_privs | Optional Solaris privset to apply to the specification | list |\n| solaris_limitprivs | Optional Solaris privset to apply to the specification | list |\n| tags | Optional list of tags to apply to the specification. | list |\n| commands | List of commands to apply the specification to.  You can use a defined `cmnd_alias` name as well as commands. | list |\n\n#### Default Override user_specifications\n| Variable Name | Description | Variable Type |\n| --- | --- | :---: |\n| defaults | List of defaults to override from the main configuration | list |\n| type | Type of default to override, this affects the operator in the configuration ( host -\u003e `@`, user -\u003e `:`, command -\u003e `!`, and runas -\u003e `\u003e`).  The type field can be one of the following values: `command`, `host`, `runas`, or `user`. | string |\n| commands | Use when `type: \"command\"`.  List of `cmnd_alias` names as well as commands to override specific default values.| list |\n| hosts | Use when `type: \"host\"`.  List of `host_alias` names as well as individual host names to override specific default values. | list |\n| operators | Use when `type: \"runas\"`. List of `runas_alias` names as well as individual user names to override specific default values. | list |\n| users | Use when `type: \"user\"`.  List of `user_alias` names as well as individual user names to override specific default values. | list |\n\n## Automatically Generating the Sudoers Files Data from an Existing Configuration\nDoes this all sound way too complicated to configure from the documentation?  Please check out and try [ahuffman.scan_sudoers](https://galaxy.ansible.com/ahuffman/scan_sudoers) to find a role that can auto-generate the proper data structure for you.  With the [ahuffman.scan_sudoers](https://galaxy.ansible.com/ahuffman/scan_sudoers) role, you can take a running configuration in one play, and lay it down on another with the [ahuffman.sudoers](https://galaxy.ansible.com/ahuffman/sudoers) role (version 2.0.0+).  You could also opt to take the collected data and push it into a source of truth such as a CMDB or repository via automation.  The collected data that is generated by [ahuffman.scan_sudoers](https://galaxy.ansible.com/ahuffman/scan_sudoers) and can be consumed by [ahuffman.sudoers](https://galaxy.ansible.com/ahuffman/sudoers) would be `{{ ansible_facts['sudoers'].sudoers_files }}`.\n\nThis should help alleviate some of the complication of manually defining the sudoers configurations as code, and get you up and running much quicker.\n\nSee the [Playbook Example](#migrating-a-running-sudoers-configuration-to-another-host) below.\n\n\n## Example Playbooks\n### RHEL7.6 Default Sudoers Configuration\n```yaml\n- name: \"Apply a RHEL7.6 Default /etc/sudoers configuration\"\n  hosts: \"all\"\n  roles:\n    - role: \"ahuffman.sudoers\"\n```\n...or with modern syntax:\n```yaml\n- name: \"Apply a RHEL7.6 Default /etc/sudoers configuration\"\n  hosts: \"all\"\n  tasks:\n    - name: \"Configure /etc/sudoers\"\n      include_role:\n        name: \"ahuffman.sudoers\"\n```\n\n#### Results: /etc/sudoers\n\nThe above two examples using the role defaults will produce a `/etc/sudoers` configuration file that looks like this:  \n```\n# Ansible managed\n\n# Default specifications\nDefaults    !visiblepw\nDefaults    always_set_home\nDefaults    match_group_by_gid\nDefaults    always_query_group_plugin\nDefaults    env_reset\nDefaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin\nDefaults    env_keep = \"COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR\"\nDefaults    env_keep += \"LS_COLORS MAIL PS1 PS2 QTDIR\"\nDefaults    env_keep += \"USERNAME LANG LC_ADDRESS LC_CTYPE LC_COLLATE\"\nDefaults    env_keep += \"LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME\"\nDefaults    env_keep += \"LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME LC_ALL\"\nDefaults    env_keep += \"LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY\"\n\n# User specifications\nroot ALL=(ALL) ALL\n%wheel ALL=(ALL) ALL\n\n# Includes\n## Include directories\n#includedir /etc/sudoers.d\n```\n\n### Sudoers Configuration (multiple files)\n\n```yaml\n- name: \"Apply a multi-file sudoers configuration\"\n  hosts: \"all\"\n  tasks:\n    - name: \"Configure /etc/sudoers and included files\"\n      include_role:\n        name: \"ahuffman.sudoers\"\n      vars:\n        sudoers_rewrite_default_sudoers_file: True\n        sudoers_remove_unauthorized_included_files: True\n        sudoers_backup: True\n        sudoers_backup_path: \"sudoers-backups\"\n        sudoers_files:\n          - path: \"/etc/sudoers\"\n            defaults:\n              - \"!visiblepw\"\n              - \"always_set_home\"\n              - \"match_group_by_gid\"\n              - \"always_query_group_plugin\" # maintains sudo pre-1.8.15 group behavior\n              - \"env_reset\"\n              - secure_path:\n                  - \"/sbin\"\n                  - \"/bin\"\n                  - \"/usr/sbin\"\n                  - \"/usr/bin\"\n              - env_keep:\n                  - \"COLORS\"\n                  - \"DISPLAY\"\n                  - \"HOSTNAME\"\n                  - \"HISTSIZE\"\n                  - \"KDEDIR\"\n                  - \"LS_COLORS\"\n                  - \"MAIL\"\n                  - \"PS1\"\n                  - \"PS2\"\n                  - \"QTDIR\"\n                  - \"USERNAME\"\n                  - \"LANG\"\n                  - \"LC_ADDRESS\"\n                  - \"LC_CTYPE\"\n                  - \"LC_COLLATE\"\n                  - \"LC_IDENTIFICATION\"\n                  - \"LC_MEASUREMENT\"\n                  - \"LC_MESSAGES\"\n                  - \"LC_MONETARY\"\n                  - \"LC_NAME\"\n                  - \"LC_NUMERIC\"\n                  - \"LC_PAPER\"\n                  - \"LC_TELEPHONE\"\n                  - \"LC_TIME\"\n                  - \"LC_ALL\"\n                  - \"LANGUAGE\"\n                  - \"LINGUAS\"\n                  - \"_XKB_CHARSET\"\n                  - \"XAUTHORITY\"\n            user_specifications:\n              - users:\n                  - \"root\"\n                hosts:\n                  - \"ALL\"\n                operators:\n                  - \"ALL\"\n                commands:\n                  - \"ALL\"\n              - users:\n                  - \"%wheel\"\n                hosts:\n                  - \"ALL\"\n                operators:\n                  - \"ALL\"\n                commands:\n                  - \"ALL\"\n            include_directories:\n              - \"/etc/sudoers.d\"\n            aliases:\n              cmnd_alias:\n                - name: \"PING\"\n                  commands:\n                    - \"/bin/ping\"\n              user_alias:\n                - name: \"PINGERS\"\n                  users:\n                    - \"ahuffman\"\n          - path: \"/etc/sudoers.d/pingers\"\n            user_specifications:\n              - type: \"user\"\n                defaults:\n                  - \"!requiretty\"\n                users:\n                  - \"PINGERS\"\n          - path: \"/etc/sudoers.d/root\"\n            defaults:\n              - \"syslog=auth\"\n            user_specifications:\n              - type: \"runas\"\n                defaults:\n                  - \"!set_logname\"\n                operators:\n                  - \"root\"\n```\n\nThe example above will produce the following configuration files:\n#### Results: /etc/sudoers\n\n```\n# Ansible managed\n\n# Default specifications\nDefaults    !visiblepw\nDefaults    always_set_home\nDefaults    match_group_by_gid\nDefaults    always_query_group_plugin\nDefaults    env_reset\nDefaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin\nDefaults    env_keep = \"COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR\"\nDefaults    env_keep += \"LS_COLORS MAIL PS1 PS2 QTDIR\"\nDefaults    env_keep += \"USERNAME LANG LC_ADDRESS LC_CTYPE LC_COLLATE\"\nDefaults    env_keep += \"LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME\"\nDefaults    env_keep += \"LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME LC_ALL\"\nDefaults    env_keep += \"LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY\"\n\n# Alias specifications\n## Command Aliases\nCmnd_Alias    PING = /bin/ping\n\n## User Aliases\nUser_Alias    PINGERS = ahuffman\n\n# User specifications\nroot ALL=(ALL) ALL\n%wheel ALL=(ALL) ALL\n\n# Includes\n## Include directories\n#includedir /etc/sudoers.d\n```\n#### Results: /etc/sudoers.d/pingers\n\n```\n# Ansible managed\n\n# Default override specifications\nDefaults:PINGERS !requiretty\n```\n\n#### Results: /etc/sudoers.d/root\n\n```\n# Ansible managed\n\n# Default specifications\nDefaults    syslog=auth\n\n\n# Default override specifications\nDefaults\u003eroot !set_logname\n```\n\n### Migrating a Running Sudoers Configuration to Another Host\n\n```yaml\n---\n- name: \"Collect Existing Sudoers Facts\"\n  hosts: \"source-host\"\n  tasks:\n    - name: \"Collect Running Sudoers Configuration\"\n      include_role:\n        name: \"ahuffman.scan_sudoers\"\n\n    - name: \"Set Collected Sudoers Facts\"\n      set_fact:\n        sudoers_files: \"{{ ansible_facts['sudoers'].sudoers_files }}\"\n\n    - name: \"Display Collected Sudoers Configuration Facts\"\n      debug:\n        var: \"sudoers_files\"\n        verbosity: \"1\"\n\n- name: \"Deploy Running Configuration to Target\"\n  hosts: \"destination-host\"\n  tasks:\n    - include_role:\n        name: \"ahuffman.sudoers\"\n      vars:\n        sudoers_remove_unauthorized_included_files: True\n```\nThe above example provides a method of using Infrastructure-as-Code in Reverse to take a known configuration converted to structured data to drive future automation.  Alternatively to directly provisioning the collected configuration on a new host, you could push the data into a CMDB or repository for future use as a source of truth.\n\n## License\n\n[MIT](LICENSE)\n\n## Author Information\n\n[Andrew J. Huffman](https://github.com/ahuffman)  \n[Tyler Cross](https://github.com/wtcross)  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahuffman%2Fansible-sudoers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fahuffman%2Fansible-sudoers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahuffman%2Fansible-sudoers/lists"}