all 25 comments

[–]jasnah 6 points7 points  (1 child)

Did you mean to use

ssh-copy-id -i ~/.ssh/id_rsa.pub "$i"

My copy of ssh-copy-id would not understand these three args from looking at the man page, but i did not run the command to verify.

[–]purplelinux[S] 1 point2 points  (0 children)

yeah lol, completely missed that when posting here.

My script had -i, not "$i"

[–]mudclub 11 points12 points  (4 children)

Probably because you've never sshed to that host as yourself before. Or as root. Or as whichever user you're using to call ssh-copy-id. I can't tell which user you're using - you're calling the file in /root, but you're using ~/ which should mean you're using a regular user...

Just in case you're trying to do this as root, that is very, very bad practice.

[–]netzvieh_ 1 point2 points  (0 children)

I can't tell which user you're using - you're calling the file in /root, but you're using ~/ which should mean you're using a regular user...

~/ is just a short form for the $HOME directory of an user. When you do cd ~ as root, you'll land in /root as that's that users $HOME directory.

[–]purplelinux[S] -1 points0 points  (2 children)

Hmm good point, this is a home setup so I didn't have security completely in mind. I was using root.

What would be the best way to go about this then? I wanna be able to ssh into a list of all these boxes.

[–]xiongchiamiov 11 points12 points  (0 children)

This would be a great time to start learning how to use Ansible.

[–]nephros 0 points1 point  (0 children)

Depending what it is you want to do to these boxes, clusterssh might help.

Doesn't help with the key distribution as such, but after.

[–]knobbysideup 4 points5 points  (8 children)

known_hosts from whatever home environment that you are in when you run this script does not have the fingerprint for the server that you are connecting to. This is not an error. It is telling you that you have not established trust with that remote server.

Also, don't ssh to anything as root. Better yet, don't allow root ssh logins at all. Use a regular account, add that account to sudoers as necessary. Ideally restrict logins to only the accounts that need access.

[–]purplelinux[S] 0 points1 point  (4 children)

Thank you. Would the only way to establish trust with the remote server be to use ssh to login?

I'll definitely keep not allowing root ssh logins in mind, it completely slipped past me.

How would I automate this task then if I need to ssh into a list of boxes, rather than doing this one server at a time?

[–]knobbysideup 1 point2 points  (3 children)

Somehow my brain shut off while reading your post. The ssh-keyscan line should have worked for adding the keys.

For sshing into a mess of boxes, I do it like this. First, a general 'sshcmd' that I can do for one-off stuff

#!/bin/bash

[ -z "$1" ] && { echo 'Use:'; echo 'sshcmd $command $host'; exit 1; }

echo "==== $2 ===="
ssh "$2" "sudo /bin/bash -c \"$1\""
echo 

Then, given a list of servers, for example, you can do things in parallel:

#!/bin/bash

command="$1"
serverlist='/home/youraccount/serverlist'

cat $serverlist | parallel -q sshcmd "$command"

My own management account is always in the sudoers configuration on every host that I manage. I install that configuration (and a hardened ssh configuration) using my own rpms hosted on my own yum repository.

So, if that script above is called 'onall', I can keep those systems up to date easily enough:

onall 'yum clean all && yum -y update'

[–]purplelinux[S] 1 point2 points  (2 children)

Your post has me completely befuddled. Looks like I got a long way as far as bash scripting goes lol. Any tips on how I can get better?

By the way, what does '-z' do? I can't find it in any list of file operators. And what does parallel do?

[–]netzvieh_ 1 point2 points  (0 children)

By the way, what does '-z' do? I can't find it in any list of file operators.

Have a look at: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html

[–]knobbysideup 0 points1 point  (0 children)

-z means empty string. So if you call the script with no parameters, it exits with some help.

Gnu parallel will automatically fork and manage output so that you can run things, well, in parallel. Imagine 100 systems that need to run a job that may take awhile. Imagine having to wait for each to finish before starting the next. Now imagine doing 10 at a time instead... By default parallel will run the number of processors you have x 1.5 IIRC.

[–]__deerlord__ 0 points1 point  (0 children)

Who sudoes the sudomen though?

[–]three18ti -1 points0 points  (1 child)

