I am trying to create a sudoers file with ansible template. The sudoers file should look like below:

Cmnd_Alias LS = /bin/ls
Cmnd_Alias LESS = /usr/bin/less
Cmnd_Alias DU = /usr/bin/du

%support1 ALL=(ALL) NOPASSWD: LS, LESS, DU

What I have managed so far is below:

Cmnd_Alias LS = ls
Cmnd_Alias LESS = less
Cmnd_Alias DU = du

%support1 ALL=(ALL) NOPASSWD: LS, LESS, DU

The template looks like below:

{% for item in commands %}
Cmnd_Alias {{ item|upper }} = {{ item }}
{% endfor %}

%{{ group }} ALL=(ALL) NOPASSWD: {% for item in commands %}
{{ item|upper}}{% if not loop.last %}, {% endif %}
{% endfor %}

vars

commands:
  - ls
  - less
  - du

As far as I know, ansible template module does not have anything which will execute the command in the remote server and print the output otherwise I was thinking of changing template file to look like below:

{% for item in commands %}
Cmnd_Alias {{ item|upper }} = `which {{ item }}`
{% endfor %}

%{{ group }} ALL=(ALL) NOPASSWD: {% for item in commands %}
{{ item|upper}}{% if not loop.last %}, {% endif %}    
{% endfor %}

and the output will be like what I wanted.

Is there any other method which can make it simple?

BTW I have already checked this post

  • I would just place the full path of the command in your vars – jdog Aug 9 at 7:47
  • For modifications on system i prefer including scripts in bash to run better. – lORD Aug 9 at 9:45

TL;DR: KISS. Don't use less.

People often make a mistake with ansible by trying to make variable things that don't need to be. Unless there are multiple places where you define the list of commands that support can access, it is perfectly acceptable to just put them in the template create file:

templates/etc/sudoers.d/support1

Cmnd_Alias LS = /bin/ls
Cmnd_Alias LESS = /bin/cat
Cmnd_Alias DU = /usr/bin/du

%support1 ALL=(ALL) NOPASSWD: LS, LESS, DU

or even explicitly as you don't reuse the Cmnd_Alias anywhere

%support1 ALL=(ALL) NOPASSWD: /bin/ls
%support1 ALL=(ALL) NOPASSWD: /bin/cat
%support1 ALL=(ALL) NOPASSWD: /usr/bin/du

And add some task like:

- name: add templates
  template:
    src: {{ item }}
    dest: /{{ item }}
    owner: root
    group: root
    mode: 0640
  with_items:
    - etc/sudoers.d/support1

You would only use templates instead of files because late on there might be some variable to add to all those or the group name might come from variable if you get another role that creates the groups.

If you need to use variable, the thing you can do is to use a list of hashes like this:

sudoers.support1.commands:
- { alias: "LS", path: "/bin/ls" }
- { alias: "DU", path: "/usr/bin/du" }

Then in the template:

{% for item in sudoers.{{ group }}.commands %}
Cmnd_Alias {{ item.alias }} = {{ item.path }}
{% endfor %}
%{{ group }} ALL=(ALL) NOPASSWD: {{ sudoers.{{ group }}.commands | map(attribute='alias') | join(', ') }}

It is not safe to use /usr/bin/less

In all this you did not notice much important thing and that is the use of less as viewer. Sadly that is a security hole. You can type '!bash' for invoking bash. And by pressing 'v' you get into editor based on VISUAL, EDITOR or LESSEDIT variables. So you can give them '/bin/cat' and they can always pipe the content into less themselves. Note this is still a security hole as some files in unix are very intentionally restricted for example:

/etc/shadow
/etc/sudoers
/etc/ssh/ssh_host_rsa_key
$HOME/.ssh/id_rsa
  • I like the second part. We should refrain from using less as sudo command. – Err0rr yesterday
  • There is zero difference between changing variable and changing the template if the change is in single place. Using the variable makes it only less readable. If you really need to use the variable, name it better and list of hashes, – Jiri Klouda yesterday

Firstly,

you should refer to jinja handling of spaces/newlines. your current template would create new lines, And I think this will confuse sudo and fail syntax validation (IIRC, the right syntax is to add - like: -%} at the for loop, but you should "play" and see what happens) To render a template you can do it on your workstation, without running it on actual target machine. Also, I think creating the template with 1 command at instruction line is more readable: {% for command in commands %} %{{group}} ALL=(ALL) NOPASSWD: {{command}} {% endfor %}

Secondly,

I do not recommend to edit existing global files with ansible. Instead create your custom template under /etc/sudoers.d/ (like you've mentioned you saw).

This is the right way to do it, because:

  • the system will have all defaults as is
  • your template will be far shorter
  • if you do mistakes, you would be sure where to look - in your template.

Thirdly,

I think executing which inside sudoers is an original idea, but should not work.

  • 1
    indeed the I got a syntax error message. I will look into the syntax. And of course I have created a separate file for this. – Err0rr Aug 11 at 13:56

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.