问题
- 有没有更安全/更好的方法可以通过 Python 脚本以非交互方式设置用户密码?我目前的解决方案
chpasswd
使用织物脚本。另一个选择是使用期望从内部织物脚本。 - 我目前设置密码的方法是否存在安全隐患?我发现的潜在安全隐患是密码在我的本地终端上以明文显示,如下所示:
[xxx.xx.xx.xxx] run: echo "johnsmith:supersecretpassw0rd" | chpasswd
。
由于我只运行织物我从笔记本电脑上写脚本,我不知道思考这是一个安全问题,但我对其他人的意见感兴趣。
背景
我使用以下代码创建了一个 Python 脚本织物配置新构建的切片主机Ubuntu 切片。如果您不熟悉 Fabric,它使用波拉米科,一个 Python SSH2 客户端,为“应用程序部署或系统管理任务”提供远程访问。
我首先想到的是织物脚本所做的就是创建一个新的管理员用户并设置他们的密码。与期望,Fabric 无法处理远程系统上的交互式命令,因此我需要以非交互式方式设置用户的密码。目前,我正在使用该chpasswd
命令,该命令以明文形式读取用户名和密码。
当前代码
# Fabric imports and host configuration excluded for brevity
root_password = getpass.getpass("Root's password given by SliceManager: ")
admin_username = prompt("Enter a username for the admin user to create: ")
admin_password = getpass.getpass("Enter a password for the admin user: ")
env.user = 'root'
env.password = root_password
# Create the admin group and add it to the sudoers file
admin_group = 'admin'
run('addgroup {group}'.format(group=admin_group))
run('echo "%{group} ALL=(ALL) ALL" >> /etc/sudoers'.format(
group=admin_group)
)
# Create the new admin user (default group=username); add to admin group
run('adduser {username} --disabled-password --gecos ""'.format(
username=admin_username)
)
run('adduser {username} {group}'.format(
username=admin_username,
group=admin_group)
)
# Set the password for the new admin user
run('echo "{username}:{password}" | chpasswd'.format(
username=admin_username,
password=admin_password)
)
本地系统终端 I/O
$ fab config_rebuilt_slice
Root's password given by SliceManager:
Enter a username for the admin user to create: johnsmith
Enter a password for the admin user:
[xxx.xx.xx.xxx] run: addgroup admin
[xxx.xx.xx.xxx] out: Adding group `admin' (GID 1000) ...
[xxx.xx.xx.xxx] out: Done.
[xxx.xx.xx.xxx] run: echo "%admin ALL=(ALL) ALL" >> /etc/sudoers
[xxx.xx.xx.xxx] run: adduser johnsmith --disabled-password --gecos ""
[xxx.xx.xx.xxx] out: Adding user `johnsmith' ...
[xxx.xx.xx.xxx] out: Adding new group `johnsmith' (1001) ...
[xxx.xx.xx.xxx] out: Adding new user `johnsmith' (1000) with group `johnsmith' ...
[xxx.xx.xx.xxx] out: Creating home directory `/home/johnsmith' ...
[xxx.xx.xx.xxx] out: Copying files from `/etc/skel' ...
[xxx.xx.xx.xxx] run: adduser johnsmith admin
[xxx.xx.xx.xxx] out: Adding user `johnsmith' to group `admin' ...
[xxx.xx.xx.xxx] out: Adding user johnsmith to group admin
[xxx.xx.xx.xxx] out: Done.
[xxx.xx.xx.xxx] run: echo "johnsmith:supersecretpassw0rd" | chpasswd
[xxx.xx.xx.xxx] run: passwd --lock root
[xxx.xx.xx.xxx] out: passwd: password expiry information changed.
Done.
Disconnecting from [email protected]... done.
答案1
您在执行的命令行中传递密码。这些密码可能不仅在您的终端中可见,而且其他发出“ps”命令的用户也可以看到(这可能取决于系统配置)。密码是纯文本。
我不了解 Fabric,但如果它让你有可能通过它们的 stdin/stdout 与执行的命令进行通信(如subprocess.Popen()
),那么使用它而不是“echo username:password|...”可能是一个更好的选择。
另外,您可以选择在 Python 脚本中创建密码哈希(使用crypt
模块和“$1$XXXXXXXX$”(“X”是随机字符)盐)并将其传递给chpasswd -e
。纯文本密码将永远不会显示或记录。
您可以使用模块生成密码哈希,crypt
如下所示:
import crypt
p='secretpassword'
print(crypt.crypt(p))
您可以将输出传递给chpasswd -e
如下内容:
`echo 'someusername:passwordhash' | chpasswd -e`
答案2
对于非交互式密码设置,我通常会生成一个随机密码并将其设置为变量,然后将该变量传递给我的命令。我不必对密码进行创造性的发挥,也不必将标准密码留在纯文本文件中。
这是一个生成随机密码的主动状态方法。
就安全性而言,我认为在自己的终端上打印密码并不是什么大问题(使用随机密码,无论如何你都会想要它,这样你就可以记下创建的密码)。
Fabric 对 ssh 的操作有什么不同吗?——无论如何,通过 ssh 传输的大多数内容都应该加密。
答案3
如果您在 Fabric 中使用 chpasswd,请确保不要在命令行中使用纯文本密码。密码不仅会显示在 stdout 中,还会写入 /var/log/secure。在 Fabric 中,您可以使用
with hide('running', 'output', 'error'):
<your task here>
确保将哈希字符串与 chpasswd 命令一起使用,这样即使在安全日志中您也不会看到纯文本形式的密码。首先确定要使用的密码,然后生成哈希字符串。您可以使用 openssl 来实现这一点。
openssl passwd -1
这将提示您输入密码并生成 MD5 哈希。您可以在脚本中使用它,如下所示。
echo "<user>:<MD5-hash>" | chpasswd -e
上述命令中的 -e 标志告诉 chpasswd 密码已加密。
答案4
你能自动配置你的新切片,然后直接登录并更改密码吗?有时最简单的方法就是最好的。
但是,您也可以在本地生成加密密码,然后直接将加密密码写入 /etc/shadow 文件。这样,您就根本不需要使用纯文本。
请注意,当您最初提供初始密码时,您必须信任您的本地系统。
顺便问一下,您能否提供一份自动配置的副本,以便我使用它,而不用从头开始编写所有内容?目前,我通过 bash 进行所有操作。
像这样吗?
sed 's/^root:.*$/root:$PASSWD:13063::::::/' /etc/shadow > /etc/shadow