Jay Godse
Jay Godse

Reputation: 15503

Ansible: create a user with sudo privileges

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?

Upvotes: 94

Views: 186235

Answers (4)

Roman Shishkin
Roman Shishkin

Reputation: 2605

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

  1. Some distros use sudo instead of wheel
  2. You don't need to touch (and risk breaking) 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

Upvotes: 11

Jarmos
Jarmos

Reputation: 456

The answers shared above were pretty helpful for me to resolve this issue I was dealing with. Taking inspiration from the aforementioned I came up with a more robust and graceful solution:

- name: "Ensure the {{ ansible_user }} User is in the "wheel" Group"
  ansible.builtin.user:
    name: "{{ ansible_user }}"
    groups: wheel
    append: true

- name: Ensure "/etc/sudoers.d/" Directory Exists
  ansible.builtin.file:
    path: /etc/sudoers.d
    state: directory
    owner: root
    group: root
    mode: "0750"

- name: "Allow the {{ ansible_user }} User to Use sudo Without Password"
  ansible.builtin.copy:
    dest: "/etc/sudoers.d/{{ ansible_user }}"
    content: "{{ ansible_user }} ALL=(ALL) NOPASSWD:ALL\n"
    owner: root
    group: root
    mode: "0440"
    validate: "/usr/sbin/visudo --check --file=%s"

The solution above allows me to ensure:

  1. The user I am "becoming" is added to the wheel group (on RedHat distros like Fedora, the equivalent of it on Debian/Ubuntu and the rest is the sudo group).

  2. The /etc/sudoers.d/ directory exists (it did not on Fedora 41 Server) with appropriate access permissions.

  3. Configure the sudoers list with my user with a directive to to require a password when using sudo. The directive is validated before it is copied to its destination. A validation failure ensures there is no broken directives passed to the /etc/sudoers.d directory.

Upvotes: 0

Jay Godse
Jay Godse

Reputation: 15503

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.

Upvotes: 184

Xiangkun
Xiangkun

Reputation: 1107

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.

Upvotes: 23

Related Questions