10

Say I have a fabfile.py that looks like this:

def setup():                                
    pwd = getpass('mysql password: ')
    run('mysql -umoo -p%s something' % pwd)

The output of this is:

[host] run: mysql -umoo -pTheActualPassword

Is there a way to make the output look like this?

[host] run: mysql -umoo -p*******

Note: This is not a mysql question!

gak
  • 32,061
  • 28
  • 119
  • 154

5 Answers5

9

Rather than modifying / overriding Fabric, you could replace stdout (or any iostream) with a filter.

Here's an example of overriding stdout to censor a specific password. It gets the password from Fabric's env.password variable, set by the -I argument. Note that you could do the same thing with a regular expression, so that you wouldn't have to specify the password in the filter.

I should also mention, this isn't the most efficient code in the world, but if you're using fabric you're likely gluing a couple things together and care more about manageability than speed.

#!/usr/bin/python

import sys
import string
from fabric.api import *
from fabric.tasks import *
from fabric.contrib import *

class StreamFilter(object):

    def __init__(self, filter, stream):
        self.stream = stream
        self.filter = filter

    def write(self,data):
        data = data.replace(self.filter, '[[TOP SECRET]]')
        self.stream.write(data)
        self.stream.flush()

    def flush(self):
        self.stream.flush()

@task
def can_you_see_the_password():
    sys.stdout = StreamFilter(env.password, sys.stdout)
    print 'Hello there'
    print 'My password is %s' % env.password 

When run:

fab -I can_you_see_the_password
Initial value for env.password:

this will produce:

Hello there
My password is [[TOP SECRET]]
Community
  • 1
  • 1
synthesizerpatel
  • 27,321
  • 5
  • 74
  • 91
  • I imagine that if the OP doesn't want his password in his terminal logs then he probably doesnt want his password sitting around in a `.py` file. – Chris W. May 19 '12 at 00:28
  • 1
    he could also use a regex on the password prompt to the end of the line.. do you have a better idea or just like to nitpick? :) – synthesizerpatel May 21 '12 at 09:49
  • In Fabric you can get the password using `env.password` so you don't need it in the .py file, but it only seems to be set in the task, not in the global environment. Also I found I had to also implement `flush` in StreamFilter. – Mark Butler Jan 21 '16 at 03:04
  • 1
    In order to be able to use fabric shell input prompts (e.g. when no hostname was specified), I had to add a method `def __getattr__(self, attr_name): return getattr(self.stream, attr_name)` to the class in order not to run into errors when fabric queried some other stream properties. – Dirk Feb 08 '17 at 17:17
1

It may be better to put the password in the user's ~/.my.cnf under the [client] section. This way you don't have to put the password in the python file.

[client]
password=TheActualPassword
Rob Olmos
  • 2,372
  • 15
  • 24
  • I clarified the question. I am only using mysql as an example, as the command I'm using does not have an alternate option to the command line. – gak Sep 06 '10 at 22:31
1

When you use the Fabric command run, Fabric isn't aware of whether or not the command you are running contains a plain-text password or not. Without modifying/overriding the Fabric source code, I don't think you can get the output that you want where the command being run is shown but the password is replaced with asterisks.

You could, however, change the Fabric output level, either for the entire Fabric script or a portion, so that the command being run is not displayed. While this will hide the password, the downside is that you wouldn't see the command at all.

Take a look at the Fabric documentation on Managing Output.

Matthew Rankin
  • 457,139
  • 39
  • 126
  • 163
0

Write a shell script that invokes the command in question with the appropriate password, but without echoing that password. You can have the shell script lookup the password from a more secure location than from your .py files.

Then have fabric call the shell script instead.

This solves both the problem of having fabric not display the password and making sure you don't have credentials in your source code.

numbsafari
  • 351
  • 4
  • 8
0
from fabric.api import run, settings
with settings(prompts={'Enter password: ': mysql_password}):
    run("mysql -u {} -p -e {}".format(mysql_user,mysql_query))

or if no prompt available:

from fabric.api import run, hide
with hide('output','running','warnings'):
   run("mycommand --password {}".format(my_password))
James Soubry
  • 1,142
  • 8
  • 4