Fabric Sudo No Password Solution
Asked Answered
K

7

7

This question is about best practices. I'm running a deployment script with Fabric. My deployment user 'deploy' needs sudo to restart services. So I am using the sudo function from fabric to run these commands in my script. This works fine but prompts for password during script execution. I DON'T want to type a password during deployments. What's the best practice here. The only solution I can think of is changing the sudo permissions to not require password for the commands my deployment user runs. This doesn't seem right to me.

Kaliningrad answered 18/12, 2012 at 23:43 Comment(1)
You could look into adding a new user, specifically for deploys, who has access to the commands you need to run without using sudo.Norman
J
-2

As Bartek also suggests, enable password-less sudo for the deployment 'user' in the sudoers file.

Something like:

run('echo "{0} ALL=(ALL) ALL" >> /etc/sudoers'.format(env.user))
Joby answered 19/12, 2012 at 13:30 Comment(2)
This is not really a good way for a couple of reasons. First, it will append this line every time the command is run. Second, the sudoers file is not meant to be modified in this way. If there is an error in the sudoers file, you may not be able to run the sudo command again without gaining root access manually.Thalassography
My answer is to enable passwordless sudo. How the user does this is another question, I just suggested one method. And yes the user should be aware of the pitfalls you mention.Joby
T
6

The ideal solution is to create a user on your server that is used only for deployment (eg, deploy). Then, set env.user=deploy in your fabfile. Then on your servers, you can give the user the necessary permission on a command-by-command basis in a sudoers file:

IMPORTANT: Always use sudo visudo to modify a sudoers file

Cmnd_Alias RELOAD_SITE = /bin/bash -l -c supervisorctl*, /usr/bin/supervisorctl*
deploy ALL = NOPASSWD: RELOAD_SITE

You can add as many Cmnd_Alias directives as is needed by the deploy user, then grant NOPASSWD access for each of those commands. See man sudoers for more details.

I like to keep my deploy-specific sudoers config in /etc/sudoers.d/deploy and include that file from /etc/sudoers by adding: includedir /etc/suoders.d at the end.

Thalassography answered 25/8, 2014 at 22:54 Comment(0)
L
2

You can use:

fabric.api import env
# [...]
env.password = 'yourpassword'
Lorna answered 13/5, 2013 at 11:41 Comment(1)
These stuff goes into vcs revealing passwords is never the best idea , especially we are talking about a server password here .Moderation
D
2

The best way to do this is with subtasks. You can prompt for a password in the fabfile and never expose any passwords, nor make reckless configuration changes to sudo on the remote system(s).

import getpass

from fabric.api import env, parallel, run, task
from fabric.decorators import roles
from fabric.tasks import execute


env.roledefs = {'my_role': ['host1', 'host2']}


@task
# @parallel -- uncomment if you need parallel execution, it'll work!
@roles('my_role')
def deploy(*args, **kwargs):
    print 'deploy args:', args, kwargs
    print 'password:', env.password
    run('echo hello')


@task
def prompt(task_name, *args, **kwargs):
    env.password = getpass.getpass('sudo password: ')
    execute(task_name, *args, role='my_role', **kwargs)

Note that you can even combine this with parallel execution and the prompt task still only runs once, while the deploy task runs for each host in the role, in parallel.

Finally, an example of how you would invoke it:

$ fab prompt:deploy,some_arg,another_arg,key=value
Delisle answered 23/4, 2016 at 14:41 Comment(0)
O
1

Seems like sudo may not be that bad of an option after all. You can specify which commands a user can run and the arguments the command may take (man sudoers). If the problem is just having to type the password, an option would involve using the pexpect module to login automatically, maybe with a password that you could store encrypted:

import pexpect, sys

pwd = getEncryptedPassword()
cmd = "yourcommand" 

sCmd = pexpect.spawn('sudo {0}'.format(cmd))
sCmd.logfile_read = sys.stdout
sCmd.expect('Password:')
sCmd.sendline(pwd)
sCmd.expect(pexpect.EOF)
Osteal answered 19/12, 2012 at 1:57 Comment(0)
K
1

Use the keyring module to store and access passwords securely.

Here's how I do it with Fabric 2:

from fabric import task
import keyring

@task
def restart_apache(connection):
    # set the password with keyring.set_password('some-host', 'some-user', 'passwd')
    connection.config.sudo.password = keyring.get_password(connection.host, 'some-user')
    connection.sudo('service apache2 restart')

You could also use GPG or any other command-line password tool. For example:

connection.config.sudo.password = connection.local('gpg --quiet -d /path/to/secret.gpg', hide=True).strip()

The secret.gpg file can be generated with echo "mypassword" | gpg -e > secret.gpg. The hide argument avoids echoing the password to the console.

To retain support for --prompt-for-sudo-password, add a conditional:

if not connection.config.sudo.password:
    connection.config.sudo.password = keyring.get_password(connection.host, 'some-user')
Kenogenesis answered 28/12, 2018 at 21:55 Comment(0)
M
-1

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://mcmap.net/q/355936/-fabric-password

Manado answered 28/9, 2013 at 12:37 Comment(0)
J
-2

As Bartek also suggests, enable password-less sudo for the deployment 'user' in the sudoers file.

Something like:

run('echo "{0} ALL=(ALL) ALL" >> /etc/sudoers'.format(env.user))
Joby answered 19/12, 2012 at 13:30 Comment(2)
This is not really a good way for a couple of reasons. First, it will append this line every time the command is run. Second, the sudoers file is not meant to be modified in this way. If there is an error in the sudoers file, you may not be able to run the sudo command again without gaining root access manually.Thalassography
My answer is to enable passwordless sudo. How the user does this is another question, I just suggested one method. And yes the user should be aware of the pitfalls you mention.Joby

© 2022 - 2024 — McMap. All rights reserved.