Quick Tip: Ansible commands as non-root user with environment variables

This is a short quick tip. When executing Ansible playbooks, you might need to execute a task as another user than the one you established the connection with. This post shows an example how to do it and deal with the environment variables.

Change history:
Date Change description
2018-01-19 The first release

While working on my previous post Elastic Stack (formerly ELK) - Elasticsearch I had the need to run a task as another user and with specific environment variables set. It took me surprisingly long to figure out a way to do it, so here it is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
---


# ===========================================================================
# Set up Elasticsearch on central logging host
# ===========================================================================
- hosts: es1
  become: true
  gather_facts: false

  vars:
    user_name: elastic
    user_password: elastic
    user_group: elastic

  tasks:

    - name: "Create a group for Elasticsearch."
      group:
        name: "{{ user_group }}"
        state: present

    - name: "Allow passwordless sudo for group {{ user_group }}"
      lineinfile:
        dest: /etc/sudoers
        state: present
        regexp: "^%{{ user_group }}"
        line: "%{{ user_group }} ALL=(ALL) NOPASSWD: ALL"
        validate: 'visudo -cf %s'

    - name: "Creating user for Elasticsearch group."
      user:
        name: "{{ user_name }}"
        groups: "{{ user_group }}"
        append: true
        createhome: true
        system: true
        state: present

    - name: "Run elasticsearch as daemon."
      environment:
        ES_NETWORK_HOST: "{{ ansible_enp0s8.ipv4.address }}"
        ES_NODE_NAME: "{{ ansible_hostname }}"
      command: "sudo -E -u {{ user_name }} ./bin/elasticsearch -d -p pid"
      args:
        chdir: /home/elastic/elasticsearch-6.1.1/
      async: 10
      poll: 0

The most important part is sudo -E -u [1]:

  • For -E, the man page says:

    The -E (preserve environment) option indicates to the security
    policy that the user wishes to preserve their existing environment
    variables. [...]
    
  • For -u, the man page says:

    The -u (user) option causes sudo to run the specified
    command as a user other than root. [...]
    

As you already guessed, the environment variables get set for the root user and the context switch with sudo preserves these variables for the other user. The started binary ./bin/elasticsearch uses these environment variables to populate placeholders in a not shown config file. I’ve shown it here with Elasticsearch specifics, but there are other situations where you and I might need this in the future.

Warning

Although this gets the job done, it feels somehow wrong and probably any of the other options listed at [2] are more appropriate. I didn’t yet had the time to wrap my head around the impact of the solutions proposed there.