【问题标题】:Script to change password on linux servers over ssh通过 ssh 在 linux 服务器上更改密码的脚本
【发布时间】:2012-01-04 10:06:13
【问题描述】:

我们的 IT 环境中有许多 Red Hat linux 服务器。我的团队成员要求我编写一个脚本(最好是 shell 脚本),以使用 SSH 一次性更改每个用户的密码。

我试图找到一个解决方案,但我发现的许多脚本都在使用 Expect。我们的服务器上没有安装 Expect,系统管理员拒绝让我们安装它。此外,用户没有 root 访问权限,因此无法使用 passwd --stdinchpasswd

有没有什么方法可以编写脚本,以便用户可以运行它并在列表中的所有服务器上仅更改他自己的用户的密码?

【问题讨论】:

  • 不幸的是不是一个选项.. :)

标签: linux shell ssh passwords


【解决方案1】:

您无需 root 访问权限即可使用 passwd

这应该可以正常工作。

passwd <<EOF
old password
new password
new password
EOF

【讨论】:

  • 谢谢丹尼斯,根据您的帖子,一旦用户登录到所需的服务器,passwd 就可以正常工作。但是,我有一个存储在文件 servers.txt 中的服务器列表,我想运行一个脚本,提供一次旧密码和新密码,然后脚本应该在该列表中的所有服务器上更改我的密码。有什么想法吗?
  • ssh user@server 'command to change password' 就是这样做的。
  • 谢谢丹尼斯,我已经对我的问题进行了编辑,显示了我的尝试。它还没有,但这是一个好的开始。谢谢你.. :)
  • @CristianCiupitu:问题提到不能使用passwd --stdin因为用户没有root 访问权限。我的回答说明这个前提是错误的;不需要 root 访问权限。
【解决方案2】:

您可能希望向同行展示的另一种方法是让他们使用无密码身份验证。他们会生成一个公钥/私钥对,并在他们登录的每台服务器上的 ~/.ssh/authorized_keys 文件中注册他们的公钥。

【讨论】:

  • 谢谢,我已经使用公钥/私钥进行身份验证,但即使使用无密码身份验证,当密码在 2 个月后过期时(在我的情况下),我仍然需要登录每个服务器,使用'passwd',输入旧密码并输入两次新密码。这有点低效。这就是我试图整合这个解决方案的原因。
  • 优秀。这简化了事情。
  • 您可能在这些服务器上安装了 sudo,对吧?如果您授予他们对脚本的 sudo 权限以更改其密码,则该脚本可以使用 --stdin 参数为他们的帐户运行 passwd。
  • 是的,尝试了所有这些方法,但有人告诉我,我无法为“passwd”获取 sudo。我有 sudo 其他一些命令,但不是这个。系统家伙是严厉的......:|
【解决方案3】:

你应该试试pssh(同时并行ssh)。

cat>~/ssh-hosts<<EOF
user100@host-foo
user200@host-bar
user848@host-qux
EOF

pssh -h ~/pssh-hosts 'printf "%s\n" old_pass new_pass new_pass | passwd'

【讨论】:

  • 谢谢,这可能是一个很好的解决方案,但同样,我们的服务器上没有 pssh.... :(
  • 您可以在任何发行版上运行此命令,例如 Android 设备、笔记本电脑、台式机。您只需将其安装在客户端,并将 ssh 作为服务器端。我认为没问题;)您也可以使用 for 循环进行简单的迭代: for i in foo bar base;做 ssh "$i" "命令行";完成
  • 很有趣,我一定会研究的。谢谢:)
  • 如果觉得回复有用,可以点赞。如果它符合您的需求,您应该“接受”回复,这就是 stackoverflow 的工作原理。
  • 好的,很抱歉。我在这里没有参与很多问题,所以请多多包涵:)
【解决方案4】:

你会使用 Perl 吗?

Here 有一个脚本可以更改一组主机中的密码。

如果需要在运行脚本的本地计算机上安装一些 Perl 模块(Net::OpenSSH::ParallelExpect 及其依赖项),但在必须更改密码的远程服务器上不需要。

【讨论】:

  • 这可能对某些人有用。环境设置的特殊方式限制了我使用此解决方案。我无法直接从我的客户端计算机访问这些服务器。我必须登录到禁用端口转发的跳转主机。因此脚本需要在具有所有这些限制的跳转主机上运行。不过感谢您提供的信息。
  • @squashbuff:我目前正在开发另一个 Perl 模块 Net::OpenSSH::Gateway,它允许 Net::OpenSSH 透明地跳过网关,但它仍在进行中。
