Files
SSH-Rotate-Keys/bin/admin-remove-old-ssh-keys.sh
2024-08-30 11:43:41 +09:00

174 lines
5.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Remove previous keys
# base folder for all data
BASE_FOLDER=$(dirname "$(readlink -f "$0")")"/";
# config folder
CONFIG_BASE="${BASE_FOLDER}../config/";
# previous public key
SSH_PUBLIC_KEYS_PREVIOUS="${BASE_FOLDER}../ssh-public-keys/admin-previous/";
# list of admin user names, if username does not match this only update the user entry
ADMIN_USERS=(admin ubuntu ec2-user)
DRY_RUN=0;
GO=0;
HOST_ONLY="";
USER_ONLY="";
#
while getopts ":h:u:ng" opt; do
case "${opt}" in
h) # hostname
HOST_ONLY="${OPTARG}";
;;
u) # username
USER_ONLY="${OPTARG}";
;;
n) # dry-run
DRY_RUN=1;
;;
g) # go
GO=1;
;;
\?)
echo -e "\n Option does not exist: ${OPTARG}\n";
echo "-h override single host name";
echo "-u override user name for a host";
echo "-f force key change";
echo "-n dry run";
echo "-g flag for actual change call";
echo ""
exit 1;
;;
esac
done
if [ ! -d "${SSH_PUBLIC_KEYS_PREVIOUS}" ]; then
echo "Missing ssh public keys previous folder: ${SSH_PUBLIC_KEYS_PREVIOUS}";
exit;
fi
# load config
if [ ! -f "${CONFIG_BASE}settings.ini" ]; then
echo "Missing 'settings.ini' file in ${CONFIG_BASE}";
exit;
fi
# shellcheck source=../config/settings.ini
# shellcheck disable=SC1094
source <(grep "=" "${CONFIG_BASE}settings.ini" | sed 's/ *= */=/g')
if [ -z "${key_age}" ]; then
echo "A minimnum key age in days must be set in the settings";
exit;
fi
if [ -z "${server_list}" ]; then
echo "No server list is defined in the settings";
exit;
fi;
# we must have "server_list" set and file must be in config folder
if [ ! -f "${CONFIG_BASE}${server_list}" ]; then
echo "Cannot find ${server_list} file in the config folder";
exit
fi
# abort if go not set
if [ ${GO} -eq 0 ] && [ ${DRY_RUN} -eq 1 ]; then
GO=1;
elif [ ${GO} -eq 0 ]; then
echo "No -g (go) parameter set. aborting. For testing set -n for dry run"
exit;
fi
# default ssh command
# -t is needed for systens when "Defaults requiretty" is set
SSH="ssh -a -x -n";
remove_ssh_key() {
AUTH_KEY_FILE="${1}";
PUB_KEY_FILE="${2}";
RMV_CHATTR_I="chattr -i"
ADD_CHATTR_I="chattr +i"
RMV_CHMOD_UW="chmod u-w"
ADD_CHMOD_UW="chmod u+w"
pub_key=$(cat "${PUB_KEY_FILE}");
# we need to escape for sed
pub_key_escaped=$(printf '%s\n' "$pub_key" | sed -e 's/[]\/$*.^[]/\\&/g');
# the -z `tail ...` checks for a trailing newline. The echo adds one if was missing (from ssh-copy-id)
UNINSTALLKEYS_SH=$(tr '\t\n' ' ' <<-EOF
if [ -f "${AUTH_KEY_FILE}" ] && grep "${pub_key}" "${AUTH_KEY_FILE}" >> /dev/null; then
${RMV_CHATTR_I} "${AUTH_KEY_FILE}";
${ADD_CHMOD_UW} "${AUTH_KEY_FILE}";
sed -i "/${pub_key_escaped}/d" "${AUTH_KEY_FILE}";
${RMV_CHMOD_UW} "${AUTH_KEY_FILE}";
${ADD_CHATTR_I} "${AUTH_KEY_FILE}";
else
echo "[!] Already removed";
fi;
EOF
);
# to defend against quirky remote shells: use 'exec sh -c' to get POSIX;
printf "exec sudo sh -c '%s'" "${UNINSTALLKEYS_SH}"
}
uninstall_ssh_key() {
HOSTNAME="${1}";
USERNAME="${2}";
PUB_KEY_FILE="${3}";
AUTH_KEY_FILE="${4}";
echo "[.] Remove from auth file: ${AUTH_KEY_FILE}";
if [ ${DRY_RUN} -eq 0 ]; then
# find the pub key in the file and remove this line only
${SSH} "${USERNAME}"@"${HOSTNAME}" "$(remove_ssh_key "${AUTH_KEY_FILE}" "${PUB_KEY_FILE}")"
else
echo "${SSH} \"${USERNAME}\"@\"${HOSTNAME}\" \"\$(remove_ssh_key \"${AUTH_KEY_FILE}\" \"${PUB_KEY_FILE}\")\"";
fi
}
# find last public in remote server and remove it
while read -r line; do
if [[ "${line}" =~ ^\# ]]; then
continue;
fi
# hostname is on pos 1
hostname=$(echo "${line}" | cut -d "," -f 1);
# if hostname opt set and not matching skip
if [ -n "${HOST_ONLY}" ] && [ "${HOST_ONLY}" != "${hostname}" ]; then
continue;
fi
# login user name
username=$(echo "${line}" | cut -d "," -f 2);
# if username opt set and not matching skip
if [ -n "${USER_ONLY}" ] && [ "${USER_ONLY}" != "${username}" ]; then
continue;
fi
# flags: (not used at the moment)
flags=$(echo "${line}" | cut -d "," -f 3);
# auth key settings (in front of auth key)
# settings=$(echo "${line}" | cut -d "," -f 4);
# ssh key names
SSH_KEY_PUB_FILE="${hostname}_${username}.pem.pub";
# previous public key does not exist, skip
if [ ! -f "${SSH_PUBLIC_KEYS_PREVIOUS}${SSH_KEY_PUB_FILE}" ]; then
echo "[!] No previous public key file ${SSH_KEY_PUB_FILE} for ${username}@${hostname}";
echo "[_] ............... SKIP";
continue;
fi
echo "[-] Remove previous key for: ${username}@${hostname} with flags '${flags}'";
# find in master key and $admin user
if [[ ${ADMIN_USERS[*]} =~ $username ]]; then
# find in "/etc/ssh/authorized_keys--master";
uninstall_ssh_key "${hostname}" "${username}" "${SSH_PUBLIC_KEYS_PREVIOUS}${SSH_KEY_PUB_FILE}" "/etc/ssh/authorized_keys--master";
fi
uninstall_ssh_key "${hostname}" "${username}" "${SSH_PUBLIC_KEYS_PREVIOUS}${SSH_KEY_PUB_FILE}" "/etc/ssh/authorized_keys/${username}"
# remove old key
echo "[-] Remove previous public key: ${SSH_KEY_PUB_FILE}";
if [ ${DRY_RUN} -eq 0 ]; then
rm "${SSH_PUBLIC_KEYS_PREVIOUS}${SSH_KEY_PUB_FILE}";
else
echo "rm \"${SSH_PUBLIC_KEYS_PREVIOUS}${SSH_KEY_PUB_FILE}\";";
fi;
echo "[=] ............... DONE";
done <<<"$(sed 1d "${CONFIG_BASE}${server_list}")";
# __END__