92

I have taken over a Ubuntu 14.04 server. It has a user called "deployer" (used with capistrano), and as such, it needs sudo privileges. With this setup, I can log into the server and do stuff like:

workstation> ssh deployer@myserver
myserver>  sudo apt-get install git
myserver> exit
workstation>

I am trying to figure out how to use Ansible (version 2.0.2.0 and python 2.7.3) to create a user called "deployer" and be able to log into the server with that id and then so sudo-ish things like "apt-get install". My playbook looks like this:

---
- hosts: example
  become: yes
  tasks:
  - name: Update apt cache
    apt:
      update_cache: yes
      cache_valid_time: 3600

  - group: name=sudo state=present

  - name: Add deployer user and add it to sudo
    user: name=deployer
          state=present
          createhome=yes
    become: yes
    become_method: "sudo"

  - name: Set up authorized keys for the deployer user
    authorized_key: user=deployer key="{{item}}"
    with_file:
      - /home/jaygodse/.ssh/id_rsa.pub

After running this playbook, I am able to ssh into the machine as "deployer", (e.g. ssh deployer@myserver) but if I run a sudo command, it always asks me for my sudo password.

I understand that the "deployer" user ultimately has to find its way into the visudo users file, but I cannot figure out which magical Ansible incantations to invoke so that I can ssh into the machine as deployer and then run a sudo command (e.g. sudo apt-get install git") without being prompted for a sudo password.

I have searched high and low, and I can't seem to find an Ansible playbook fragment which puts the user "deployer" into the sudo group without requiring a password. How is this done?

Jay Godse
  • 15,163
  • 16
  • 84
  • 131
  • Possible duplicate of [Ansible: best practice for maintaining list of sudoers](https://stackoverflow.com/questions/33359404/ansible-best-practice-for-maintaining-list-of-sudoers) – techraf Aug 21 '18 at 18:56

3 Answers3

180

Sometimes it's knowing what to ask. I didn't know as I am a developer who has taken on some DevOps work.

Apparently 'passwordless' or NOPASSWD login is a thing which you need to put in the /etc/sudoers file.

The answer to my question is at Ansible: best practice for maintaining list of sudoers.

The Ansible playbook code fragment looks like this from my problem:

- name: Make sure we have a 'wheel' group
  group:
    name: wheel
    state: present

- name: Allow 'wheel' group to have passwordless sudo
  lineinfile:
    dest: /etc/sudoers
    state: present
    regexp: '^%wheel'
    line: '%wheel ALL=(ALL) NOPASSWD: ALL'
    validate: 'visudo -cf %s'

- name: Add sudoers users to wheel group
  user:
    name=deployer
    groups=wheel
    append=yes
    state=present
    createhome=yes

- name: Set up authorized keys for the deployer user
  authorized_key: user=deployer key="{{item}}"
  with_file:
    - /home/railsdev/.ssh/id_rsa.pub

And the best part is that the solution is idempotent. It doesn't add the line

%wheel ALL=(ALL) NOPASSWD: ALL

to /etc/sudoers when the playbook is run a subsequent time. And yes...I was able to ssh into the server as "deployer" and run sudo commands without having to give a password.

SuperSandro2000
  • 581
  • 10
  • 20
Jay Godse
  • 15,163
  • 16
  • 84
  • 131
  • 74
    Please add the line `validate: 'visudo -cf %s'` to the end of your `lineinfile:` section to validate prior to saving. Messing up the sudoers file will lock you out of sudo access permanently. – Simon Woodside Dec 23 '16 at 05:46
  • 2
    `authorized_key` [accepts the key as a string](http://docs.ansible.com/ansible/latest/authorized_key_module.html) in the `key` parameter since v1.9 – Tim Nov 26 '17 at 07:19
  • 9
    You can also create/copy a file in `/etc/sudoers.d`, most distributions as a default include line for that... – Gert van den Berg Dec 08 '17 at 16:32
  • Note that the `validate` command will probably need the full path to `visudo` to work. – Matt Hughes May 24 '18 at 17:50
  • @MattHughes `validate: '/usr/sbin/visudo -cf %s'` <- is this what you mean? – Jeter-work Oct 10 '18 at 18:31
  • Why do we add the user to wheel and not directly to sudo group? ```- name: "Granting Administrative Privileges" user: name: deployer groups: sudo append: yes``` – Milad Dec 02 '19 at 11:59
  • 1
    Btw. if you are wondering, what the `%s` in `validate` means, it is the destination (dest) or path of the file that is supposed to be modified. Here is the [documentation](https://docs.ansible.com/ansible/latest/modules/lineinfile_module.html). – AdamKalisz Apr 02 '20 at 09:49
  • 1
    For Ansible 2.3 and later, the parameter dest in lineinfile should be changed to path. – Indika K Aug 03 '20 at 02:41
  • you forgot to ensure that file /etc/sudoers is present – Jens Timmerman Aug 16 '20 at 15:02
  • I don't think its good to enable passwordless sudo for all sudo users. It is suitable for automation accounts but not for human user accounts. Better to just set `deployer ALL=(ALL) NOPASSWD:ALL` – openCivilisation Apr 24 '21 at 01:24
  • @SimonWoodside The Ansible's documentation page for "validate" says: _The validation command to run __before copying__ into place_. Why do you conclude it will check before __saving__? – aderchox Nov 28 '21 at 05:43
23

To create a user with sudo privileges is to put the user into /etc/sudoers, or make the user a member of a group specified in /etc/sudoers. And to make it password-less is to additionally specify NOPASSWD in /etc/sudoers.

Example of /etc/sudoers:

## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL

## Allows people in group wheel to run all commands
%wheel  ALL=(ALL)       ALL

## Same thing without a password
%wheel  ALL=(ALL)       NOPASSWD: ALL

And instead of fiddling with /etc/sudoers file, we can create a new file in /etc/sudoers.d/ directory since this directory is included by /etc/sudoers by default, which avoids the possibility of breaking existing sudoers file, and also eliminates the dependency on the content inside of /etc/sudoers.

To achieve above in Ansible, refer to the following:

- name: sudo without password for wheel group
  copy:
    content: '%wheel ALL=(ALL:ALL) NOPASSWD:ALL'
    dest: /etc/sudoers.d/wheel_nopasswd
    mode: 0440

You may replace %wheel with other group names like %sudoers or other user names like deployer.

pallxk
  • 1,057
  • 14
  • 14
  • 1
    Thanks for this answer. I added `validate: '/usr/sbin/visudo -cf %s'` to make sure that the syntax is correct and won't block you if you have a typo. – Jack Wire Mar 25 '21 at 11:05
1

Although the initial answer is useful and popular, it can be updated based on the newest changes.

  1. There is no group wheel in most modern distributions, but sudo is quite common
  2. You don't need to touch (and break) system files in the /etc directory, but should use an extra path like /etc/sudoers.d
  3. Use true/false boolean variables to be compatible with ansible-lint
  4. I prefer to use variables for any kind of routine code, which can be copy/pasted between projects without changes.

This is the updated version:

- name: Add {{ sudo_user }} user
  user:
    name: "{{ sudo_user }}"
    groups: sudo
    append: true
    state: present
    createhome: true

- name: Make sudo without password for {{ sudo_user }} user
  copy:
    dest: /etc/sudoers.d/80-ansible-sudo-user
    content: "{{ sudo_user }} ALL=(ALL) NOPASSWD:ALL"
    mode: 0440
Roman Shishkin
  • 2,097
  • 20
  • 21