【解决方案5】:

【讨论】:

    【解决方案6】:

    认为我应该将我的解决方案放在答案字段中 - 不确定这是否应该成为问题的一部分..

    好的,我根据 Dennis 的建议制定了一个部分可行的解决方案。

    servers.txt 看起来像:

    server1
    server2
    server3
    .
    .
    .
    

    我正在使用:

    for server in `cat servers.txt`; do
    ssh $server -l user 'passwd <<EOF
    old_pass
    new_pass
    new_pass
    EOF';
    done
    

    这会产生:

    user@server1's password: **<Type password manually>**
    (current) UNIX password: New UNIX password: Retype new UNIX password: Changing password for user user.
    Changing password for user
    passwd: all authentication tokens updated successfully.
    user@server2's password: **<Type password manually>**
    (current) UNIX password: New UNIX password: Retype new UNIX password: Changing password for user user.
    Changing password for user
    passwd: all authentication tokens updated successfully.
    

    所以在这里,我仍然需要为每台服务器输入一次旧密码。可以避免吗?

    【讨论】:

    • 您有没有找到避免为每台服务器输入一次旧密码的方法?
    • @Lizz 我最终使用了 expect。就安全性而言,这不是理想的解决方案,但必须尽快完成。查看 Randy Katz 接受的答案。
    【解决方案7】:

    另一种可能性:在一台服务器上手动更改它。从 /etc/shadow 中获取加密密码。现在,做这样的事情:

    for host in $HOST_LIST; do
        ssh $host "passwd -p 'encrypted_passwd' user"
    done
    

    当然,“encrypted_pa​​sswd”是您从 /etc/shadow 中手动更改密码的地方。$HOST_LIST 是您希望更改密码的主机列表。可以简单地使用以下命令创建:

    export HOST_LIST="server1 server2 server15 server67"
    

    或者也许有一个文件(正如其他人建议的那样):

    export HOST_LIST=`cat host_list.txt`
    

    文件“host_list.txt”包含您要更改密码的所有系统的列表。

    编辑:如果您的 passwd 版本不支持 -p 选项,您可能有 'usermod' 程序可用。上面的示例保持不变,只需将 'passwd' 替换为 'usermod'。

    此外,您可以考虑使用useful tool pdsh,它将上面的示例简化为:

    echo $HOST_LIST | pdsh -Rssh -w- "usermod -p 'encrypted_passwd' user"
    

    最后一个要注意的“陷阱”:加密密码可能包含美元符号字符 ('$') 作为字段分隔符。您可能必须在 for 循环或 pdsh 命令中转义那些(即“$”变为“\$”)。

    【讨论】:

    • passwd-0.77-4.el6 (Enterprise Linux 6) 或 passwd-0.79-2.fc20 (Fedora 20) 没有 -p 选项。
    • 看看'usermod'程序...在CentOS(RHEL的克隆)5.x和6.x上,它支持-p选项。我编辑了我的回复以包含更多细节。
    • 对我来说效果很好。澄清一下:您必须转义 encrypted_pa​​sswd 中的所有 $ 字符,而不仅仅是第一个。
    【解决方案8】:

    以 squashbuff 的示例为基础,我尝试了以下方法,对我来说效果很好:

    #!/bin/bash
    用于`cat hostlist`中的服务器;做
    回声$服务器;
    ssh 用户名@$server '密码 &lt&ltEOF
    旧密码
    新密码
    新密码
    EOF';
    完成

    安全方面,可以改进以在不回显到屏幕或将明文保存到磁盘的情况下接受输入。

    【讨论】:

      【解决方案9】:

      如果您有 ssh,为什么首先要有密码?将用户的公共 ssh 密钥推送到他们有权使用并完成的所有服务器。这也让您可以轻松地授予和撤销您想要的所有访问权限。

      在之前的 $dayjob 中,我们实际上有数万台服务器,他们有一个数据库,其中允许工程师在哪些服务器上使用,并且 ssh 密钥的安装是一个自动化过程。几乎没有人在任何机器上都有密码。

      【讨论】:

      • 感谢 Edward,但是基础架构管理已外包,我在做出这些决定时没有任何发言权。我必须在不进行大的基础架构更改的情况下完成这项工作。这不是一个选择。
      【解决方案10】:

      远程机器不需要安装expect。您可以在本地工作站或 VM(虚拟机)或任何 *nix 机上安装 expect,并编写一个调用此 .ex(预期)脚本的包装器(从发行版到发行版可能会有小的变化,这在 CentOS 5/6 上进行了测试):

      #!/usr/bin/expect -f
      # wrapper to make passwd(1) be non-interactive
      # username is passed as 1st arg, passwd as 2nd
      
      set username [lindex $argv 0]
      set password [lindex $argv 1]
      set serverid [lindex $argv 2]
      set newpassword [lindex $argv 3]
      
      spawn ssh $serverid passwd
      expect "assword:"
      send "$password\r"
      expect "UNIX password:"
      send "$password\r"
      expect "password:"
      send "$newpassword\r"
      expect "password:"
      send "$newpassword\r"
      expect eof
      

      【讨论】:

      • 使用此代码,您可能希望使此代码类似于 ./passwdWrapper,然后在您的 bash 文件中添加 ./passwdWrap $user $password $server $newpassword
      • 如果这是您第一次连接到此服务器,系统可能会提示您验证指纹,以绕过从 spawn ssh $serverid passwdspawn ssh -o "StrictHostKeyChecking no" $serverid passwd 的第 10 行更新
      【解决方案11】:
      echo "name:password" | chpasswd
      

      【讨论】:

      • 问题中提到不能使用chpasswd
      【解决方案12】:
      1. 在您要执行脚本的任何服务器上安装sshpass

        yum -y install sshpass
        
      2. 准备一个文本文件,您必须在其中传递主机用户名密码端口等详细信息>。 (根据您的要求)。

        192.168.1.2|sachin|dddddd|22
        
      3. 使用以下详细信息准备一个脚本文件。

        #!/bin/bash
        
        FILE=/tmp/ipaddress.txt
        
        MyServer=""
        MyUser=""
        MyPassword=""
        MyPort=""
        
        exec 3<&0
        exec 0<$FILE
        
        while read line
        do
            MyServer=$(echo $line | cut -d'|' -f1)
            MyUser=$(echo $line | cut -d'|' -f2)
            MyPassword=$(echo $line | cut -d'|' -f3)
            MyPort=$(echo $line | cut -d'|' -f4)
        
            HOST=$MyServer
            USR=$MyUser
            PASS=$MyPassword
        
            sshpass -p $PASS ssh -p $MyPort -o StrictHostKeychecking=no $USR@$HOST \
                    -T "echo 'sachin@patel' | passwd --stdin root"                 \
                    < /dev/null | tee -a output.log
        done
        
        exec 0<&3
        

      【讨论】:

      • 如果有人运行ps,密码不可见吗?
      【解决方案13】:

      echo -e "wakka2\nwakka2\n" |密码根

      【讨论】:

        【解决方案14】:

        Expect 自带的passmass 脚本 (man page) 不需要在远程机器上安装 Expect。

        【讨论】:

          【解决方案15】:

          真正的问题是他们为什么不使用某种名称服务? NIS/黄页或 LDAP,您不必在一堆服务器上手动更改密码。用户更改密码一次,并在域主服务器上完成。

          【讨论】:

          • 我在目前的环境中工作,限制已经到位。我不是域管理员,我对使您的解决方案有效所需的架构更改没有发言权。我正在为像我这样在相同限制性环境中工作的最终用户提供解决方案。
          【解决方案16】:
          cat /tmp/passwords | ssh $server sudo chpasswd -e
          

          如果密码被加密,或者

          cat /tmp/passwords | ssh $server sudo chpasswd
          

          如果密码未加密。

          /tmp/passwords 格式应为“user:password”

          【讨论】:

          • 如问题中所述,用户没有root访问权限。所以不能使用'sudo chpasswd'。老实说,如果系统管理员允许用户运行“sudo chpasswd”,那么我认为这是一个很大的安全问题。
          【解决方案17】:

          我刚刚实现了一个小的tool,它可以一次更改许多用户/主机的密码。它是基于 Java 的应用程序,因此它可以在 Windows 和 Linux 上运行。它是免费的,尽情享受吧:)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-08-25
            • 2018-02-17
            • 2011-10-25
            • 2015-03-06
            • 2023-04-03
            • 1970-01-01
            • 2023-02-06
            相关资源
            最近更新 更多