This is the man page, which describes everything about this script:
NAME
sshkeys - add and remove public keys from remote servers
SYNOPSIS
sshkeys <-u username> <-h hostname> <-k keypath> (OPTION)
DESCRIPTION
This page documents the script sshkeys, a ssh public keys management tool designed to add, remove and check public keys on a remote server(s).
The script should be used from server with bash, as it is written in bash and uses advanced tools like awk and sed for key editing. Running the
script requires to specify the mandatory arguments: username, hostname and keypath. After these arguments you can choose one option at a time
according to operation you'd like to perform.
Managing public keys according to the options.
-u username
here you can specify username to login with on a remote machine.
-h hostname
enter hostname or several hostnames separated with ','. You can also specify a file containing hostnames list.
-k keypath
enter the absolute path to the directory containing the public keys.
OPTION
choose one option according to what do you like to do. Known options are:
-i Info mode. This option doesn't require additional parameter. In this mode the proper authorized key file is found and compared with known
keys stored in the keypath. At the end you can continue with other operations:
[a]dd - add keys to the file, you can enter keys you'd like to add to the file separated with ' ' or ','.
[r]emove - remove lines from the file, you can enter line numbers which will be removed.
[b]backup restore
- restore the backup in case something goes wrong.
[e]xit - exit the script. This will delete temporary files and end the script. This option is used by default.
[c]ancel - exit the script without removing any temporary files. Use this in case you like to preserved temporary files for
further usage.
-a keys
Add keys. This option takes as a parameter key file names separated with ','. These keys have to be stored in the keypath directory.
Specified keys will be added to the authorized keys file on remote servers.
-r keys
Remove keys. This option takes as a parameter key file names separated with ','. These keys have to be stored in the keypath directory.
Specified keys will be removed from the authorized keys file on remote servers.
EXAMPLES
sshkeys -u user -h host1.com,host2.com -k /here/are/keys/ -i
get information from the two hosts specified
sshkeys -u user -h host1.com,host2.com -k /here/are/keys/ -a user1.pub,user2.pub
add public keys user1.pub and user2.pub to specified hosts
sshkeys -u user -h /file/with/hosts.txt -k /here/are/keys/ -r user1.pub,user2.pub
remove public keys user1.pub and user2.pub from hosts specified in the file hosts.txt
AUTHOR
Written by KrisKo.
- the public keys in the pubkeys folder should be in SECSH Public Key File Format.
The script:
#!/bin/bash ######################################################################### # Version 1.1 # # Description: # script for ssh public key management on remote machines allowing to # add and remove keys ######################################################################### #set the temp folder TMP=/tmp; #add description to comment e.g. # <keyname>.pub <your desription> description="myDescription" ### usage() # Display complete help and usage of this script ### usage(){ echo "USAGE: $0 -u <username> -h <hostnames> -k <keypath> (-i | -a <keys> | -r <keys>)"; echo "Add and remove public keys from remote servers." echo -e "\n-u -h -k\tthese option are mandatory, they need to be specified" echo -e "-h <hostname>\tyou can specify multiple hostnames separated with \",\" or a filename containing hostnames" echo -e "-k <keypath>\tspecify directory where the keys are stored" echo -e "-i -a -r\tyou can use only one option at the same time" echo -e "-i\t\tenter info mode" echo -e "-a <keys>\tadd keys to the specified server, enter key filenames separated with \",\"" echo -e "-r <keys>\tremove keys from the specified server, enter key filenames separated with \",\"" echo -e "\nNote thet this script was tested on RHEL and SLES linux. It does not work on Solaris!" exit 0 } ### findfile() # Connect to the host, find the correct file ### findfile(){ #find all standard files on the remote host SSHOUT="`ssh $USERNAME@$HOST " if [ -f ~/.ssh/authorized_keys ];then cd ~/.ssh; echo ~/.ssh,authorized_keys fi if [ -f ~/.ssh2/authorization ]; then cd ~/.ssh2; echo ~/.ssh2,authorization fi if [ -f ~/.ssh2/authorized_keys ];then cd ~/.ssh2; echo ~/.ssh2,authorized_keys fi "`" #if ssh connection failed, end this script if [ $? == 255 ]; then echo ERROR: Failed to connect to remote host. exit 255 fi LINE="`echo $SSHOUT | tr " " "\n" | grep -c ""`" #notify if no standard file is found if [ -z $SSHOUT ]; then echo "ERROR: No standard file found!" echo "Would you like to create standard file \"~/.ssh/authorized_keys\"? [y]" read ans if [ "x$ans" == "x" ] || [ "$ans" == "y" ]; then echo "Creating file..." #ssh $USERNAME@$HOST "touch ~/.ssh/authorized_keys" SSHOUT="~/.ssh,authorized_keys_default" else echo "Quitting, you can create proper file on the remote host manually." exit 1; fi #show found file (if there are more than one, let the user choose one) elif [ $LINE -gt 1 ]; then echo -e '\n'Found file: echo $SSHOUT | tr " " "\n" | grep -n ""; echo "Choose line number for file to edit:"; read LINE; SSHOUT="`echo $SSHOUT | tr " " "\n" | awk NR==$LINE`" fi echo -e '\n'INFO: Using file: $SSHOUT | tr "," "/" } ### getfile() # Download the file and store it in $TMPAUTH ### getfile(){ #parse $SSHOUT given as the parameter $1 to file path and name FPATH="`echo $1 | cut -d "," -f 1`" FNAME="`echo $1 | cut -d "," -f 2`" #check if the temporary file exists and warn if [ -f $TMP/$FNAME.tmp ]; then echo "WARNING: file $TMP/$FNAME.tmp exists, it will be overwritten!" fi if [ "$FNAME" == "authorized_keys_default" ]; then FNAME="authorized_keys" >$TMP/$FNAME.tmp else #cat the remote file into the local temp file echo Downloading the file $FNAME. ssh $USERNAME@$HOST " cat $FPATH/$FNAME; " > $TMP/$FNAME.tmp fi } ### writedirect() # Write the prepared temp file (and keys) to the remote server and create backup ### writedirect(){ echo -e '\n'The file \"$FPATH/$FNAME\" will be written to the server...; #create backup of the existing file on remote host and cat the prepared temp file to the remote host and set proper permissions cat $TMP/$FNAME.tmp | ssh $USERNAME@$HOST " echo "INFO: Creating backupfile"; mkdir $FPATH 2>/dev/null; mv $FPATH/$FNAME $FPATH/$FNAME.bak 2>/dev/null || echo "INFO: No file to backup."; echo "INFO: Writing to $FPATH/$FNAME"; dd conv=notrunc > $FPATH/$FNAME; chmod 600 $FPATH/$FNAME;" #if we work with authorization file, copy/remove also the necessary keys if [ "$FNAME" == "authorization" ]; then if [ "$1" == "add" ]; then echo -e '\n'Copying keys... cat $TMP/$FNAME-tmp.tar | ssh $USERNAME@$HOST "cd $FPATH; tar xvf -" elif [ "$1" == "rem" ]; then echo -e '\n'Removing keys... ssh $USERNAME@$HOST "cd $FPATH; rm $REMKEYS" fi fi echo DONE. #remove local temporary files echo -e '\n'INFO: Removing temporary files. if [ -f $TMP/$FNAME.tmp ]; then rm $TMP/$FNAME.tmp; echo $TMP/$FNAME.tmp; fi; if [ -f $TMP/$FNAME-tmp.tar ]; then rm $TMP/$FNAME-tmp.tar; echo $TMP/$FNAME-tmp.tar; fi echo "# # # DONE # # #"; } ### restore() # Restore backup file ### restore(){ #warn that keys are not restored by authorization file if [ "$FNAME" == "authorization" ]; then echo WARNING: restoring only file \"autorization\"! The keys are not being restored. fi #move existing file to .old and copy backup to the original file ssh $USERNAME@$HOST " if [ -f "$FPATH/$FNAME.bak" ]; then echo "INFO: Found backupfile, restoring..."; mv $FPATH/$FNAME $FPATH/$FNAME.old; echo "Created \"$FNAME.old\" from the original..."; cp $FPATH/$FNAME.bak $FPATH/$FNAME; echo "Backup restored..."; chmod 600 $FPATH/$FNAME; echo DONE!; else echo "ERROR: Backup file not found."; fi" exit 0 } ### getkey() # Create proper form of .pub key file ### getkey(){ #when there's no newline at the end of a pub key file, add one test "`tail -c 2 "$KEYPATH/$key"`" && echo "" >> "$KEYPATH/$key" #convert the key to proper form and test if succesfull SSHKEY="`ssh-keygen -i -f "$KEYPATH/$key"`"; if [ ! "$SSHKEY" ]; then echo -n "INFO: " #in case the test is not succesfull convert the key to unix format dos2unix "$KEYPATH/$key" fi SSHKEY="`ssh-keygen -i -f "$KEYPATH/$key"`" #if the conversion fails, show error message and continue if [ ! "$SSHKEY" ]; then echo -e ERROR: Conversion of \"$key\" failed!'\n' SSHKEY="ERROR: Conversion failed" fi } ### adddirect() # Adding directly to the remote server ### adddirect(){ #$1=specified keys, $2=parameter direct/info according from where this function is called for HOST in $( echo $HOST | sed -e 's/,/ /g' ); do echo -e "\nINFO: Connecting to host $HOST" #download the file if the function is called directly, otherwise the file is already downloaded if [ "$2" == "direct" ]; then #get the file (this will rewrite the existing file) findfile; getfile $SSHOUT; fi #prepare temporary file (and keys) for key in $( echo $1 | sed -e 's/,/ /g'); do if [ -f $KEYPATH/$key ]; then echo adding key: $key; if [ "$FNAME" == "authorized_keys" ]; then #create proper key form: ssh-rsa ABCKEY... getkey $key #test if the key is not already in the file (double entries check) if [ "`cat $TMP/$FNAME.tmp | grep -n "" | grep --color "$SSHKEY"`" ]; then echo WARNING: The key \"$key\" is already in the file! Skipping entry... elif [ "`echo $SSHKEY | grep ERROR`" ]; then echo WARNING: The key \"$key\" is not properly formatted or is corrupted! Skipping entry... else echo "# $key $description" >> $TMP/$FNAME.tmp; echo "$SSHKEY" >> $TMP/$FNAME.tmp fi elif [ "$FNAME" == "authorization" ]; then #before the pub key file will be tar-red, check the format (this will not skip the failed keys, they will be uploaded with others) getkey $key echo -e "Key\t$key" >> $TMP/$FNAME.tmp; # tar keys and prepare to upload them tar -r -C $KEYPATH -f $TMP/$FNAME-tmp.tar $key; fi; else echo "The key \"$key\" doesn't exist." fi done writedirect "add"; done exit 0 } ### removedirect() # Direct removal of specified keys ### removedirect(){ for HOST in $( echo $HOST | sed -e 's/,/ /g' ); do echo -e "\nINFO: Connecting to host $HOST" findfile; #download the auth. file getfile $SSHOUT; #remove requested lines accorind to specified keys lines=''; for key in $( echo $1 | sed -e 's/,/ /g'); do echo ""; if [ -f $KEYPATH/$key ]; then if [ "$FNAME" == "authorized_keys" ]; then #prepare the pub key file to proper form getkey $key #find match and store line numbers to the LINENR LINENR="`cat $TMP/$FNAME.tmp | grep -n "" | grep --color "$SSHKEY" | cut -d ":" -f 1`" if [ "$LINENR" != "" ]; then #try if the previous line is a comment COMMENT="`cat $TMP/$FNAME.tmp | awk NR==$(($LINENR-1))`" if [[ "$COMMENT" == \#* ]]; then lines="$lines"" $LINENR $(($LINENR-1))" echo \"$key\" match: cat $TMP/$FNAME.tmp | awk NR==$(($LINENR-1)) cat $TMP/$FNAME.tmp | awk NR==$LINENR else lines="$lines"" $LINENR" echo \"$key\" match \(without comment line\): cat $TMP/$FNAME.tmp | awk NR==$LINENR fi else echo No match for key \"$key\".; fi elif [ "$FNAME" == "authorization" ]; then if [ "`cat $TMP/$FNAME.tmp | grep -n "" | grep --color "$key"`" != "" ]; then echo \"$key\" match: cat $TMP/$FNAME.tmp | grep -n "" | sed -e 's/:/: /' | grep --color "$key" lines="$lines"" `cat $TMP/$FNAME.tmp | grep -n "" | grep --color "$key" | cut -d ":" -f 1`" REMKEYS="`echo $REMKEYS $key`"; else echo No match for key \"$key\".; fi fi else echo "The key \"$key\" doesn't exist." fi done #if some matching keys were found if [ ! -z "$lines" ]; then SORTED=`echo $lines | tr " " "\n" | sort -nr | uniq`; echo -e '\n'INFO: These lines will be removed: $SORTED #additional info when authorization file is used if [ "$FNAME" == "authorization" ]; then echo INFO: These keys will be removed: $REMKEYS fi #remove specified/selected lines echo ""; for line in $SORTED; do echo Removing: $line: `awk NR==$line $TMP/$FNAME.tmp` ; sed -i "$line"d $TMP/$FNAME.tmp; done #write to the file writedirect "rem"; else echo -e '\n'WARNING: No matching key found...; echo INFO: Removing $TMP/$FNAME.tmp rm $TMP/$FNAME.tmp echo "# # # DONE # # # "; fi done exit 0 } ### remove() # Remove specified lines from file ### remove(){ #sort entered numbers to remove lines in correct order SORTED=`echo $1 | tr "," "\n" | tr " " "\n" | sort -nr | uniq` echo These lines will be removed: $SORTED if [ $(( `echo $SORTED | wc -w` % 2 )) != 0 ]; then echo "WARNING: Entered line count is not even, are you sure to remove selected lines?" fi echo "Press enter to continue or CTRL+C to quit." read w8; #remove the specified lines, optionally mark keys which would be also removed for line in $SORTED; do echo Removing: $line: `awk NR==$line $TMP/$FNAME.tmp` if [ "$FNAME" == "authorization" ]; then THISKEY="`awk NR==$line $TMP/$FNAME.tmp | sed -e 's/Key\t//g'`" REMKEYS="`echo $REMKEYS $THISKEY | tr " " ","`" fi sed -i "$line"d $TMP/$FNAME.tmp done #additional info when authorization file is used if [ "$FNAME" == "authorization" ]; then echo INFO: These keys will be removed: $REMKEYS fi #write to the file writedirect "rem"; exit 0 } ### check() # Info function; display keys, compare them, show options ### check(){ #find the used authorization files, choose which one to use findfile; #when the file is found and chosen, download it getfile $SSHOUT; #compare the file with all keys, don't compare authorization file as it contains only keyfile names if [ "$FNAME" != "authorization" ]; then echo Matching keys: for key in $( ls $KEYPATH ); do #get the key getkey $key #print matching/known keys if [ "`cat $TMP/$FNAME.tmp | grep -n "" | sed -e 's/:/: /' | grep --color -B 1 "$SSHKEY"`" != "" ]; then echo -e Key: $key cat $TMP/$FNAME.tmp | grep -n "" | sed -e 's/:/: /' | grep --color -B 1 "$SSHKEY" KEY="$KEY"" `cat $TMP/$FNAME.tmp | grep -n "" | sed -e 's/:/: /' | grep --color -B 1 "$SSHKEY" | cut -d ":" -f 1`" echo "" fi done #show supported options echo -e '\n'Would you like to [a]dd/[r]emove? [continue]; read opt; case "$opt" in "a" ) cd $KEYPATH; ls -l; echo -n "enter keys to add (key1 key2 ... or use * to select all files): "; read -e addkey; adddirect "$addkey" "info"; ;; "r" ) echo -n "enter line numbers to remove (enter lines for comment and key) (nr nr ...): "; read remnr; remove "$remnr"; ;; * ) echo NON-Matching keys: ;; esac #printf all other entries in file exept of known keys LNCOUNT=`cat $TMP/$FNAME.tmp | wc -l` ACTLN=1 while [ "$LNCOUNT" -ge "$ACTLN" ]; do if [ ! "`echo $KEY | grep -w $ACTLN`" ]; then echo $ACTLN: `cat $TMP/$FNAME.tmp | awk NR==$ACTLN` fi let ACTLN=$ACTLN+1 done #else print the whole file else cat $TMP/$FNAME.tmp | grep -n "" | sed -e 's/:/: /'; fi #show supported options echo -e '\n'Would you like to [a]dd/[r]emove/[b]ackup restore/[e]xit/[c]ancel? [exit]; read opt; case "$opt" in "a" ) cd $KEYPATH; ls -l; echo -n "enter keys to add (key1 key2 ... or use * to select all files): "; read -e addkey; adddirect "$addkey" "info"; ;; "r" ) echo -n "enter line numbers to remove(nr nr ...): "; read remnr; remove "$remnr"; ;; "b" ) restore; ;; "c" ) exit 0; ;; * ) echo Removing temp file and exitting... rm $TMP/$FNAME.tmp exit 0; ;; esac exit 0 } # if no parameters are specified, show them how it works if [ $# -eq 0 ];then usage; fi ## check prerequisites # check OS if [ -f /etc/*release ]; then OSversion="`cat /etc/*release | head -n 1 | cut -d\ -f 1,2 | tr [A-Z] [a-z]`" case $OSversion in "red hat") echo "INFO: your OS is supported.";; "suse linux") echo "INFO: your OS is supported.";; *) echo "ERROR: Unsupported OS, supported systems are SLES and RHEL." echo "Press any key to ignore this error and continue." read w8;; esac else echo "ERROR: Unable to determine OS, supported systems are SLES and RHEL." echo "Press any key to ignore this error and continue." read w8 fi # check tools used in this script if [ `which sed 2>/dev/null 1>&2; echo $?` == 1 ]; then echo "FATAL ERROR: sed not found."; exit 1; fi if [ `which cut 2>/dev/null 1>&2; echo $?` == 1 ]; then echo "FATAL ERROR: cut not found."; exit 1; fi if [ `which ssh 2>/dev/null 1>&2; echo $?` == 1 ]; then echo "FATAL ERROR: ssh not found."; exit 1; fi if [ `which ssh-keygen 2>/dev/null 1>&2; echo $?` == 1 ]; then echo "FATAL ERROR: ssh-keygen not found."; exit 1; fi if [ `which tar 2>/dev/null 1>&2; echo $?` == 1 ]; then echo "ERROR: tar not found. Tar is needed when copying keys for \'autorization\' file"; fi if [ `which dos2unix 2>/dev/null 1>&2; echo $?` == 1 ]; then echo "ERROR: dos2unix not found. This tool is needed to convert public keys to proper format."; fi ### chkopts() # Check if all mandatory options are entered ### chkopts(){ if [ "$USERNAME" == "" ] || [ "$HOST" == "" ] || [ "$KEYPATH" == "" ]; then echo ERROR: You need to specify Username, Hostname and Keypath. exit 1 fi if [ ! -d $KEYPATH ]; then echo ERROR: The key path is not valid! exit 1 fi } #allowed options; in each case proper function is called with parameter (if specified) while getopts "u:h:k:ia:r:" option; do case "$option" in u ) USERNAME=$OPTARG;; h ) if [ -f "$OPTARG" ]; then HOST="`cat $OPTARG`"; else HOST=$OPTARG; fi;; k ) KEYPATH=$OPTARG; cd $KEYPATH; KEYPATH=`pwd`;; i ) chkopts; echo INFO MODE...; check;; a ) chkopts; echo ADDING KEYS...; ALLKEYS="`echo $OPTARG | tr " " ","`" echo KEYS: $ALLKEYS adddirect $ALLKEYS "direct";; r ) chkopts; echo REMOVING KEYS...; ALLKEYS="`echo $OPTARG | tr " " ","`" echo KEYS: $ALLKEYS removedirect $ALLKEYS;; [?]) echo "Bad option."; usage;; esac done exit 0
No comments:
Post a Comment