I've grown tired of typing my password back and forth to all the hosts you connect to, i want to be able to jump to every single user on all the hosts with ease.
So i've made this script with a quite messy oneliner at the end of it.
The script first reads user input where to connect to.
remote_user, remote_host and remote_port.
echo "Enter the user you want to connect with (sudo needs to be enabled and installed)"
read -e rUser
echo "Enter the host you want to connect to"
read -e rHost
echo "Enter the SSH-port"
read -e rPort
read -s -p "Enter Password: " password
Checks if ssh-key is generated, if not proceeds with ssh-keygen for the user to generate a strong key.
if [ ! -d "$HOME/.ssh" ] && [ ! -f "$HOME/.ssh/id_rsa" ] && [ ! -f "$HOME/.ssh/id_rsa.pub" ]; then
echo -e "Private / Public keys not generated"
echo -e "Generating..."
ssh-keygen -b 4096
fi
After that we proceed with establishing ssh-connection and creating the authorized_keys file on the remote host.
(Annoying 'bug' here you have to enter the password twice, since it doesnt seem possible to read ssh-password from stdin.)
cat "$HOME/.ssh/id_rsa.pub" | ssh "$rUser@$rHost" -p $rPort "cat >> ~/.ssh/authorized_keys"
Since the script will only be run once per remote host, its acceptable.
We continue with the quite messy oneliner.
We're establishing an SSH connection, to solve the problem with password over SSH we pass the -S parameter to SUDO that lets us read the password from STDIN. Now our subsequent SUDO calls will work. We proceed and create the .ssh directories for all the users on the system if they dont exist.
We create the authorized_keys file for all users and set correct owner, then we append authorized_keys file of the user we connected with.
remoteUsers=($(ssh "$rUser@$rHost" -p $remotePort
'echo '"$password"' | sudo -S ls /home/ && for localUser
in $(ls /home | grep -v $USER); do sudo mkdir -p /home/$localUser/.ssh &&
sudo touch /home/$localUser/.ssh/authorized_keys
&& sudo chown "$localUser:$localUser" /home/$localUser/.ssh/authorized_keys &&
cat /home/$USER/.ssh/authorized_keys | sudo tee
--append /home/$localUser/.ssh/authorized_keys > /dev/null; done'))
Not that pretty. But i don't know how to improve this without considering another approach for the sudo over SSH problem.
And finally we write our .ssh/config with all the users in it.
for remoteUser in "${remoteUsers[@]}"
do
cat <<< "Host ${remoteUser}_${rHost}
HostName $rHost
Port $rPort
User $remoteUser" >> /home/$USER/.ssh/config
done
Below is the script in its entirety.
#!/bin/bash
echo "Enter the user you want to connect with (sudo needs to be enabled and installed)"
read -e rUser # -e Identifier bash feature
echo "Enter the host you want to connect to"
read -e rHost # -e Identifier bash feature
echo "Enter the SSH-port"
read -e rPort
read -s -p "Enter Password: " password
# Generate private public ssh-keys
if [ ! -d "$HOME/.ssh" ] && [ ! -f "$HOME/.ssh/id_rsa" ] && [ ! -f "$HOME/.ssh/id_rsa.pub" ]; then
echo -e "Private / Public keys not generated"
echo -e "Generating..."
ssh-keygen -b 4096
fi
# Send public key to remote host
echo "Sending public key to remote host..."
cat "$HOME/.ssh/id_rsa.pub" | ssh "$rUser@$rHost" -p $rPort "cat >> ~/.ssh/authorized_keys"
remoteUsers=($(ssh "$rUser@$rHost" -p $rPort 'echo '"$password"' | sudo -S ls /home/ && for localUser in $(ls /home | grep -v $USER); do sudo mkdir -p /home/$localUser/.ssh && sudo touch /home/$localUser/.ssh/authorized_keys && sudo chown "$localUser:$localUser" /home/$localUser/.ssh/authorized_keys && cat /home/$USER/.ssh/authorized_keys | sudo tee --append /home/$localUser/.ssh/authorized_keys > /dev/null; done'))
for remoteUser in "${remoteUsers[@]}"
do
cat <<< "Host ${remoteUser}_${rHost}
HostName $rHost
Port $rPort
User $remoteUser" >> /home/$USER/.ssh/config
done
2 Answers 2
That looks crazy. But some constructive comments:
Did you check for
ssh-copy-id
script, that is usually shipped withopenssh
? It solves for you the first part of your problem in standard way.The second problem is in my eyes non-existent. Do you really need your
authorized_keys
in all accounts? Isn't it enough for one user that can dosudo
?The third is part is interesting. SSH config file is useful thing and I appreciate that you use it. I see the main plus in the auto-complete of full
user_host
string in your case (instead ofuser@host
, where ssh would help only with thehost
part), but if you would use only one user, you would not need that either.You need to count with the case that
sudo
might not accept password without TTY or from pipe on command-line.Sending password in command like this might be also security issue, since the command might get logged somewhere on the remote host (debug output or in
audit
).
-
\$\begingroup\$ I guess i could just use the sudo user and doing sudo su otheruser && cd , but it seems more correct to add my public key to all of the users. And when it's finished i can just simply ssh host_user and all is done, no more need for extra scripts. Otherwise i would have to sudo su otheruser every single time ? \$\endgroup\$JazzCat– JazzCat2016年03月26日 16:48:11 +00:00Commented Mar 26, 2016 at 16:48
-
\$\begingroup\$ 1) Instead of
sudo su user
, you can use simplysudo -u user
without misusingsu
. 2) Yes, it clearly depends on how many users you need to connect and how frequently you need to switch them (and if it is a lot, there stinks something). \$\endgroup\$Jakuje– Jakuje2016年03月26日 16:51:44 +00:00Commented Mar 26, 2016 at 16:51 -
\$\begingroup\$ Its very frequent. Each host has its own user, and there is hundreds of them, so quite often yes :) Each site that is in development or production has its own $HOME/public_html, when developing or bugfixing, you want to be logged in as that user. (To be able to run screen/tmux or whatever you need to be logged in as that user) \$\endgroup\$JazzCat– JazzCat2016年03月26日 16:54:12 +00:00Commented Mar 26, 2016 at 16:54
-
\$\begingroup\$ And i've searched all logs, cannot find any record of the password there, may depend on host configuration though. \$\endgroup\$JazzCat– JazzCat2016年03月26日 17:34:13 +00:00Commented Mar 26, 2016 at 17:34
-
1\$\begingroup\$ Yes, got that. About the logs, it might happen when there is
LogLevel DEBUG
or more on the serversshd
and then the full command is dropped into the log. About theaudit
on RHELs, I was wrong. There is logged only that some command was run, but not the full command line. \$\endgroup\$Jakuje– Jakuje2016年03月26日 17:55:22 +00:00Commented Mar 26, 2016 at 17:55
The conditions to create keys
The condition on the directory seems a bit excessive here:
if [ ! -d "$HOME/.ssh" ] && [ ! -f "$HOME/.ssh/id_rsa" ] && [ ! -f "$HOME/.ssh/id_rsa.pub" ]; then echo -e "Private / Public keys not generated" echo -e "Generating..." ssh-keygen -b 4096 fi
My concern is that if the key files are missing but the directory exists,
the script will not create the keys.
But it's not unusual that the directory would exist without keys.
For example the directory is created when you connect to a remote server for the first time, to store the known_hosts
file.
So I suggest to drop the condition on the directory:
if [ ! -f "$HOME/.ssh/id_rsa" ] && [ ! -f "$HOME/.ssh/id_rsa.pub" ]; then
Prefer input redirection instead of cat
Instead of using a cat
process:
cat "$HOME/.ssh/id_rsa.pub" | ssh "$rUser@$rHost" -p $rPort "cat >> ~/.ssh/authorized_keys"
It's more efficient and elegant to use input redirection:
ssh "$rUser@$rHost" -p $rPort "cat >> ~/.ssh/authorized_keys" < "$HOME/.ssh/id_rsa.pub"
Running long snippets on a remote server
This is pretty much unreadable:
remoteUsers=($(ssh "$rUser@$rHost" -p $remotePort 'echo '"$password"' | sudo -S ls /home/ && for localUser in $(ls /home | grep -v $USER); do sudo mkdir -p /home/$localUser/.ssh && sudo touch /home/$localUser/.ssh/authorized_keys && sudo chown "$localUser:$localUser" /home/$localUser/.ssh/authorized_keys && cat /home/$USER/.ssh/authorized_keys | sudo tee --append /home/$localUser/.ssh/authorized_keys > /dev/null; done'))
Here's a more readable way to write it:
remoteUsers=($(ssh "$rUser@$rHost" -p $remotePort << EOF
echo "$password" | sudo -S ls /home/ && \
for localUser in \$(ls /home | grep -v \$USER); do
sudo mkdir -p /home/$localUser/.ssh && \
sudo touch /home/$localUser/.ssh/authorized_keys && \
sudo chown "$localUser:$localUser" /home/$localUser/.ssh/authorized_keys && \
cat /home/\$USER/.ssh/authorized_keys | sudo tee --append /home/$localUser/.ssh/authorized_keys > /dev/null
done
EOF
))
Just be careful: notice that the $
that should be executed on the remote and not locally, such as $(ls ...)
and $USER
must be escaped.
Security
The security concerns raised by @Jakuje are very valid.
It would be better to not execute sudo
on the remote like this.
If ssh-copy-id
is not an option, another alternative is to run the script for each remote user one by one, so that there's no more need for sudo
.
-
\$\begingroup\$ Didn't know you could escape like that, had some issues with that , thats why i had to cut break the single quotes '"$password"'. Nice, thanks! \$\endgroup\$JazzCat– JazzCat2016年03月26日 16:45:31 +00:00Commented Mar 26, 2016 at 16:45
-
\$\begingroup\$ Although i get this error now: Pseudo-terminal will not be allocated because stdin is not a terminal. Maybe your solution breaks the sudo -S ? \$\endgroup\$JazzCat– JazzCat2016年03月26日 17:29:41 +00:00Commented Mar 26, 2016 at 17:29
-
\$\begingroup\$ @JazzCat you can use the
-T
flag ofssh
to disable pseudo-tty allocation, that will make the warning (not an error) go away \$\endgroup\$janos– janos2016年03月26日 17:34:43 +00:00Commented Mar 26, 2016 at 17:34 -
\$\begingroup\$ Solution isn't working with or without the -T flag, no .ssh directory created or authorized_keys file. \$\endgroup\$JazzCat– JazzCat2016年03月26日 17:55:16 +00:00Commented Mar 26, 2016 at 17:55