Script to change password on linux servers over ss

2020-02-02 12:23发布

问题:

We have a number of Red Hat linux servers in our IT environment. I am being asked by my team members to write a script (preferably shell script) to change a user's password on each one of those in a single go, using SSH.

I have tried to find a solution but many of the scripts I found are using Expect. We do not have Expect installed on our servers and the system admins have refused to let us install it. Also, the users do not have root access so passwd --stdin or chpasswd cannot be used.

Is there any way a script can be written so that a user can run it and change the password of only his own user on all the servers in a list?

回答1:

The remote machine(s) do not need expect installed. You can install expect on a local workstation or VM (virtualbox) or whichever *nix box, and write a wrapper that calls this .ex (expect) script (there may be small changes from distro to distro, this tested on 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


回答2:

You do not need root access to use passwd.

This shoud work just fine.

passwd <<EOF
old password
new password
new password
EOF


回答3:

You should try pssh (parallel ssh at the same time).

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'


回答4:

Building on squashbuff's example, I tried the following, which worked well for me:

#!/bin/bash
for server in `cat hostlist`; do
echo $server;
ssh username@$server 'passwd <<EOF
old_password
new_password
new_password
EOF';
done

Security wise, Could be improved to take input without echoing to the screen OR saving the plaintext to disk.



回答5:

echo "name:password" | chpasswd


回答6:

Another possibility: change it manually on one server. Get the encrypted password out of /etc/shadow. Now, do something like this:

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

Of course, 'encrypted_passwd" is what you got out of /etc/shadow where you manually changed the password. And $HOST_LIST is a list of hosts where you want the password changed. That could be created simply with:

export HOST_LIST="server1 server2 server15 server67"

Or perhaps with a file (as others have suggested):

export HOST_LIST=`cat host_list.txt`

Where the file "host_list.txt" has a list of all the systems where you want the password changed.

Edit: if your version of passwd doesn't support the -p option, you might have the 'usermod' program available. The example above remains the same, simply replace 'passwd' with 'usermod'.

Furthermore, you might consider the useful tool pdsh, which would simplify the above example to something like this:

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

One last "gotcha" to look out for: the encrypted password likely contains the dollar sign character ('$') as a field separator. You'll probably have to escape those in your for loop or pdsh command (i.e. "$" becomes "\$").



回答7:

  1. Install sshpass on any of the server from where you want to execute the script.

    yum -y install sshpass
    
  2. Prepare a text file in which you have to pass details like Host, User Name, Password and Port. (Based on your requirement).

    192.168.1.2|sachin|dddddd|22
    
  3. Prepare a script file using below details.

    #!/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
    


回答8:

An alternative you may want to present to your peers would be to have them use password-less authentication. They'd generate a public/private key pair and register their public key in the ~/.ssh/authorized_keys file on each of the servers they log into.



回答9:

Can you use Perl?

Here there is an script that changes the password in a set of hosts.

If requires some Perl modules (Net::OpenSSH::Parallel, Expect and their dependencies) installed on the local machine running the script but nothing on the remote servers where the password has to be changed.



回答10:

Have you tried App::Unix::RPasswd



回答11:

The passmass script (man page) that comes with Expect doesn't require Expect to be installed on the remote machines.



回答12:

Thought I should put my solution in an answer field - not sure if this should be a part of the question..

OK, I have put together a partially working solution using Dennis' suggestion.

servers.txt looks like:

server1
server2
server3
.
.
.

I am using:

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

This produces:

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.

So here, I still need to type my old password once for each server. Can this be avoided?



回答13:

If you have ssh, why have passwords in the first place? Push the user's public ssh key to all the servers they're authorized to use and be done with it. This also lets you easily grant and revoke access all you want.

At a previous $dayjob, where we had literally tens of thousands of servers, they had a database of which engineers were allowed on which servers, and the installation of ssh keys was an automated process. Almost NOBODY had a password on ANY machine.



回答14:

echo -e "wakka2\nwakka2\n" | passwd root



回答15:

cat /tmp/passwords | ssh $server sudo chpasswd -e

if the password is encrypted, or

cat /tmp/passwords | ssh $server sudo chpasswd

if the password is not encrypted.

/tmp/passwords should have format of "user:password"



回答16:

The real question is why were they not using some sort of name services? NIS/Yellow Pages or LDAP and you're not having to manually change passwords across a bunch of servers. A user changes their password once and it's done across the domain master.