HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Modify sudoers file with ansible playbook template

Submitted by: @import:stackexchange-devops··
0
Viewed 0 times
filesudoerstemplatewithplaybookansiblemodify

Problem

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

Solution

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

Code Snippets

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

%support1 ALL=(ALL) NOPASSWD: LS, LESS, DU
%support1 ALL=(ALL) NOPASSWD: /bin/ls
%support1 ALL=(ALL) NOPASSWD: /bin/cat
%support1 ALL=(ALL) NOPASSWD: /usr/bin/du
- name: add templates
  template:
    src: {{ item }}
    dest: /{{ item }}
    owner: root
    group: root
    mode: 0640
  with_items:
    - etc/sudoers.d/support1
sudoers.support1.commands:
- { alias: "LS", path: "/bin/ls" }
- { alias: "DU", path: "/usr/bin/du" }
{% for item in sudoers.{{ group }}.commands %}
Cmnd_Alias {{ item.alias }} = {{ item.path }}
{% endfor %}
%{{ group }} ALL=(ALL) NOPASSWD: {{ sudoers.{{ group }}.commands | map(attribute='alias') | join(', ') }}

Context

StackExchange DevOps Q#4716, answer score: 6

Revisions (0)

No revisions yet.