From 07108e576461a5283110bd4e4ac53d53b938bc24 Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Fri, 30 Aug 2024 09:46:59 +0900 Subject: [PATCH] Clean up admin ssh rotate scripts --- ...h-keys.sh => admin-remove-old-ssh-keys.sh} | 45 ++++++++------- ...e-ssh-keys.sh => admin-rotate-ssh-keys.sh} | 57 +++++++++++-------- ...est-ssh-keys.sh => admin-test-ssh-keys.sh} | 38 ++++++++----- .../{current => admin-current}/.gitignore | 0 .../{previous => admin-previous}/.gitignore | 0 5 files changed, 82 insertions(+), 58 deletions(-) rename bin/{remove-old-ssh-keys.sh => admin-remove-old-ssh-keys.sh} (82%) rename bin/{rotate-ssh-keys.sh => admin-rotate-ssh-keys.sh} (89%) rename bin/{test-ssh-keys.sh => admin-test-ssh-keys.sh} (77%) rename ssh-public-keys/{current => admin-current}/.gitignore (100%) rename ssh-public-keys/{previous => admin-previous}/.gitignore (100%) diff --git a/bin/remove-old-ssh-keys.sh b/bin/admin-remove-old-ssh-keys.sh similarity index 82% rename from bin/remove-old-ssh-keys.sh rename to bin/admin-remove-old-ssh-keys.sh index 3bbd894..452db05 100755 --- a/bin/remove-old-ssh-keys.sh +++ b/bin/admin-remove-old-ssh-keys.sh @@ -7,31 +7,27 @@ 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/previous/"; +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; -FORCE=0; GO=0; HOST_ONLY=""; USER_ONLY=""; # -while getopts ":h:u:nfg" opt; do +while getopts ":h:u:ng" opt; do case "${opt}" in - h|hostname) + h) # hostname HOST_ONLY="${OPTARG}"; ;; - u|username) + u) # username USER_ONLY="${OPTARG}"; ;; - n|dry-run) + n) # dry-run DRY_RUN=1; ;; - f|force) - FORCE=1; - ;; - g|go) + g) # go GO=1; ;; \?) @@ -53,9 +49,20 @@ if [ ! -d "${SSH_PUBLIC_KEYS_PREVIOUS}" ]; then fi # load config -if [ -f "${CONFIG_BASE}settings.ini" ]; then - source <(grep = "${CONFIG_BASE}settings.ini" | sed 's/ *= */=/g') +if [ ! -f "${CONFIG_BASE}settings.ini" ]; then + echo "Missing 'settings.ini' file in ${CONFIG_BASE}"; + exit; fi +# shellcheck source=../config/settings.ini +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"; @@ -113,26 +120,26 @@ uninstall_ssh_key() { } # find last public in remote server and remove it -for line in `cat "${CONFIG_BASE}${server_list}" | sed 1d`; do - if [[ "${i}" =~ ^\# ]]; then +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 [ ! -z "${HOST_ONLY}" ] && [ "${HOST_ONLY}" != "${hostname}" ]; then + 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 [ ! -z "${USER_ONLY}" ] && [ "${USER_ONLY}" != "${username}" ]; then + 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); + # settings=$(echo "${line}" | cut -d "," -f 4); # ssh key names SSH_KEY_PUB_FILE="${hostname}_${username}.pem.pub"; @@ -145,7 +152,7 @@ for line in `cat "${CONFIG_BASE}${server_list}" | sed 1d`; do echo "[-] Remove previous key for: ${username}@${hostname} with flags '${flags}'"; # find in master key and $admin user - if [[ ${ADMIN_USERS[@]} =~ $username ]]; then + 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 @@ -158,6 +165,6 @@ for line in `cat "${CONFIG_BASE}${server_list}" | sed 1d`; do echo "rm \"${SSH_PUBLIC_KEYS_PREVIOUS}${SSH_KEY_PUB_FILE}\";"; fi; echo "[=] ............... DONE"; -done +done <<<"$(sed 1d "${CONFIG_BASE}${server_list}")"; # __END__ diff --git a/bin/rotate-ssh-keys.sh b/bin/admin-rotate-ssh-keys.sh similarity index 89% rename from bin/rotate-ssh-keys.sh rename to bin/admin-rotate-ssh-keys.sh index 2fa6306..5ecd15d 100755 --- a/bin/rotate-ssh-keys.sh +++ b/bin/admin-rotate-ssh-keys.sh @@ -11,8 +11,8 @@ LAST_ROTATE="${BASE_FOLDER}../last-rotate/"; # ssh-keys temp holder SSH_PRIVATE_KEYS="${BASE_FOLDER}../ssh-keys/"; # ssh public keys from current and last -SSH_PUBLIC_KEYS_PREVIOUS="${BASE_FOLDER}../ssh-public-keys/previous/"; -SSH_PUBLIC_KEYS_CURRENT="${BASE_FOLDER}../ssh-public-keys/current/"; +SSH_PUBLIC_KEYS_PREVIOUS="${BASE_FOLDER}../ssh-public-keys/admin-previous/"; +SSH_PUBLIC_KEYS_CURRENT="${BASE_FOLDER}../ssh-public-keys/admin-current/"; # list of admin user names, if username does not match this only update the user entry ADMIN_USERS=(admin ubuntu ec2-user) @@ -23,24 +23,24 @@ GO=0; HOST_ONLY=""; USER_ONLY=""; # -while getopts ":h:u:nfg" opt; do +while getopts ":h:u:nfcg" opt; do case "${opt}" in - h|hostname) + h) # hostname HOST_ONLY="${OPTARG}"; ;; - u|username) + u) # username USER_ONLY="${OPTARG}"; ;; - n|dry-run) + n) # dry-run DRY_RUN=1; ;; - f|force) + f) # force FORCE=1; ;; - c|force-create) + c) # force-create FORCE_CREATE=1 ;; - g|go) + g) # go GO=1; ;; \?) @@ -71,13 +71,20 @@ if [ ! -d "${SSH_PUBLIC_KEYS_PREVIOUS}" ]; then fi # load config -if [ -f "${CONFIG_BASE}settings.ini" ]; then - source <(grep = "${CONFIG_BASE}settings.ini" | sed 's/ *= */=/g') -fi -if [ -z "${key_age}" ]; then - echo "A minimnum key age in days must be set"; +if [ ! -f "${CONFIG_BASE}settings.ini" ]; then + echo "Missing 'settings.ini' file in ${CONFIG_BASE}"; exit; fi +# shellcheck source=../config/settings.ini +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"; @@ -141,7 +148,7 @@ add_ssh_key() { pub_key=$(cat "${PUB_KEY_FILE}"); # if we have auth key settings, prefix them to the pub key # Note that the check key "pub_key" ignores any prefixes, but we add with settings prefix - if [ ! -z "${AUTH_KEY_SETTINGS}" ]; then + if [ -n "${AUTH_KEY_SETTINGS}" ]; then pub_key_write="${AUTH_KEY_SETTINGS} ${pub_key}"; else pub_key_write="${pub_key}"; @@ -182,20 +189,20 @@ install_ssh_key() { fi } -for line in `cat "${CONFIG_BASE}${server_list}" | sed 1d`; do - if [[ "${i}" =~ ^\# ]]; then +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 [ ! -z "${HOST_ONLY}" ] && [ "${HOST_ONLY}" != "${hostname}" ]; then + 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 [ ! -z "${USER_ONLY}" ] && [ "${USER_ONLY}" != "${username}" ]; then + if [ -n "${USER_ONLY}" ] && [ "${USER_ONLY}" != "${username}" ]; then continue; fi # check if force or if last rotaet in valid range @@ -203,9 +210,9 @@ for line in `cat "${CONFIG_BASE}${server_list}" | sed 1d`; do # holds unix timestamp, if now - this timestamp is < key_age => skip last_rotate=$(cat "${LAST_ROTATE}${hostname}_${username}.last-rotate"); current_timestamp=$(date +%s) - age=$(( ($current_timestamp - $last_rotate) )) + age=$(( current_timestamp - last_rotate )) days_left=$(( (age)/(3600*24) )) - if [ $days_left -le $key_age ]; then + if [ $days_left -le "$key_age" ]; then echo "[!] Last rotate for ${username}@${hostname} was ${days_left} days ago, minimum is ${key_age}"; echo "[_] ............... SKIP"; continue; @@ -285,7 +292,7 @@ for line in `cat "${CONFIG_BASE}${server_list}" | sed 1d`; do echo "[~] Deploy current key for: ${username}@${hostname} with flags '${flags}': ${SSH_KEY_PUB_FILE}"; fi # deploy public key to server - if [[ ${ADMIN_USERS[@]} =~ $username ]]; then + if [[ ${ADMIN_USERS[*]} =~ $username ]]; then # - master admin file install_ssh_key "${hostname}" "${username}" "${SSH_PUBLIC_KEYS_CURRENT}${SSH_KEY_PUB_FILE}" "/etc/ssh/authorized_keys--master" "${auth_key_settings}"; fi @@ -320,11 +327,11 @@ for line in `cat "${CONFIG_BASE}${server_list}" | sed 1d`; do fi # post roate write timestamp into rotate file if [ ${DRY_RUN} -eq 0 ]; then - echo $(date +%s) > "${LAST_ROTATE}${hostname}_${username}.last-rotate"; + "$(date +%s)" > "${LAST_ROTATE}${hostname}_${username}.last-rotate"; else - echo "\"echo $(date +%s) > \"${LAST_ROTATE}${hostname}_${username}.last-rotate\";"; + echo "\"$(date +%s) > \"${LAST_ROTATE}${hostname}_${username}.last-rotate\";"; fi echo "[=] ............... DONE"; -done +done <<<"$(sed 1d "${CONFIG_BASE}${server_list}")"; # __END__ diff --git a/bin/test-ssh-keys.sh b/bin/admin-test-ssh-keys.sh similarity index 77% rename from bin/test-ssh-keys.sh rename to bin/admin-test-ssh-keys.sh index ecb5e98..134b6c6 100755 --- a/bin/test-ssh-keys.sh +++ b/bin/admin-test-ssh-keys.sh @@ -10,12 +10,12 @@ LAST_ROTATE="${BASE_FOLDER}../last-rotate/"; HOST_ONLY=""; USER_ONLY=""; -while getopts ":h:u:nfg" opt; do +while getopts ":h:u:" opt; do case "${opt}" in - h|hostname) + h) # hostname HOST_ONLY="${OPTARG}"; ;; - u|username) + u) # username USER_ONLY="${OPTARG}"; ;; \?) @@ -29,9 +29,20 @@ while getopts ":h:u:nfg" opt; do done # load config -if [ -f "${CONFIG_BASE}settings.ini" ]; then - source <(grep = "${CONFIG_BASE}settings.ini" | sed 's/ *= */=/g') +if [ ! -f "${CONFIG_BASE}settings.ini" ]; then + echo "Missing 'settings.ini' file in ${CONFIG_BASE}"; + exit; fi +# shellcheck source=../config/settings.ini +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"; @@ -50,20 +61,20 @@ TEST_STRING="TEST"; ERROR=0; WARNING=0; -for line in `cat "${CONFIG_BASE}${server_list}" | sed 1d`; do - if [[ "${i}" =~ ^\# ]]; then +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 [ ! -z "${HOST_ONLY}" ] && [ "${HOST_ONLY}" != "${hostname}" ]; then + 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 [ ! -z "${USER_ONLY}" ] && [ "${USER_ONLY}" != "${username}" ]; then + if [ -n "${USER_ONLY}" ] && [ "${USER_ONLY}" != "${username}" ]; then continue; fi @@ -81,7 +92,7 @@ for line in `cat "${CONFIG_BASE}${server_list}" | sed 1d`; do rotate_date=""; if [ -f "${LAST_ROTATE}${hostname}_${username}.last-rotate" ]; then # load last rotate timestamp and get YYYY-MM-DD - rotate_date=$(${datecmd} -d @$(cat "${LAST_ROTATE}${hostname}_${username}.last-rotate") +%F); + rotate_date=$(${datecmd} -d @"$(cat "${LAST_ROTATE}${hostname}_${username}.last-rotate")" +%F); fi # check for diff in username / hostname warning_string="" @@ -90,13 +101,13 @@ for line in `cat "${CONFIG_BASE}${server_list}" | sed 1d`; do fi # check for creation date diff if [ "${rotate_date}" != "${current_date}" ]; then - if [ ! -z "${warning_string}" ]; then + if [ -n "${warning_string}" ]; then warning_string="${warning_string}, "; fi warning_string="${warning_string}${rotate_date} != ${current_date}"; fi # print out warning or ok - if [ ! -z "${warning_string}" ]; then + if [ -n "${warning_string}" ]; then echo "[WARNING] ${warning_string}"; WARNING=1; else @@ -107,8 +118,7 @@ for line in `cat "${CONFIG_BASE}${server_list}" | sed 1d`; do echo "[!] FAILURE: ${response}"; ERROR=1; fi - -done +done <<<"$(sed 1d "${CONFIG_BASE}${server_list}")"; if [ ${WARNING} -eq 1 ]; then echo "A warning has been found by either username/hostname string in the PEM key not matching to call username/hostname or the rotate date differs to the creation date from the PEM public key"; diff --git a/ssh-public-keys/current/.gitignore b/ssh-public-keys/admin-current/.gitignore similarity index 100% rename from ssh-public-keys/current/.gitignore rename to ssh-public-keys/admin-current/.gitignore diff --git a/ssh-public-keys/previous/.gitignore b/ssh-public-keys/admin-previous/.gitignore similarity index 100% rename from ssh-public-keys/previous/.gitignore rename to ssh-public-keys/admin-previous/.gitignore