Answers: <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>
  
Answers: CC BY-SA 4.0
Answers: 2018-08-13T04:40:34.737Z
Answers: I like the second part. We should refrain from using less as sudo command.
Answers: Prakash
Answers: CC BY-SA 4.0
Answers: 2018-08-13T05:08:20.857Z
Answers: 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,
Answers: Jiri Klouda
Answers: CC BY-SA 4.0
Answers: 2018-08-12T16:54:43.047Z
Answers: 2018-08-13T05:27:06.520Z
Answers: 2018-08-13T05:27:06.520Z
Answers: Jiri Klouda
Answers: <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>
  
Answers: CC BY-SA 4.0
Answers: 2018-08-11T13:56:25.607Z
Answers: 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.
Answers: Prakash
Answers: CC BY-SA 4.0
Answers: 2018-08-10T08:46:07.133Z
Answers: 2019-03-06T17:41:17.493Z
Answers: 2019-03-06T17:41:17.493Z
Answers: mvk_il
Body: <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>
  
Comments: CC BY-SA 4.0
Comments: 2018-08-09T07:47:10.803Z
Comments: I would just place the full path of the command in your vars
Comments: jdog
Comments: CC BY-SA 4.0
Comments: 2018-08-09T09:45:07.947Z
Comments: For modifications on system i prefer including scripts in bash to run better.
Comments: lORD
Tags: <ansible>
Title: Modify sudoers file with ansible playbook template
UserDisplayName: Prakash
ThreadText: # 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](https://unix.stackexchange.com/questions/349691/how-to-modify-sudoers-file-with-ansible/349712)
  
  **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.  
  
  ---
  
  