Can I prevent fabric from prompting me for a sudo password?

PythonSudoFabric

Python Problem Overview


I am using Fabric to run commands on a remote server. The user with which I connect on that server has some sudo privileges, and does not require a password to use these privileges. When SSH'ing into the server, I can run sudo blah and the command executes without prompting for a password. When I try to run the same command via Fabric's sudo function, I get prompted for a password. This is because Fabric builds a command in the following manner when using sudo:

sudo -S -p <sudo_prompt> /bin/bash -l -c "<command>"

Obviously, my user does not have permission to execute /bin/bash without a password.

I've worked around the problem by using run("sudo blah") instead of sudo("blah"), but I wondered if there is a better solution. Is there a workaround for this issue?

Python Solutions


Solution 1 - Python

Try passing shell=False to sudo. That way /bin/bash won't be added to the sudo command. sudo('some_command', shell=False)

From line 503 of fabric/operations.py:

if (not env.use_shell) or (not shell):
    real_command = "%s %s" % (sudo_prefix, _shell_escape(command))

the else block looks like this:

                                             # V-- here's where /bin/bash is added
real_command = '%s %s "%s"' % (sudo_prefix, env.shell,
    _shell_escape(cwd + command))

Solution 2 - Python

You can use:

from fabric.api import env
# [...]
env.password = 'yourpassword'

Solution 3 - Python

This is the most direct answer to your question: You do not actually have a problem; you misunderstand how Fabric run() and sudo() work.

Your "workaround" is NOT a workaround it is the 100% valid answer to the problem.

Here's a simple set of rules:

  1. Use "run()" when you don't expect a prompt.
  2. use "sudo()" when you do expect a prompt. (this should be true for all or most commands requiring a prompt, even if the executable in question is not Bash or Sudo).

This same answer applies to folks trying to run commands under "sudo". Even if sudoers has passwordless config for the current user on some system, if you use sudo() instead of run() then you will force a prompt (unless the Fabric code already contains an ENV password or key).

BTW the author of Fabric answered my question - very similar to your question - in #IRC. Nice guy, one of the unsung heroes of open source for persisting in his Fabric and Paramiko work.

...In my test environment, there is always 1 username which has full password-less access to sudo. Typing sudo echo hello will not prompt me. Furthermore, that sudo user is configured with "!requiretty" so all commands can run over SSH (like SSH hopping between hosts). This means I can simply use "run()" with to execute "sudo something", but it's just another command which runs without a prompt. As far as security is concerned, it is someone's job to lock down a production host but not a test host. (If you are being forced to test things by and and can not automate, that is a huge problem).

Solution 4 - Python

In your /etc/sudoers file add

user ALL=NOPASSWD: some_command

where user is your sudo user and some_command the command you want to run with fabric, then on the fabric script run sudo it with shell=False:

sudo('some_command', shell=False)

this works for me

Solution 5 - Python

In your /etc/sudoers file, you could add

user ALL=NOPASSWD: /bin/bash

...where user is your Fabric username.

Obviously, you can only do this if you have root access, as /etc/sudoers is only writable by root.

Also obviously, this isn't terribly secure, as being able to execute /bin/bash leaves you open to essentially anything, so if you don't have root access and have to ask a sysadmin to do this for you, they probably won't.

Solution 6 - Python

Linux noob here but I found this question while trying to install graphite-fabric onto an EC2 AMI. Fabric kept prompting for a root password.

The evntual trick was to pass in the ssh private key file to fabric.

fab -i key.pem graphite_install -H root@servername

Solution 7 - Python

You can also use passwords for multiple machines:

from fabric import env
env.hosts = ['user1@host1:port1', '[email protected]']
env.passwords = {'user1@host1:port1': 'password1', '[email protected]': 'password2'}

See this answer: https://stackoverflow.com/a/5568219/552671

Solution 8 - Python

I recently faced this same issue, and found Crossfit_and_Beer's answer confusing.

A supported way to achieve this is via using env.sudo_prefix, as documented by this github commit (from this PR)

My example of use:

env.sudo_prefix = 'sudo '

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmipadiView Question on Stackoverflow
Solution 1 - PythonSam DolanView Answer on Stackoverflow
Solution 2 - PythonGabriel Gcia FdezView Answer on Stackoverflow
Solution 3 - PythonScott PriveView Answer on Stackoverflow
Solution 4 - Pythonsebastian serranoView Answer on Stackoverflow
Solution 5 - PythonCanSpiceView Answer on Stackoverflow
Solution 6 - PythonfiatView Answer on Stackoverflow
Solution 7 - PythonDave HalterView Answer on Stackoverflow
Solution 8 - PythonlingfishView Answer on Stackoverflow