#!/bin/bash # # Author: Georg Voell - georg.voell@oracle.com # Version: @(#)key-management 3.0.1 22.06.2020 (c)2020 Oracle # #@ Manage the ssh keys. #@ #@Usage: key-management [options] action [format] #@ Options: #@ -h, --help : Displays helptext. #@ -v, --version : Displays the version of the script. #@ -u, --username : Name of user e.g. "name@org.com". #@ -p, --passphrase : Passphrase for key encryption. #@ Action: #@ create : Create private and public keypair for ssh and putty. #@ delete : Delete all the keys for user specified by username. #@ copy : Copy keys to destination (could be "user@hostname" or IP e.g. "opc@130.61.219.239"). #@ install : Install management software. #@ list : List all local user with keys. #@ show : Display keys or fingerprint. Allowed values: "pub", "ssh", "api", "pk8", "ppk" and 'fp'. #@ Format: #@ pub: Display ssh public key. #@ ssh: Display ssh private key. #@ api: Display public key in PEM format (OCI API key). #@ pk8: Display private key in PEM format (PKCS#8). #@ ppk: Display putty private key (PPK). #@ fp : Display fingerprint of private key. #@ #@Examples: #@ key-management create --username "opc" #@ Create keys for user "opc" #@ key-management list #@ Show all user (which have keys created with this tool) #@ key-management show api --username "opc" #@ Display OCI API public key in PEM format. #@ key-management show ssh --username "opc" #@ Display ssh private key. #@ key-management show fp --username "opc" #@ Display fingerprint for ssh private key (needed by OCI). # # Exit codes: # 01: Unknown or wrong parameter. # 02: No username specified. # 03: Error while creating keys. # 04: Key (or user) does not exist. # 05: Could not copy keys to destination. # 99: User interrupt. # # See also: # **install-scripts**(1) # # ToDo: # # Known bugs: # # Update history: # # V 3.0.0 11.06.2020 New version # V 3.0.1 22.06.2020 Only use print-table if tcsh is available # script=${0} # Name of this script progstr=`basename $script` # Basename of the script progdir=`dirname $script` # Dirname of the script source "${progdir}/lib.bash" # Include default bash library PATH="$WORKPATH" # Set PATH to something useful # Set some deaults keygenurl="https://atrona.de/ssh-keygen/keygen.pl" sshstr=".ssh" authkeysstr="authorized_keys" configstr="config" keysstr="keys" infostr="info.txt" ppstr="passphrase.txt" keybasename="id_rsa" sshfolder="${REALHOME}/$sshstr" keysfolder="${sshfolder}/$keysstr" sshconfig="${sshfolder}/$configstr" ppfile="${keysfolder}/$ppstr" # Do extra cleanup function ExtraCleanup() { filecheck -rm ${scratchfile}.keys filecheck -rm ${scratchfile}.user } # Returns a URI string for passing to curl (or transfer) function UriEncode() { # Check if he have jq in path jq=`filecheck -x jq` # We can do translation only if we have jq in PATH if [ "$jq" != "" ]; then $jq -nr --arg v "$1" '$v|@uri' else echo "$1" fi } # Get the fingerprint from private key function GetFingerprint() { privkey=${1} passphrase=${2} # Preset fingerprint="" addparams="" if [ -r "$privkey" ]; then opensslinst=`filecheck -x openssl` if [ "$opensslinst" != "" ]; then sslversstr=`$opensslinst version` havefips=`echo "$sslversstr" | grep 'fips'` encrypted=`grep "ENCRYPTED" "$privkey"` if [ "$encrypted" != "" -a "$passphrase" != "" ]; then $opensslinst rsa -pubout -outform DER -passin "pass:$passphrase" -in "$privkey" -out $scratchfile > /dev/null 2>&1 else $opensslinst rsa -pubout -outform DER -in "$privkey" -out $scratchfile > /dev/null 2>&1 fi if [ -r "$scratchfile" ]; then if [ "$havefips" != "" ]; then addparams="-non-fips-allow" fi fingerprint=`cat $scratchfile | $opensslinst md5 -c $addParams | sed 's|(stdin)= ||g'` fi fi fi # Return result echo "$fingerprint" } # Get the fingerprint from infofile function GetFingerprintFromInfo() { username=${1} fingerprint="" if [ "$username" != "" ]; then infofile="${keysfolder}/${username}/$infostr" if [ -r "$infofile" ]; then fingerprint=`grep "Fingerprint:" "$infofile" | cut -d':' -f2- | sed 's|^ *||' | tr -d "'"` fi fi echo "$fingerprint" } # Get the passphrase from ppfile function GetPassphraseFromPPFile() { username=${1} passphrase="" if [ "$username" != "" ]; then if [ -r "$ppfile" ]; then passphrase="`grep "^$username " "$ppfile" | cut -d' ' -f2`" fi fi echo "$passphrase" } # Generate tab separated list with infos function WriteToKeylist() { username=${1} keyfile="${keysfolder}/${username}/$keybasename" if [ ! -r "$keyfile" ]; then keyfile="${keysfolder}/${username}/${keybasename}.pk8" fi if [ -r "$keyfile" ]; then fingerprint="`GetFingerprintFromInfo "$username"`" encrypted=`grep "ENCRYPTED" "$keyfile"` if [ "$encrypted" = "" ]; then havepassphrase="No" else havepassphrase="Yes" fi printf "%s\t%s\t%s\t%s\n" "$username" "$havepassphrase" "$fingerprint" "$keyfile" >> ${scratchfile}.keys fi } # Copy keys to another host function CopyKeys() { username=${1} destination=${2} errcode=0 serviceuser="`echo $destination | cut -d'@' -f1`" servicehost="`echo $destination | cut -d'@' -f2`" if [ "$serviceuser" = "$servicehost" ]; then printf "Please specify destination e.g. 'opc@130.61.219.239'. Exiting.\n" errcode=5 else if [ "$username" != "" ]; then if [ -d "${keysfolder}/$username" ]; then # Copy user folder with keys to host scp -q -r "${keysfolder}/$username" "${destination}:/tmp" stat=$? if [ $stat -eq 0 ]; then # Create move script echo 'if [ ! -d "$HOME/'$sshstr'" ]; then mkdir -m 0700 -p "$HOME/'$sshstr'"; fi' > $scratchfile echo 'if [ ! -d "$HOME/'$sshstr'/'$keysstr'" ]; then mkdir -m 0700 "$HOME/'$sshstr'/'$keysstr'"; fi' >> $scratchfile echo 'if [ ! -d "$HOME/'$sshstr'/'$keysstr'/'$username'" ]; then mv "/tmp/'$username'" "$HOME/'$sshstr'/'$keysstr'"; else rm -fR "/tmp/'$username'" "'$scratchfile'"; exit 5; fi' >> $scratchfile echo 'pubkey="`cat "$HOME/'$sshstr'/'$keysstr'/'$username'/'$keybasename'.pub"`"' >> $scratchfile echo 'result="`grep "$pubkey" "$HOME/'$sshstr'/'$authkeysstr'"`"' >> $scratchfile echo 'if [ "$result" = "" ]; then echo "$pubkey" >> "$HOME/'$sshstr'/'$authkeysstr'"; fi' >> $scratchfile echo "rm -f $scratchfile" >> $scratchfile scp -q "$scratchfile" "${destination}:$scratchfile" ssh "$destination" "cat $scratchfile | bash" stat=$? if [ $stat -ne 0 ]; then printf "Installing (ssh) failed. Exiting.\n" errcode=5 fi else printf "Copy (scp) failed. Exiting.\n" errcode=5 fi else printf "Keys do not exist in folder '${keysfolder}/$username'. Exiting.\n" errcode=4 fi else printf "Username not specified.\n" errcode=2 fi fi return $errcode } # Create keys if user folder doesn't exists function CreateKeys() { username=${1} passphrase=${2} errcode=0 if [ "$username" != "" ]; then if [ ! -d "${keysfolder}/$username" ]; then uriusername=`UriEncode "$username"` if [ "$passphrase" != "" ]; then uripassphrase=`UriEncode "$passphrase"` myurl="${keygenurl}?username=${uriusername}&passphrase=${uripassphrase}" else myurl="${keygenurl}?username=${uriusername}" fi transfer --quiet "$myurl" -o "${keysfolder}/${username}.zip" stat=$? # If we got an error - remove zip file if it does exisits if [ $stat -ne 0 ]; then echo "transfer error" filecheck -rm "${keysfolder}/${username}.zip" fi # If we could download zip with keys - continue if [ -f "${keysfolder}/${username}.zip" ]; then unzip -q "${keysfolder}/${username}.zip" -d "$keysfolder" rm -f "${keysfolder}/${username}.zip" # Create passphrase file if [ ! -f "$ppfile" ]; then printf "username\tpassphrase\n" > "$ppfile" chmod 600 "$ppfile" fi # Write username and passphrase to ppfile printf "%s\t%s\n" "$username" "$passphrase" >> "$ppfile" # Delete first 2 lines (containing passphrase) from infofile infofile="${keysfolder}/${username}/$infostr" mv -f "$infofile" $scratchfile # tail +3 $scratchfile > "$infofile" sed '1,2d' $scratchfile > "$infofile" chmod 600 "$infofile" rm -f $scratchfile printf "Keys created in folder '${keysfolder}/$username'.\n" else printf "Keys could not be created.\n" errcode=3 fi else printf "Keys exists in folder '${keysfolder}/$username'. Leaving keys unchanged.\n" errcode=3 fi else printf "Username not specified.\n" errcode=2 fi return $errcode } # Preset param="" format="" username="" passphrase="" # Check parameters: Loop until all parameters are used up while [ "$1" != "" ]; do pname=${1} case "$pname" in -u | --username) shift if [ "$1" != "" ]; then username=${1} shift else errstr="Please specify a username (e.g. 'name@org.com') after parameter '$pname'." fi ;; -p | --passphrase) shift if [ "$1" != "" ]; then passphrase=${1} shift else errstr="Please specify a passphrase (e.g. 'MySecret') after parameter '$pname'." fi ;; -v | --version) shift showversion=1 ;; -h | --help) shift showhelp=1 ;; *) paramck=`echo "$1" | grep '^-'` # Types don't begin with '-' if [ "$param" = "" -a "$paramck" = "" ]; then param=`echo "$1" | tr "[:upper:]" "[:lower:]"` else if [ "$format" = "" -a "$paramck" = "" ]; then format=`echo "$1" | tr "[:upper:]" "[:lower:]"` else errstr="Unknown parameter: '$1'." fi fi shift esac done # Display help or error message DisplayHelp ### Main # Create ssh folder if it doesn't exists if [ ! -d "$sshfolder" ]; then mkdir -m 0700 -p "$sshfolder" fi # Create keys folder if it doesn't exists if [ ! -d "$keysfolder" ]; then mkdir -m 0700 "$keysfolder" fi # Create ssh config if it doesn't exists if [ ! -f "$sshconfig" ]; then printf "# Created by tool '$progstr'.\n\n" > "$sshconfig" printf "# Default settings\n" >> "$sshconfig" printf 'Host *\n' >> "$sshconfig" printf '\tForwardAgent no\n' >> "$sshconfig" printf '\tForwardX11 no\n' >> "$sshconfig" printf '\tForwardX11Trusted no\n' >> "$sshconfig" printf '\tPort 22\n' >> "$sshconfig" printf '\tProtocol 2\n' >> "$sshconfig" printf '\tServerAliveInterval 60\n' >> "$sshconfig" printf '\tServerAliveCountMax 30\n' >> "$sshconfig" printf '\tStrictHostKeyChecking no\n' >> "$sshconfig" printf '\tUserKnownHostsFile /dev/null\n' >> "$sshconfig" printf '\tLogLevel error\n\n' >> "$sshconfig" chmod 600 "$sshconfig" fi # Create a list with all existing users and check if user already exists stat=0 ls "$keysfolder" > ${scratchfile}.user haveuser=`filecheck -s ${scratchfile}.user` if [ "$haveuser" != "" -a "$username" != "" ]; then user="`grep "^$username$" ${scratchfile}.user`" else user="" fi # If we don't have an action specified - list all keys if [ "$param" = "" ]; then param="list" fi case "$param" in delete) if [ "$username" = "" ]; then exitcode=2 errormsg $exitcode "($progstr) No username specified." else if [ "$username" = "$user" ]; then # Keys exist for user confirm "Are you sure to delete all keys for username '$username'?" --yes "y/yes" --no "n/[no]" stat=$? if [ $stat -eq 0 ]; then rm -fR "${keysfolder}/$username" if [ -f "$ppfile" ]; then mv -f "$ppfile" $scratchfile grep -v "^$username " $scratchfile > "$ppfile" rm -f $scratchfile chmod 600 "$ppfile" fi else printf "Leaving keys unchanged.\n" fi else echo "username: '$username'." echo "user: '$user'." exitcode=4 errormsg $exitcode "($progstr) Keys do not exist for username '$username'." fi fi ;; create) if [ "$username" = "" ]; then exitcode=2 errormsg $exitcode "($progstr) No username specified." else if [ "$username" = "$user" ]; then # Keys already exist for user confirm "Keys for username '$username' already exist. Do you want to renew?" --yes "y/yes" --no "n/[no]" stat=$? if [ $stat -eq 0 ]; then rm -fR "${keysfolder}/$username" if [ -f "$ppfile" ]; then mv -f "$ppfile" $scratchfile grep -v "^$username " $scratchfile > "$ppfile" rm -f $scratchfile chmod 600 "$ppfile" fi else printf "Leaving keys unchanged.\n" fi fi if [ $stat -eq 0 ]; then CreateKeys "$username" "$passphrase" exitcode=$? fi fi ;; copy) if [ "$username" = "" ]; then exitcode=2 errormsg $exitcode "($progstr) No username specified." else if [ "$username" = "$user" ]; then # Keys exist for user CopyKeys "$username" "$format" exitcode=$? else exitcode=4 errormsg $exitcode "($progstr) Keys do not exist for username '$username'." fi fi ;; install) ;; list) if [ "$haveuser" != "" ]; then printf "username\tencrypted\tfingerprint\tprivate-key\n" > ${scratchfile}.keys if [ "$username" != "" ]; then if [ "$username" = "$user" ]; then WriteToKeylist "$username" else exitcode=4 errormsg $exitcode "($progstr) Keys do not exist for username '$username'." fi else # List all user while read -r username; do WriteToKeylist "$username" done < ${scratchfile}.user fi # Print result if [ $exitcode -eq 0 ]; then # Check if we have tcsh available tcsh=`filecheck -x tcsh` if [ "$tcsh" != "" ]; then print-table ${scratchfile}.keys else cat ${scratchfile}.keys fi fi else printf "No keys created yet.\n" fi ;; show) if [ "$username" = "" ]; then exitcode=2 errormsg $exitcode "($progstr) No username specified." else if [ "$username" = "$user" ]; then # Keys exist for user case "$format" in ssh) keyfile="${keysfolder}/${username}/$keybasename" if [ -r "$keyfile" ]; then cat "$keyfile" else exitcode=4 fi ;; api) keyfile="${keysfolder}/${username}/${keybasename}.pem" if [ -r "$keyfile" ]; then cat "$keyfile" else exitcode=4 fi ;; pub | pk8 | ppk) keyfile="${keysfolder}/${username}/${keybasename}.$format" if [ -r "$keyfile" ]; then cat "$keyfile" else exitcode=4 fi ;; fp) fingerprint="`GetFingerprintFromInfo "$username"`" if [ "$fingerprint" != "" ]; then echo "$fingerprint" else keyfile="${keysfolder}/${username}/$keybasename" if [ ! -r "$keyfile" ]; then keyfile="${keysfolder}/${username}/${keybasename}.pk8" fi if [ -r "$keyfile" ]; then encrypted=`grep "ENCRYPTED" "$keyfile"` if [ "$encrypted" != "" ]; then mypassphrase="`GetPassphraseFromPPFile "$username"`" if [ "$mypassphrase" = "" ]; then mypassphrase="$passphrase" fi fingerprint=`GetFingerprint "$keyfile" "$mypassphrase"` else fingerprint=`GetFingerprint "$keyfile"` fi if [ "$fingerprint" != "" ]; then echo "$fingerprint" else exitcode=4 fi else exitcode=4 fi fi ;; *) errormsg 1 "($progstr) Unknown format '$format'." esac else exitcode=4 errormsg $exitcode "($progstr) Keys do not exist for username '$username'." fi fi ;; *) errormsg 1 "($progstr) Unknown action '$param'." esac # Cleanup and exit Cleanup exit $exitcode