Running commands as a user without a login shell

I’m attempting to run a command as a user without a login shell. My task(s) looks like the following:

- name: test task 
  become: true
  become_user: ucd
  become_flags: "-s /usr/bin/bash"
  ansible.builtin.command:
    cmd: whoami
  register: testvalue

- name: debug test
  debug:
    msg: "{{ testvalue }}"

on my test box the ucd user has the following set in the /etc/passwd file:

$ sudo grep ucd /etc/passwd
ucd:x:995:992::/home/ucd:/sbin/nologin

when I run my playbook I receive the following error:

TASK [java : test task] ************************************************************************
fatal: [dtest08]: FAILED! => changed=true 
  module_stderr: |-
    Shared connection to 192.168.40.131 closed.
  module_stdout: |-
    /usr/bin/bash: ucd: No such file or directory
  msg: |-
    MODULE FAILURE
    See stdout/stderr for the exact error
  rc: 127

However, if I change my task to the following:

- name: test task
  ansible.builtin.command:
    cmd: sudo -u ucd -s /usr/bin/bash -c whoami
  register: testvalue

- name: debug test
  debug:
    msg: "{{ testvalue }}"

everything works as it should:

ASK [java : test task] *************************************************************************************************************************************************************************************************************
changed: [dtest08]

TASK [java : debug test] ************************************************************************************************************************************************************************************************************
ok: [dtest08] => 
  msg:
    changed: true
    cmd:
    - sudo
    - -u
    - ucd
    - -s
    - /usr/bin/bash
    - -c
    - whoami
    delta: '0:00:00.032662'
    end: '2023-12-06 10:36:40.532027'
    failed: false
    msg: ''
    rc: 0
    start: '2023-12-06 10:36:40.499365'
    stderr: ''
    stderr_lines: []
    stdout: ucd
    stdout_lines:
    - ucd

I would expect the become items on the first task would act the same was as the sudo parameters. My question is what is the best way to accomplish running commands as a non-root user that does not have a login shell.

My use case, is I need to install an application via script file (.sh), and I’m testing with the whoami command for testing since the install script was failing

Perhaps you need to specify a become_method?

Perhaps Bash is at /bin/bash (this is the case on older versions of Debian)? EDIT: Clearly Bash is available at /usr/bin/bash as you second example showed.

1 Like

Unfortunately, setting become_method: sudo results in the same error.

Does the $HOME directory /home/ucd exist?

Running with a higher verbosity level (-vvv or higher) should show the actual escalation command that’s run, which may help in figuring out what’s going on.

2 Likes

Ah, you’re using -s incorrectly.

     -s, --shell
                 Run the shell specified by the SHELL environment variable
                 if it is set or the shell specified by the invoking user's
                 password database entry.  If a command is specified, it is
                 passed to the shell for execution via the shell's -c op‐
                 tion.  If no command is specified, an interactive shell is
                 executed.  Note that most shells behave differently when a
                 command is specified as compared to an interactive session;
                 consult the shell's manual for details.

It does not take an argument, so /usr/bin/bash is interpreted by sudo as a positional argument, and due to the different placement of -u ucd in Ansible’s version of the command you get the output that you showed.

Ansible’s sudo usage does not invoke the shell from the user’s password database entry by default, so all you should need to do is specify become_user and not mess with the flags.

- hosts: localhost
  tasks:
    - command: whoami
      become_user: mail
ec2-user@pandora ansible $ grep mail /etc/passwd
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

ec2-user@pandora ansible $ ansible-playbook ~/test.yml -v

PLAY [localhost] ***************************************************************

TASK [command] ***************************************************************

changed: [localhost] =>
    changed: true
    cmd:
    - whoami
    delta: '0:00:00.004282'
    end: '2023-12-07 11:57:37.151609'
    msg: ''
    rc: 0
    start: '2023-12-07 11:57:37.147327'
    stderr: ''
    stderr_lines: <omitted>
    stdout: mail
    stdout_lines: <omitted>
4 Likes

Removing the become_flags from the task worked. I just assumed (I know I shouldn’t assume) that since I need to do that on the command line, I would need to do that here with ansible.

3 Likes

You also don’t need to do that on the command line.

ec2-user@pandora ansible $ sudo -u mail whoami
mail

You do need either -s or to specify a shell as the command (both together works, but unnecessarily spawns two shells) if you want an interactive session, but noninteractive sudo execution doesn’t invoke the user’s shell.

ec2-user@pandora ansible $ sudo -u mail -i
This account is currently not available.
ec2-user@pandora ~ $ sudo -u mail -s
bash-5.1$
exit
ec2-user@pandora ~ $ sudo -u mail /bin/dash
$
2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.