16

I am trying to copy .ssh/id_rsa.pub from our central server to multiple servers. I have the following script which I usually use to push changes to the different servers.

#!/bin/bash


for ip in $(<IPs); do
    # Tell the remote server to start bash, but since its
    # standard input is not a TTY it will start bash in
    # noninteractive mode.
    ssh -q "$ip" bash <<-'EOF'



EOF

done

But in this case, I need to cat the public key on the local server and then add that to multiple servers. Is there a way by using the above here document script to execute the following.

cat .ssh/id_rsa.pub |ssh tony@0.0.0.0 'cat > .ssh/authorized_keys'
2
  • why you need to cat on local since you're copied from one central location to remotes ? – klerk Jul 17 '14 at 21:43
  • I need to add central server's public key hence local server. Sorry for the confusion. – user67186 Jul 17 '14 at 21:48
23

With this simple loop you can automate it and spread to all remote servers.

#!/bin/bash
for ip in `cat /home/list_of_servers`; do
    ssh-copy-id -i ~/.ssh/id_rsa.pub $ip
done
2
  • Hi, I accept your anwser and it worked fine. Thanks – user67186 Jul 17 '14 at 22:16
  • +1. I'm a big fan of a very easy scripting style that get the job done! – Laith Leo Alobaidy Dec 24 '18 at 19:12
7

Here is my simple script to copy ssh-keygen to multiple servers without asking password everytime.

for server in `cat server.txt`;  
do  
    sshpass -p "password" ssh-copy-id -i ~/.ssh/id_rsa.pub user@$server  
done

This requires sshpass, which may need to be installed separately, either via package or from source.

3

The accepted answer won't work if one needs to copy someone else's public key to multiple machines. So, I've come up with the following solution:

cat add-vassal-tc-agents.sh

#!/bin/bash
set -x # enable bash debug mode
if [ -s vassal-public-key.pub ]; then # if file exists and not empty
    for ip in `cat tc-agents-list.txt`; do # for each line from the file
        # add EOL to the end of the file (i.e., after the last line)
        # and echo it into ssh, where it is added to the authorized_keys
        sed -e '$s/$/\n/' -s vassal-public-key.pub | ssh "$ip" 'cat >> ~/.ssh/authorized_keys'
    done
else
    echo "Put new vassal public key into ./vassal-public-key.pub to add it to tc-agents-list.txt hosts"
fi

This script adds the new key to the users on the list of machines, provided that the environment it is run on has the access.

Example of tc-agents-list.txt:

root@10.10.0.1
root@10.10.0.2
root@10.10.0.3
root@10.10.0.4

Note: This requires the use of GNU sed.  Since the question says "Linux", GNU sed is probably present.

1
  • Can you explain why you use the -s option to sed? Based on my reading of the man page, it seems to be meaningful only if you specify multiple files (which you don’t). – G-Man Says 'Reinstate Monica' May 6 at 23:33
2

For copying your public key, you have something in-built in openssh itself. So instead of cat and ssh use this :-

ssh-copy-id -i ~/.ssh/id_rsa.pub YOUR-REMOTE-HOST
2
  • I want to execute the command copying central server's public to remote servers which exist in IP file. The script iterates through them. So, your example may not be useful here. Thanks – user67186 Jul 17 '14 at 21:52
  • No need to use the -i option if you are using the default location of the public key. – Laith Leo Alobaidy Aug 28 '19 at 4:44
0

You can do this with a simple while-loop and embedded server list like this:

while read SERVER
do
    ssh-copy-id user@"${SERVER}"
done <<\EOF
server1
server2
server3
EOF

Having the list inside the script does away with separate data files which can get misplaced.

1
  • ssh-copy-id has already been suggested in some other answers. – RalfFriedl Jun 26 '19 at 16:48
0

Assuming you have a file with servers IP list, name SERVER, and just the IP addresses of the servers are defined.

This for loop will work as well.

for user in $(awk '{print $1}' SERVER | awk '{printf "user1@""%s"(NR==0?RS:"\n"), $1}' ) ;
do
        ssh-copy-id -f -i id_rsa_k2.pub $user
done
0

I have made some changes to the solution provided by Ilya Sheershoff, thanks.

#!/bin/bash
keys=${1:-*.pub}
echo update ssh-keys: ${keys}

cat targets | grep -vE '^(\s*$|#)' | sed 's/#.*$//g' | while read host user
do
   echo "# adding public ssh-keys for $user@$host"
   #for k in $(ls *.pub);
   for k in ${keys};
   do
      echo "# adding public key $k"
      # ssh-copy-id -f -i $k $user@$host
      touch ${k%\.pub}
      ssh-copy-id -i $k $user@$host
   done
done

This script adds the public keys of id-rsa-*.pub to the users on the list of hosts, provided that the environment it is run on has the access.

Example of targets:

# targets formatted with host and user
# host user

# host1
hostname1 user1
hostname1 user2
# host2
hostname2 user1
hostname2 user2

To make use of the ssh-copy-id script which prevents duplication of multiple keys in the authorized_keys, we can use the following workaround to run without the private key to be tested for login in case your version of the ssh-copy-id script does not yet support the -f force option like mine:

     # workaround ssh-copy-id -f option missing
     # ssh-copy-id -f -i $k $user@$host
     touch ${k%\.pub}
     ssh-copy-id -i $k $user@$host
New contributor
stefan123t is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.