Parse error in sudoers file

I've created a user called kafka to whom I am trying to give a sudo access to run only /etc/init.d/kafka commands.

I added the following entry to /etc/sudoers.d/kafka via Ansible:

kafka ALL = NOPASSWD: /etc/init.d/kafka

However, this breaks sudo completely with the following error:

/etc/sudoers.d/kafka: syntax error near line 1
sudo: parse error in /etc/sudoers.d/kafka near line 1
sudo: no valid sudoers sources found, quitting
sudo: unable to initialize policy plugin

Here's the full Ansible snippet:

- name: Create kafka user's group
  group:
    name: "{{ kafka_group }}"
    state: present

- name: Create kafka user
  user:
    name: "{{ kafka_user }}"
    state: present
    group: "{{ kafka_group }}"
    shell: /bin/bash

- name: Set up password-less sudo for kafka user
  copy:
    content: "{{ kafka_user }} ALL = NOPASSWD: /etc/init.d/{{ kafka_service_name }}"
    dest: "/etc/sudoers.d/{{ kafka_user }}"
    owner: root
    group: root
    mode: 0440

What am I doing wrong?


Solution 1:

A "sudo: parse error in ..." originating from /etc/sudoers or any of the files included with either the #include <filename> or #includedir <path> directives may be caused by a missing new-line on the last entry in that file.

Solution 2:

Using the copy module is probably not the best choice to handle /etc/sudoers with Ansible.

The lineinfile module has an option to validate the file before saving. It is also easier to remove the line, etc with that module.

The documentation contains an example how to use it.

- name: Set up password-less sudo for kafka user
  lineinfile: dest=/etc/sudoers state=present regexp='^%{{ kafka_user }} ALL\=' line='%{{ kafka_user }} ALL= NOPASSWD: /etc/init.d/{{ kafka_service_name }}' validate='visudo -cf %s'