我希望能够使用fabric在远程Ubuntu 10.4
框中更新我的密码。
我希望我的fabfile.py
看起来像这样:
def update_password(old_pw, new_pw):
# Connects over ssh with a public key authentication
run("some_passwd_cmd --old %s --new %s" % (old_pw, new_pd))
不幸的是,我所知道的唯一命令是允许更改密码passwd
,而在Ubuntu 10.4上似乎没有任何方法可以将新(或旧)密码作为参数传递给passwd
。
可以使用什么命令通过fabric
在Ubuntu 10.4上更改用户密码?
修改:
我已经看了usermod -p
,这可能会有效,但手册页不建议这样做。
编辑:出于某种原因,usermod -p
无法通过结构进行操作。
同样,我在mikej的答案中尝试了一种(有些不安全的)变体来解决问题:
# connecting & running as root.
from fabric.api import *
from fabric.contrib import files
files.append("%s\n%s" % (passwd, passwd), '.pw.tmp')
# .pw.tmp:
# PASSWD
# PASSWD
run("passwd %s < .pw.tmp" % user)
run("rm .pw.tmp")
这不是一个非常优雅的解决方案,但它确实有效。
感谢您的阅读。
布赖恩
答案 0 :(得分:14)
您可以使用passwd
例如
echo
echo -e "oldpass\\nnewpass\\nnewpass" | passwd
(-e
的{{1}}选项启用了反斜杠转义的解释,因此换行符被解释为这样)
答案 1 :(得分:10)
诀窍是使用usermod
和Python crypt
的组合来更改密码:
from crypt import crypt
from getpass import getpass
from fabric.api import *
def change_password(user):
password = getpass('Enter a new password for user %s:' % user)
crypted_password = crypt(password, 'salt')
sudo('usermod --password %s %s' % (crypted_password, user), pty=False)
答案 2 :(得分:5)
我在Ubuntu 11.04上使用chpasswd
fabric.api.sudo('echo %s:%s | chpasswd' % (user, pass))
注意: 通常这种模式不起作用:
$ sudo echo bla | restricted_command
因为只有'echo'获得了提升权限,而不是'restricted_command'。
但是,这里有效,因为当fabric.api.sudo被篡改时 使用shell = True(默认值),结构组装命令如下:
$ sudo -S -p <sudo_prompt> /bin/bash -l -c "<command>"
sudo生成一个新的shell(/ bin / bash),以root权限运行,和 那个升级的shell运行命令。
使用sudo管道的另一种方法是使用sudo tee:
答案 3 :(得分:3)
出于兴趣,我必须在一组Solaris盒子上做一个类似的任务(添加很多用户,设置他们的密码)。 Solaris usermod没有--password选项,所以在过去我使用Expect来做这件事,但编写Expect脚本可能很痛苦。
所以这次我将使用Python的crypt.crypt,直接编辑/ etc / shadow(当然还有备份)。 http://docs.python.org/release/2.6.1/library/crypt.html
评论者建议使用管道传输的各种回声咒语。 AFAIK这将永远不会工作,因为passwd被编程为忽略来自stdin的输入并且仅接受来自交互式tty的输入。见http://en.wikipedia.org/wiki/Expect
答案 4 :(得分:1)
我没有其他方法的运气。以为我会分享我曾经使用过的一次性脚本的方法。
它使用自动响应器在提示符下键入密码。然后,我立即使所有密码失效,以便用户有机会选择自己的密码。
这不是最安全的方法,但是根据您的用例,它可能会有用。
from collections import namedtuple
from getpass import getpass
import hashlib
from invoke import Responder
import uuid
from fabric import Connection, Config
User = namedtuple('UserRecord', ('name', 'password'))
def set_passwords(conn, user):
print(f'Setting password for user, {user.name}')
responder = Responder(
pattern=r'(?:Enter|Retype) new UNIX password:',
response=f'{user.password}\n',
)
result = conn.sudo(f'passwd {user.name}', warn=True, hide='both',
user='root', pty=True, watchers = [responder])
if result.exited is not 0:
print(f'Error, could not set password for user, "{user.name}". command: '
f'{result.command}; exit code: {result.exited}; stderr: '
f'{result.stderr}')
else:
print(f'Successfully set password for {user.name}')
def expire_passwords(conn, user):
print(f'Expiring password for user, {user.name}')
cmd = f'passwd --expire {user.name}'
result = conn.sudo(cmd, warn=True, user='root')
if result.exited is not 0:
print(f'Error, could not expire password for user, "{user.name}". '
f'command: {result.command}; exit code: {result.exited}; stderr: '
f'{result.stderr}')
else:
print(f'Successfully expired password for {user.name}')
def gen_password(seed_string):
# Don't roll your own crypto. This is for demonstration only and it is
# expected to only create a temporary password that requires changing upon
# initial login. I am no cryptography expert, hence this alternative
# simplified answer to the one that uses crypt, salt, etc -
# https://stackoverflow.com/a/5137688/1782641.
seed_str_enc = seed_string.encode(encoding='UTF-8')
uuid_obj = uuid.UUID(int=int(hashlib.md5(seed_str_enc).hexdigest(), 16))
return str(uuid_obj)[:8]
def some_function_that_returns_something_secret(conn):
return f'dummy-seed-{conn}'
sudo_pass = getpass('Enter your sudo password:')
config = Config(overrides={'sudo': {'password': sudo_pass}})
with Connection('vm', config=config) as vm_conn:
print(f'Making a new connection to {vm_conn.host}.')
# I usually use the sudo connection here to run a command that returns a
# reproducible string that only the sudo user could get access to be used
# for user_record.password bellow. Proceed with caution, this is not a
# recommended approach
seed = some_function_that_returns_something_secret(vm_conn)
user_record = User(name='linux_user', password=gen_password(seed))
set_passwords(vm_conn, user_record)
expire_passwords(vm_conn, user_record)
print(f'Done! Disconnecting from {vm_conn.host}.')
# So that you know the temporary password, print user_record or save to file
# `ssh linux_user@vm` and it should insist that you change password
print(user_record)