#!/bin/bash # Purpose: This is a wrapper script for expect.sshkeys # This does some pre-req checks and distributes sshkeys # to a List of servers in a required file: "serverList" # Author: Rawiri Blundell, Datacom # Date: June 2014 # Variables serverList=serverlist adminPwd="${PWD}/.pwdfiler" compareStrings=1 # Basic Horizontal Rule function hr() { printf '%*s\n' "${1:-$COLUMNS}" | tr ' ' "${2:-#}" } # Check that $serverList exists if [[ ! -f "${serverList}" ]]; then printf '%s\n' "File '${serverList}' is required and doesn't exist where I expect it" \ "Please ensure this file is present in ${PWD}" exit 1 fi # Greet hr 40 printf '\t%s\n' "You are running ${0##*/}" hr 40 printf '%s\n' "" "This script attempts to distribute your sshkey across" \ " all the servers in the file '${serverList}'" \ "" "This assumes you have access on all servers listed, using the same password" \ "If not, consider exiting and sorting that out." read -rp "Press [Enter] to continue or Ctrl-C to exit" #### SSH Stuff #### # Check for sshkeys and if not found, generate # Does the local host support ed25519? # Ancient versions of ssh don't have '-Q' so also likely won't have ed25519 # If you wanted a more portable test: man ssh | grep ed25519 if ssh -Q key 2>/dev/null | grep -q ed25519; then localED25519=true fi # If the local host supports ed25519 and doesn't have a key, generate it if [[ "${localED25519}" = "true" ]] && [[ ! -f ~/.ssh/id_ed25519.pub ]]; then printf '%s\n' "I could not find an ed25519 sshkey, let me generate one for you..." ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519 fi # Let's also generate an RSA key with 2048 bits for legacy purposes if [[ ! -f ~/.ssh/id_rsa.pub ]]; then printf '%s\n' "I could not find an RSA sshkey, let me generate one for you..." ssh-keygen -t rsa -b 2048 -N "" -f ~/.ssh/id_rsa fi # Sanitise the serverlist file to prevent failures down the track while read -r host; do if ! nslookup "${host}" >/dev/null 2>&1; then sed -i "/^${host}$/d" "${serverList}" fi done < "${serverList}" # Get ~/.ssh/known_hosts up to scratch, this should reduce the need to depend on expect # to take care of interacting with remote hosts for fingerprinting # First, notify the user printf '%s\n' "Please wait while I perform maintenance on your known_hosts file..." if [[ -f ~/.ssh/known_hosts ]]; then # Backup the current known_hosts file # We filter out hosts that we're going to check anyway # This auto-updates the entries (e.g. server rebuilds are catered for) grep -vif "${serverList}" ~/.ssh/known_hosts > ~/.ssh/known_hosts.old fi # Generate a temporary known_hosts file from the serverlist if [[ "${localED25519}" = "true" ]]; then ssh-keyscan -t rsa,ed25519 -f "${serverList}" > ~/.ssh/known_hosts.new 2>/dev/null else ssh-keyscan -t rsa -f "${serverList}" > ~/.ssh/known_hosts.new 2>/dev/null fi # Now cat the old and new files together cat ~/.ssh/known_hosts.old ~/.ssh/known_hosts.new 2>/dev/null | sort | uniq -u > ~/.ssh/known_hosts # Double check perms chmod 600 ~/.ssh/known_hosts #### /SSH Stuff #### # Remove any existing pwdfiler files and generate a new one rm -f "${adminPwd}" # Prompt for the authentication password twice while (( compareStrings > 0 )); do hr 40 printf '%s' "Please enter your password for authenticating and press [Enter]: " read -rs pwdin1 printf '\n%s' "Please confirm your password and press [Enter]: " read -rs pwdin2 # Compare the two, if they don't match, try again if [[ "${pwdin1}" != "${pwdin2}" ]]; then echo "" read -rp "The passwords entered do not match. Press [Enter] to start again." compareStrings=$(( compareStrings + 1 )) else # If the passwords match, write it to .pwdfiler echo "${pwdin1}" > "${adminPwd}" # And give the condition to exit the while loop compareStrings=0 fi done # Secure pwdfiler chmod 600 "${adminPwd}" # Heavy Lifting for host in $(<"${serverList}"); do # We now call an expect script that essentially automates the following #ssh-copy-id -i /home/$user/.ssh/id_rsa.pub "${host}" if grep "${host}" ~/.ssh/known_hosts | grep -q ed25519; then ./expect.sshkeys "${host}" ed25519 else ./expect.sshkeys "${host}" rsa fi # Alternative method that might be figured out in the future: #cat ~/.ssh/id_rsa.pub | ssh $user@$host "cat - >> .ssh/authorized_keys" done # Cleanup # Remove any pwdfiler files #rm -f "${adminPwd}"