Search code examples
postgresqlpsqlsudofish

Command not found when running as other user with sudo


I am trying to run psql with user postgres. When I run sudo su - postgres AND THEN psql from within the new session, it is working smoothly. In fact, the ~/.bashrc in that session with use postgres has the correct PATH.

However, if I run sudo -u postgres psql, I get sudo: psql: command not found. Even though the session where I am running this command (I use the FISH shell) has the correct PATH as well, and I can invoke psql without the full path with my user.

I need to invoke the command as sudo -u postgres psql, how can this behavior be explained?

Edit: if (from FISH) I switch to BASH and run sudo -u postgres psql, it works! I guess it has to do with the FISH path then...

Edit 2: The issue seems to be that the PATH is reset when using sudo.

➜  ~ psql
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  role "opc" does not exist
➜  ~ sudo -u postgres psql
sudo: psql: command not found
➜  ~ echo $PATH
/home/opc/.local /home/opc/.local/bin /usr/pgsql-15/bin /usr/pgsql-15/bin /usr/local/bin /usr/bin /usr/local/sbin /usr/sbin
➜  ~ sudo echo $PATH
/home/opc/.local /home/opc/.local/bin /usr/pgsql-15/bin /usr/pgsql-15/bin /usr/local/bin /usr/bin /usr/local/sbin /usr/sbin
➜  ~ sudo -u postgres /usr/pgsql-15/bin/psql
could not change directory to "/home/opc": Permission denied
psql (15.1)
Type "help" for help.

postgres=#

But if I echo $PATH with sudo, it seems fine...


Solution

  • This is caused by a sudo configuration that has the "secure_path" setting. This causes sudo to reset $PATH to a hardcoded "known safe" value. This might be enabled by your distribution.

    When you run sudo bash, that bash will read its settings, including .bashrc, and if you set $PATH in that it will then, of course, have that $PATH again.

    But if you run a command without going through a shell that resets $PATH, you'll get the hardcoded setting.

    It's possible to change that setting by running sudo visudo and changing the line that says

    Defaults secure_path="some:path:here"
    

    to

    Defaults !secure_path
    

    An alternative is to just run the command via the fully qualified path, like

    sudo -u postgres (command -s psql)
    

    One more comment about your tests:

    sudo echo $PATH

    This doesn't do what you want. The $PATH will be expanded by the shell that runs sudo, and so sudo won't ever see anything but the value of it. It is exactly equivalent to running sudo echo /home/opc/.local /home/opc/.local/bin /usr/pgsql-15/bin ....

    You might want to use something like

    sudo env
    

    or

    sudo sh -c 'echo $PATH'
    

    instead.