<p><strong>TL;DR:</strong> KISS. Don't use less.</p>

<p>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: </p>

<p><strong>templates/etc/sudoers.d/support1</strong> </p>

<pre><code>Cmnd_Alias LS = /bin/ls
Cmnd_Alias LESS = /bin/cat
Cmnd_Alias DU = /usr/bin/du

%support1 ALL=(ALL) NOPASSWD: LS, LESS, DU
</code></pre>

<p>or even explicitly as you don't reuse the Cmnd_Alias anywhere</p>

<pre><code>%support1 ALL=(ALL) NOPASSWD: /bin/ls
%support1 ALL=(ALL) NOPASSWD: /bin/cat
%support1 ALL=(ALL) NOPASSWD: /usr/bin/du
</code></pre>

<p>And add some task like:</p>

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

<p>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.</p>

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

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

<p>Then in the template:</p>

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

<p><strong>It is not safe to use /usr/bin/less</strong></p>

<p>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:</p>

<pre><code>/etc/shadow
/etc/sudoers
/etc/ssh/ssh_host_rsa_key
$HOME/.ssh/id_rsa
</code></pre>

CC BY-SA 4.0
2018-08-13T04:40:34.737Z
I like the second part. We should refrain from using less as sudo command.
Prakash
CC BY-SA 4.0
2018-08-13T05:08:20.857Z
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
CC BY-SA 4.0
2018-08-12T16:54:43.047Z
2018-08-13T05:27:06.520Z
2018-08-13T05:27:06.520Z
Jiri Klouda
<h3>Firstly</h3>

<p>you should refer to Jinja handling of spaces/newlines. your current template would create new lines, And I think this will confuse <code>sudo</code> and fail syntax validation (IIRC, the right syntax is to add <code>-</code> like: <code>-%}</code> 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.</p>

<p>Also, I think creating the template with 1 command at instruction line is more readable:</p>

<pre><code>{% for command in commands %}
%{{group}} ALL=(ALL) NOPASSWD: {{command}}
{% endfor %}
</code></pre>

<h3>Secondly</h3>

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

<p>This is the right way to do it, because:</p>

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

<h3>Thirdly</h3>

<p>I think executing <code>which</code> inside <code>sudoers</code> is an original idea, but should not work.</p>

CC BY-SA 4.0
2018-08-11T13:56:25.607Z
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.
Prakash
CC BY-SA 4.0
2018-08-10T08:46:07.133Z
2019-03-06T17:41:17.493Z
2019-03-06T17:41:17.493Z
mvk_il
<p>I am trying to create a sudoers file with ansible template. The sudoers file should look like below:</p>

<pre><code>Cmnd_Alias LS = /bin/ls
Cmnd_Alias LESS = /usr/bin/less
Cmnd_Alias DU = /usr/bin/du

%support1 ALL=(ALL) NOPASSWD: LS, LESS, DU
</code></pre>

<p>What I have managed so far is below:</p>

<pre><code>Cmnd_Alias LS = ls
Cmnd_Alias LESS = less
Cmnd_Alias DU = du

%support1 ALL=(ALL) NOPASSWD: LS, LESS, DU
</code></pre>

<p>The template looks like below:</p>

<pre><code>{% 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 %}
</code></pre>

<p>vars</p>

<pre><code>commands:
  - ls
  - less
  - du
</code></pre>

<p>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:</p>

<pre><code>{% 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 %}
</code></pre>

<p>and the output will be like what I wanted.</p>

<p>Is there any other method which can make it simple?</p>

<p>BTW I have already checked this <a href="https://unix.stackexchange.com/questions/349691/how-to-modify-sudoers-file-with-ansible/349712">post</a></p>

CC BY-SA 4.0
2018-08-09T07:47:10.803Z
I would just place the full path of the command in your vars
jdog
CC BY-SA 4.0
2018-08-09T09:45:07.947Z
For modifications on system i prefer including scripts in bash to run better.
lORD
<ansible>
Modify sudoers file with ansible playbook template
Prakash
# Modify sudoers file with ansible playbook template

(Asked by: username_0 on 2018-08-08)

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

**Tags:** ansible

> **Comments:**
> **username_1**: I would just place the full path of the command in your vars  
> **username_2**: For modifications on system i prefer including scripts in bash to run better.  

---

## 2 answers

### Answer by username_3 on 2018-08-12. Score: 6

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

> **Comments:**
> **username_0**: I like the second part. We should refrain from using less as sudo command.  
> **username_3**: 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,  

---

### Answer by username_4 on 2018-08-10. Score: 1

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.

> **Comments:**
> **username_0**: 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.  

---

