๐ญ Iโm currently working on Kong Ansible Collection
ahuffman / ansible-sudoers Goto Github PK
View Code? Open in Web Editor NEWControls the configuration of the default /etc/sudoers file and included files/directories.
License: MIT License
Controls the configuration of the default /etc/sudoers file and included files/directories.
License: MIT License
๐ญ Iโm currently working on Kong Ansible Collection
If the playbook is run in "--check"-mode the run will fail due to "existing_sudoer_spec_list" being undefined as shell / command modules are not run in this mode:
fatal: []: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'dict object' has no attribute 'stdout_lines'\n\nThe error appears to have been in 'roles/wtcross.sudoers/tasks/main.yml': line 35, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Get a list of all existing separate sudoer specs\n ^ here\n"}
This issue could be fixed in the following ways:
Using a module is the right way, but in this case it would require raising the minimum Ansible version from 1.2 to 2.0. If you don't mind raising the version requirement you can check my pull request I'm going to send.
Hi,
Using --check
it fails with following error:
{"msg": "The conditional check 'sudoers_includes_separate_specs.stdout != \"1\"' failed. The error was: error while evaluating conditional (sudoers_includes_separate_specs.stdout != \"1\"): 'dict object' has no attribute 'stdout'
Because shell commands are ignored when --check ing.
It looks like it's possible to use a check_mode: yes
:
Force a task to run in check mode, even when the playbook is called without --check. This is called check_mode: yes.
- name: this task will always run under checkmode and not change the system
lineinfile: line="important config" dest=/path/to/myconfig.conf state=present
check_mode: yes
From http://docs.ansible.com/ansible/latest/playbooks_checkmode.html#enabling-or-disabling-check-mode-for-tasks & https://stackoverflow.com/a/46454251
When attempting to use this role with ansible's become features, this fails.
task path: /Users/jph/.ansible/roles/wtcross.sudoers/tasks/main.yml:67
fatal: [HOST]: FAILED! => {"changed": false, "checksum": "1d99f8306ef375a9efca0fd061d5161fc8f0bd2a", "cmd": "visudo -cf /home/jph/.ansible/tmp/ansible-tmp-1519164114.3-191627255996605/source", "msg": "[Errno 2] No such file or directory", "rc": 2}
But when I login and run this as root, it works fine. Any ideas? I had a look and I can't work it out at all.
in task "Ensure local backup directory exists", line 46, owner is set to "{{ ansible_user }}" which is a remote user, yet the task run locally, it consequently fails when there is no local account with this name
The default configuration should be the safest one
Hi,
Thanks for maintaining this very useful role!
I was wondering if you have any plans to publish it in an Ansible collection?
I use Red Hat Ansible Automation Hub (which is based on Galaxy NG), and support for standalone roles is limited.
Thanks again,
Ben
So, as the title says.
sudoer_separate_specs
defaults to true, and the doco states it should not nuke the directory contents, but mine did at the task Remove separate sudoer specs that are not authorized
.
I think I'm meant to do something with authorized_sudoer_specs
? Needs to be documented better maybe?
It is likely outside the scope, but it would be wonderful to take an existing sudoers file (/etc/sudoers or /etc/sudoers.d/) and convert all the aliases and specs into correctly-formatted vars. This could help remediate existing systems and get them version controlled under Ansible.
With the config below
sudoer_separate_specs: True
sudoer_rewrite_sudoers_file: True
sudoer_remove_unauthorized_specs: False
using sample playbook given, the following errors occur -
TASK [wtcross.sudoers : Ensure the sudoers file is valid and up to date (separate specs)] ***************************************************************************************************************************************************
task path: /etc/ansible/roles/wtcross.sudoers/tasks/main.yml:44
fatal: [10.x.x.x]: FAILED! => {"changed": false, "msg": "AnsibleFilterError: The slice filter requires a mapping to operate on, got a <type 'list'>."}
It appears a parameter is missing a default value:
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ): 'NoneType' object is not iterable. 'NoneType' object is not iterable
failed: [sendai.fizeau.net] (item=/etc/sudoers.d/02_nagios) => changed=false
ansible_loop_var: item
item:
path: /etc/sudoers.d/02_nagios
user_specifications:
commands: /usr/sbin/checkrestart
hosts: ALL
tags: NOPASSWD
users: nagios
msg: |-
AnsibleError: Unexpected templating type error occurred on ({{ ansible_managed | comment }}
{% if item.defaults is defined %}
# Default specifications
{% for default in item.defaults %}
{% if default is mapping %}
{% for name, values in default.items() %}
{% if name == 'secure_path' %}
Defaults {{ name }} = {% for item in values %}{% if not loop.last %}{{ item }}:{% else %}{{ item }}{% endif %}{% endfor %}
{% else %}
{% for items in values | list | slice(6) %}
{% if items %}
Defaults {{ name }} {% if not loop.first %}+{% endif %}= "{{ items | list | join(' ') }}"
{% endif -%}
{% endfor %}
{% endif %}
{% endfor %}
{% elif default | first == ':' %}
Defaults{{ default }}
{% else %}
Defaults {{ default }}
{% endif %}
{% endfor %}
{% endif %}
{% if item.aliases is defined %}
# Alias specifications
{% if item.aliases.cmnd_alias is defined %}
## Command Aliases
{% for ca in item.aliases.cmnd_alias %}
Cmnd_Alias {{ ca.name }} = {% for cmnd in ca.commands %}{% if not loop.last %}{{ cmnd }}, {% else %}{{ cmnd }}{% endif %}{% endfor %}
{% endfor %}
{% endif %}
{% if item.aliases.host_alias is defined %}
## Host Aliases
{% for ha in item.aliases.host_alias %}
Host_Alias {{ ha.name }} = {% for host in ha.hosts %}{% if not loop.last %}{{ host }}, {% else %}{{ host }}{% endif %}{% endfor %}
{% endfor %}
{% endif %}
{% if item.aliases.runas_alias is defined %}
## Runas Aliases
{% for ra in item.aliases.runas_alias %}
Runas_Alias {{ ra.name }} = {% for user in ra.users %}{% if not loop.last %}{{ user }}, {% else %}{{ user }}{% endif %}{% endfor %}
{% endfor %}
{% endif %}
{% if item.aliases.user_alias is defined %}
## User Aliases
{% for ua in item.aliases.user_alias %}
User_Alias {{ ua.name }} = {% for user in ua.users %}{% if not loop.last %}{{ user }}, {% else %}{{ user }}{% endif %}{% endfor %}
{% endfor %}
{% endif %}
{% endif %}
{% if item.user_specifications is defined %}
{% if item.user_specifications | json_query('[?!type]') | flatten | length > 0 %}
# User specifications
{% for spec in item.user_specifications %}
{% if spec.type is undefined %}
{% for user in spec.users %}{% if not loop.last %}{{ user }}, {% else %}{{ user }}{% endif %}{% endfor %} {% for host in spec.hosts %}{% if not loop.last %}{{ host }}, {% else %}{{ host }}{% endif %}{% endfor %}={% if spec.operators is defined %}({% for op in spec.operators %}{% if not loop.last%}{{ op }}, {% else %}{{ op }}{% endif %}{% endfor %}){% endif %} {% if spec.selinux_type is defined %}TYPE={% for type in spec.selinux_type %}{% if not loop.last %}{{ type }}, {% else %}{{ type }} {% endif %}{% endfor %}{% endif %}{% if spec.selinux_role is defined %}ROLE={% for role in spec.selinux_role %}{% if not loop.last %}{{ role }}, {% else %}{{ role }} {% endif %}{% endfor %}{% endif %}{% if spec.solaris_privs is defined %}PRIVS={% for priv in spec.solaris_privs %}{% if not loop.last %}{{ priv }}, {% else %}{{ priv }} {% endif %}{% endfor %}{% endif %}{% if spec.solaris_limitprivs is defined %}LIMITPRIVS={% for lpriv in spec.solaris_limitprivs %}{% if not loop.last %}{{ lpriv }}, {% else %}{{ lpriv }} {% endif %}{% endfor %}{% endif %}{% if spec.tags is defined %}{% for tag in spec.tags %}{{ tag }}:{% endfor %} {% endif %}{% for cmnd in spec.commands %}{% if not loop.last %}{{ cmnd }}, {% else %}{{ cmnd }}{% endif %}{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% if item.user_specifications | json_query('[*].defaults') | flatten | length > 0 %}
# Default override specifications
{% for spec in item.user_specifications %}
{% if spec.type is defined %}
{% if spec.type == 'user'%}
Defaults:{% for user in spec.users %}{% if not loop.last %}{{ user }}, {% else %}{{ user }} {% endif %}{% endfor %}{% for default in spec.defaults %}{% if not loop.last %}{{ default }}, {% else %}{{ default }}{% endif %}{% endfor %}
{% elif spec.type == 'runas' %}
Defaults>{% for op in spec.operators %}{% if not loop.last %}{{ op }}, {% else %}{{ op }} {% endif %}{% endfor %}{% for default in spec.defaults %}{% if not loop.last %}{{ default }}, {% else %}{{ default }}{% endif %}{% endfor %}
{% elif spec.type == 'host' %}
Defaults@{% for host in spec.hosts %}{% if not loop.last %}{{ host }}, {% else %}{{ host }} {% endif %}{% endfor %}{% for default in spec.defaults %}{% if not loop.last %}{{ default }}, {% else %}{{ default }}{% endif %}{% endfor %}
{% elif spec.type == 'command' %}
Defaults!{% for cmnd in spec.commands %}{% if not loop.last %}{{ cmnd }}, {% else %}{{ cmnd }} {% endif %}{% endfor %}{% for default in spec.defaults %}{% if not loop.last %}{{ default }}, {% else %}{{ default }}{% endif %}{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% if item.include_files is defined or item.include_directories is defined %}
# Includes
{% if item.include_files is defined and item.include_files | length > 0 %}
## Include files
{% for file in item.include_files %}
#include {{ file }}
{% endfor %}
{% endif %}
{% if item.include_directories is defined and item.include_directories | length > 0 %}
## Include directories
{% for dir in item.include_directories %}
#includedir {{ dir }}
{% endfor %}
{% endif %}
{% endif %}
): 'NoneType' object is not iterable. 'NoneType' object is not iterable
The role parameters are very minimal:
sudoers_files:
- path: /etc/sudoers.d/02_nagios
user_specifications:
users: nagios
hosts: ALL
tags: NOPASSWD
commands: /usr/sbin/checkrestart
sudoers_backup: false
I ran ansible in check mode, but I assume that makes no difference.
Hello,
I think to have a better change management, this role should be driven with releases and/or tags using the semantic versioning (ex: 0.1.0) ?
What do you think about that ? If you're agree, can you set the first release/tag please ?
Thanks
TASK [ansible-sudoers : Ensure the sudoers file is valid and up to date (separate specs)] ********************************************************************************
fatal: [mngt.us.dcapi.net]: FAILED! => {"changed": false, "msg": "AnsibleFilterError: The slice filter requires a mapping to operate on, got a <type 'list'>."}
It looks like this role require community.general
(json_query
filter).
settings:
sudoer_separate_specs: True
sudoer_rewrite_sudoers_file: False
sudoer_remove_unauthorized_specs: True
playbook:
- name: testme
hosts: AIXWUKIT,SAG0120_TESTLPAR
gather_facts: no
vars:
sudoer_aliases:
user:
- name: XAIX_STAFF
comment: aix users
users:
- ab
- alti
- nj
- rb
- rgruber
- tremch
- seb
- walzjo
- gnowotny
runas:
- name: ROOT
comment: root stuff
users:
- '#0'
command:
- name: XSU_ROOT
comment: root stuff
commands:
- /usr/bin/su -, /usr/bin/su - -c *
sudoer_specs:
- name: XPERM_AIX
comment: aix permissions
users: XAIX_STAFF
hosts: ALL
operators: ROOT
tags: NOPASSWD
commands: ALL
defaults:
- '!requiretty'
roles:
- manage_sudoers
result (missing command and user aliases):
root@aixwukit: /etc/sudoers.d # ls -l
total 8
-r--r----- 1 root system 146 Sep 07 14:03 XPERM_AIX
root@aixwukit: /etc/sudoers.d # cat XPERM_AIX
#Ansible managed: Manual interventions are a waste of time.
#aix permissions
Defaults:XAIX_STAFF !requiretty
XAIX_STAFF ALL=(ROOT) NOPASSWD: ALL
Some output of the test failure:
PLAY [test-kitchen] ************************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [ansible-sudoers : Ensure sudo is installed] ******************************
fatal: [localhost]: FAILED! => {"failed": true, "msg": "The conditional check 'sudo_installed is success' failed. The error was: template error while templating string: no test named 'success'. String: {% if sudo_installed is success %} True {% else %} False {% endif %}"}
to retry, use: --limit @/tmp/kitchen/default.retry
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: 1 actions failed.
>>>>>> Converge failed on instance <default-fedora-latest>. Please see .kitchen/logs/default-fedora-latest.log for more details
>>>>>> ----------------------
>>>>>> Please see .kitchen/logs/kitchen.log for more details
>>>>>> Also try running `kitchen diagnose --all` for configuration
The command "bundle exec kitchen test $KITCHEN_REGEXP" exited with 20.
Done. Your build exited with 1.
Ansible fails with the following error (thats using only one entry in sudoer_specs)
vars:
- sudoer_specs:
- name: vagrant
users: vagrant
comment: Stuff for admins
hosts: ALL
operators: ALL
tags:
- NOPASSWD
commands: ALL
TASK [../../ansible-sudoers : Ensure the sudoers file is valid and up to date (separate specs)] *** fatal: [centos7]: FAILED! => {"changed": false, "failed": true, "msg": "AnsibleUndefinedVariable: 'dict object' has no attribute 'iteritems'"}
ansible --version ansible 2.3.1.0 config file = configured module search path = Default w/o overrides python version = 3.5.2 (default, Oct 11 2016, 05:05:28) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)]
Hi! would it be possible, and how, to have different roles configured in different conf files?
I have tried using differnt group vars, or include, but I was not succesfull. The idea is to have one file for each role you want to have, so is more organized for future maintenance (for exambple, having a different definition for DBAs, SysOps, DevOps, etc)
ansible-sudoers/tasks/main.yml
Line 51 in 3920507
If I include this role in other playbooks, and set 'become: True' in playbook vars. This task will fail because my local machine require sudo password.
I think better to explicit add 'become: False' to this task.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.