50

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?

mipadi
  • 398,885
  • 90
  • 523
  • 479

7 Answers7

32

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))
Sam Dolan
  • 31,966
  • 10
  • 88
  • 84
  • I do have SSH keys set up. The issue is with the way Fabric passes the command off to sudo, not with SSH. – mipadi Sep 17 '10 at 17:13
  • I see, so what's wrong with just defining the second function? Why complicate things? – Sam Dolan Sep 17 '10 at 17:20
  • As I noted, I've basically already done that. I just wondered if there was a config option or something that I'm missing. – mipadi Sep 17 '10 at 17:39
  • Hrm, thought I had tried that and it didn't work, but I gave it a shot just now and it did. – mipadi Sep 17 '10 at 17:52
  • 2
    Thanks so much for this. One note that was screwing me up: I had this command inside a with block (for my virtualenv) and it was not working (which is probably what user802596 is complaining about). Moving it out of there solved the problem. – Tom Mar 14 '13 at 14:20
  • I did not follow the solution. Do we need to change somethings in fabric/operations.py? – mungayree Apr 01 '20 at 02:59
  • I did not follow the solution. Do we need to modify fabric/operations.py ? – mungayree Apr 01 '20 at 03:00
13

You can use:

from fabric.api import env
# [...]
env.password = 'yourpassword'
Delgan
  • 18,571
  • 11
  • 90
  • 141
5

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

sebastian serrano
  • 1,047
  • 12
  • 12
1

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
fiat
  • 15,501
  • 9
  • 81
  • 103
  • Can you provide a full code example? I'm also running into this issue and your answer seems to be the solution I need. Thanks in advance! – ndequeker Mar 20 '13 at 11:38
  • Sorry - that's all I have. I was actually getting graphite installed - full notes here http://stackoverflow.com/questions/5436606/using-etsys-statsd-in-a-windows-environment/10892374#10892374 – fiat Mar 26 '13 at 09:47
  • Thanks! I have used a shell file for now. – ndequeker Mar 26 '13 at 09:51
  • 1
    The password prompt you faced was the login prompt, not the password prompt for sudo. For your problem, key-based authentication is the correct answer. But for others who find this via Google, it's important to KNOW what is prompting you for a password - in order to solve it. Prompts can originate from 3 places: login, the remote sudo prompt, or even from fabric itself (ie if you call a function with sudo() then Fabric will try the authentication it knows about else it will send you a prompt... even if the remote system did not ask for a prompt). – Scott Prive Feb 18 '14 at 19:29
1

You can also use passwords for multiple machines:

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

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

Community
  • 1
  • 1
Dave Halter
  • 15,556
  • 13
  • 76
  • 103
1

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.

CanSpice
  • 34,814
  • 10
  • 72
  • 86
0

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 '
Community
  • 1
  • 1
lingfish
  • 422
  • 5
  • 6