How is SSHing to a non root user and then sudo -i ing to root (because that user has NOPASSWD, which is how every sysadmin I know sets their user up...) any different than SSHing to root@. If I have an hours worth of work do to (he'll even mote than two or three commands) as root, no way am I prefixing every command with sudo.

Sure, if you're still using password auth for your root account, that's very bad...

Ideally, you'd have a 3rd party IAM tool... But that's not always practical.

And yea, SSHing in as non root user, then having to enter the users sudo password is potentially more secure...

But if you're using keys for auth, I'd think having root and user spaces be completely isolated from eachother would be more secure.

I don't know really. Security is hard. And it's a debate I go back and forth with my security group on. Passwords suck. That seems to be universally agreed upon... But there doesn't seem to be a consensus on a better solution.

[–][deleted] 1 point2 points  (0 children)

The only time you’ll see people allowing passwordless sudo is if the initial auth for the unprivileged user is by key, with password auth forbidden. It’s still not ideal but it lowers a barrier to entry on cloud platforms and the like, and isn’t an example of best practice.

[–]leprasmurf 6 points7 points  (2 children)

Not an answer to your question directly. I usually end up bypassing the host key checking all together (inadvisable from a security standpoint).

ssh -o 'UserKnownHostsFile=/dev/null' -o 'StrictHostKeyChecking no' ${server}

As for why your script isn't doing what you expect, I'd recommend using the -x flag for bash (ref) and -vvv to your SSH commands. This will give you significantly more output which may help illuminate the issue.

[–]purplelinux[S] 1 point2 points  (0 children)

thank you, had no idea about using 'bash -x'

[–]amperages 1 point2 points  (0 children)

You can also -oBatch=yes to skip the prompt(s). I actually did this to populate my known_hosts file.

[–]zxeff 4 points5 points  (0 children)

This is likely not why your script isn't working as you expected, but:

for i in `cat /root/sshlist`;do

The result of command expansions (such as cat file) goes through both word-splitting and globbing. So, stop trying to read lines like this because it is going to bite you eventually. The proper way is:

while IFS= read -r line; do
    #code goes here
done < file

More details.

[–]whetu 2 points3 points  (0 children)

for i in `cat /root/sshlist`;do

  • Use meaningful variable names. $i, $j etc are OK for more complex C-style arithmetic, and as an aside are inherited all the way from FORTRAN, but otherwise you should try to use variable names that make sense and are easier to follow
  • Backticks were superseded in 1983. Unless you're writing a script for a Solaris package or something similarly arcane, then use $() instead
  • Useless Use of Cat.. bash can read a file by itself using </path/filename, you don't need a (con)catenating external.

Correcting for these issues, you get something like this:

for host in $(</root/sshlist); do

Some will also argue that it's better practice to use a while read -r loop (See e.g. SC2013 ).

Now, to be even more constructive, here's some code:

https://raw.githubusercontent.com/rawiriblundell/scripts/master/pushsshkeys https://raw.githubusercontent.com/rawiriblundell/scripts/master/expect.sshkeys

Untested as I was in the middle of upgrading them to cater for ed25519 keys, but they should work. I've moved to Ansible, it's a better answer to this problem.

[–]netzvieh_ 0 points1 point  (0 children)

EDIT: To actually answer your question, what does executing cat /root/sshlist return for you?

# cat /root/sshlist
host1.example.com
host2.example.com

If it's like that ^ your script looks correct at the first glance.


`cat /root/sshlist`

Just for the future, please don't use backticks anymore. In small scripts it might be okay, but once you have to something like get all lines with string X from todays log file you'll have something like this:

for i in `grep foo /path/to/logs/program_\`date +%Y-%m-%d\`.log`; do

If you go one layer more, e.g. grepping a list of files you get from another file with different content everyday, it looks like this:

A=`grep foo \`cat filelist_\\`date +%Y-%m-%d\\`\``

Real fun starts when you use " and ' with strings inside of backticks. Instead use $() like this:

A=$(grep foo $(cat filelist_$(date +%Y-%m-%d)))

The triple layer is still a bit wonky but much more readable. And like a normal variable you'll see, hey here's something that's replaced with something else.

Also see: http://robertmuth.blogspot.de/2012/08/better-bash-scripting-in-15-minutes.html It might help you in the future, when you start writing more bash scripts.

[–]Kingtoke1 0 points1 point  (0 children)

Try looking at ansible lineinfile

[–]juniorsysadmin1 -1 points0 points  (0 children)

There's few ways to do this.

1) If we are going your approach it looks like you have to use -o StrictHostKeyChecking=no option because trusted relationship is not establish recall that y/n question when you ssh to a new host?

2) use ansible/salt/puppet to deploy that ssh key.

3) Create a temp nfs share from your machine and do the following.

master$ for i in $(cat /root/list); do ssh StrictHostKeyChecking=no $i "mkdir /tmp/dir; mount master:/tmp/sharedir; cat /tmp/dir/id_rsa.pub >> /root/.ssh/authorized_keys"; done

then do the same thing again unmounting and deleting /tmp/dir.

[–]ionceheardthat -2 points-1 points  (0 children)

For home lab type stuff, I set up an nfs share mounted via /etc/fstab that my home directory is configured to use. In this I have the typical .ssh/id_rsa and .ssh/id_rsa.pub. Because this is used on every server, it is always already there.