Why does 'ansible -a "env"' return a different environment PATH than my user?

Any time i used ansible it ran as a different user..under a different shell. should be able to see what user by doing:

ansible -a "id"

you can then see the user shell defined in: cat /etc/passwd

Best practice to add to the path would be by adding a line in: /home/<username>/.profile or ~/.bash_profile


ansible -a is using the command module and this doesn't use a shell to execute the command.

http://docs.ansible.com/ansible/intro_adhoc.html
Normally commands also take a -m for module name, but the default module name is ‘command’.

The components of the path, such as /usr/sbin are added to the path by by the shell sourcing the /etc/profile file, and the command module doesn't create login shell so it won't read that file.

http://linux.die.net/man/1/bash
When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The --noprofile option may be used when the shell is started to inhibit this behavior.

The ansible docs say that if you want a shell, to use the shell module. However it doesn't seem that there is an option to start a login shell from the shell module (by passing the --login option) anyway.

In fact, it is mentioned in various places that the ansible policy is to not trust the environment, and to set any VARS explicitly when the task is defined.

However it is possible to set the path when using ansible in ad-hoc mode. These are the nearest I could do to replicate the PATH you see in an interactive /bin/bash shell;

$ ansible raspberrypi -m shell \
-a 'PATH=$PATH:/usr/local/sbin:/usr/sbin:$HOME/bin  env' \
 | grep PATH

PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/usr/local/sbin:
/usr/sbin:/home/pi/bin

or alternatively, you can source the /etc/profile file;

 $ ansible raspberrypi -m shell \
 -a 'executable=/bin/bash source /etc/profile ; env | grep PATH'

 PATH=/opt/consul/bin:/usr/local/sbin:/usr/local/bin:
 /usr/sbin:/usr/bin:/sbin:/bin

this seems to work also;

$ ansible raspberrypi -a '/bin/bash -l -c "env"'

 PATH=/opt/consul/bin:/usr/local/sbin:/usr/local/bin:
 /usr/sbin:/usr/bin:/sbin:/bin

So given your question is ultimately about running commands under sudo with ansible, I had another look at how the PATH is set when using ansible -s -a env. I think its important to notice that when using the sudo -s flag in ansible, the $PATH is set by a different mechanism to when using only ansible -a env.

When using sudo command or ansible -s the users environment is reset, and $PATH is controlled by the Default secure_path setting in /etc/sudoers and this is explained in the man sudoers documentation;

By default, the env_reset option is enabled. This causes commands to be executed with a new, minimal environment. The new environment contains the TERM, PATH, HOME, MAIL, SHELL, LOGNAME, USER, USERNAME and SUDO_* variables in addition to variables from the invoking process permitted by the env_check and env_keep options.

If you don't set a value for Default secure_path, then these values are hard coded into the sshd binary, see this answer for details.

However by default on fedora/centros/ubuntu the value for $PATH is taken from secure_path set in /etc/sudoers;

secure_path - Path used for every command run from sudo.

For example on my fedora localhost, it has the following line in /etc/sudoers

Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin

and if I run the env command remotely by ssh and sudo I get that exact path back;

$ ssh localhost "sudo env" | grep PATH
PATH=/sbin:/bin:/usr/sbin:/usr/bin

and I get the same thing using ansible;

$ ansible localhost -s -a 'env' | grep PATH
PATH=/sbin:/bin:/usr/sbin:/usr/bin

and I've tried the same thing on a raspbian(debian) instance, and I get similar behaviour;

$ ansible raspberrypi -s -a 'cat /etc/sudoers' | grep secure
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

and that is the path that ansible sees with the -s -a options;

$ ansible raspberrypi -s -a env | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

So in respect of your original question, I would take a look at the /etc/sudoers file, and check the value of Defaults secure_path="/some/path/here".

If you do not have a value there which includes the appropriate sbin/ directory, then the following command in ansible is not going to work without a full path given;

ansible multi -s -a "service ntpd stop"