added --slave option, 3 new configuration parameters & supporting functions for master->slave operations, several bug fixes (VRF 1.5.0) [Patrick Van der Veken]
This commit is contained in:
parent
da24312c22
commit
7f23f5ac8b
@ -45,6 +45,16 @@ SSH_KEYSCAN_BIN="/usr/bin/ssh-keyscan"
|
|||||||
# by default -f <file> is used by manage_sudo.sh to supply hostnames, do not add here
|
# by default -f <file> is used by manage_sudo.sh to supply hostnames, do not add here
|
||||||
SSH_KEYSCAN_ARGS="-t rsa"
|
SSH_KEYSCAN_ARGS="-t rsa"
|
||||||
|
|
||||||
|
# whether to start an SSH agent process for the master->client operations [0=No; 1=Yes]
|
||||||
|
DO_SSH_AGENT=0
|
||||||
|
|
||||||
|
# whether to start an SSH agent process for the master->slave->client operations [0=No; 1=Yes]
|
||||||
|
DO_SSH_SLAVE_AGENT=0
|
||||||
|
|
||||||
|
# location of the SSH private key that should be added to the SSH agent process
|
||||||
|
# must be a passphrase-less key (required when using DO_SSH_AGENT, DO_SSH_SLAVE_AGENT)
|
||||||
|
SSH_PRIVATE_KEY="$HOME/.ssh/id_rsa"
|
||||||
|
|
||||||
# maximum number of background process to spawn (~maxuprc, ~nstrpty etc)
|
# maximum number of background process to spawn (~maxuprc, ~nstrpty etc)
|
||||||
MAX_BACKGROUND_PROCS=30
|
MAX_BACKGROUND_PROCS=30
|
||||||
|
|
||||||
|
365
manage_ssh.sh
365
manage_ssh.sh
@ -2,7 +2,7 @@
|
|||||||
#******************************************************************************
|
#******************************************************************************
|
||||||
# @(#) manage_ssh.sh
|
# @(#) manage_ssh.sh
|
||||||
#******************************************************************************
|
#******************************************************************************
|
||||||
# @(#) Copyright (C) 2014 by KUDOS BVBA <info@kudos.be>. All rights reserved.
|
# @(#) Copyright (C) 2014 by KUDOS BVBA (info@kudos.be). All rights reserved.
|
||||||
#
|
#
|
||||||
# This program is a free software; you can redistribute it and/or modify
|
# This program is a free software; you can redistribute it and/or modify
|
||||||
# it under the same terms of the GNU General Public License as published by
|
# it under the same terms of the GNU General Public License as published by
|
||||||
@ -18,13 +18,16 @@
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# @(#) MAIN: manage_ssh.sh
|
# @(#) MAIN: manage_ssh.sh
|
||||||
# DOES: performs basic functions for SSH controls: update SSH keys locally or
|
# DOES: performs basic functions for SSH controls: update SSH keys locally or
|
||||||
# remote, create SSH key fingerprints or distribute the SSH controls files
|
# remote, create SSH key fingerprints, distribute the SSH controls files,
|
||||||
|
# discover SSH host keys.
|
||||||
# EXPECTS: (see --help for more options)
|
# EXPECTS: (see --help for more options)
|
||||||
# REQUIRES: check_config(), check_logging(), check_params(), check_root_user(),
|
# REQUIRES: check_config(), check_logging(), check_params(), check_root_user(),
|
||||||
# check_setup(), check_syntax(), count_fields(), die(), display_usage(),
|
# check_setup(), check_syntax(), count_fields(), die(), display_usage(),
|
||||||
# distribute2host(), do_cleanup(), fix2host(), get_linux_version(),
|
# distribute2host(), distribute2slave(), do_cleanup(), fix2host(),
|
||||||
# log(), logc(), resolve_host(), sftp_file(), update2host(),
|
# fix2slave(), get_linux_name(), get_linux_version(), log(), logc(),
|
||||||
# update_fingerprints(), wait_for_children(), warn()
|
# resolve_host(), sftp_file(), start_ssh_agent(), stop_ssh_agent(),
|
||||||
|
# update2host(), update2slave(), update_fingerprints(),
|
||||||
|
# wait_for_children(), warn()
|
||||||
# For other pre-requisites see the documentation in display_usage()
|
# For other pre-requisites see the documentation in display_usage()
|
||||||
#
|
#
|
||||||
# @(#) HISTORY:
|
# @(#) HISTORY:
|
||||||
@ -53,6 +56,9 @@
|
|||||||
# @(#) (VRF 1.3.3) [Patrick Van der Veken]
|
# @(#) (VRF 1.3.3) [Patrick Van der Veken]
|
||||||
# @(#) 2015-09-27: added SSH host keys discovery, re-assigned '-d' command-line
|
# @(#) 2015-09-27: added SSH host keys discovery, re-assigned '-d' command-line
|
||||||
# @(#) option to this function (VRF 1.4.0) [Patrick Van der Veken]
|
# @(#) option to this function (VRF 1.4.0) [Patrick Van der Veken]
|
||||||
|
# @(#) 2015-10-03: added --slave option, 3 new configuration parameters & supporting
|
||||||
|
# @(#) functions for master->slave operations, several bug fixes
|
||||||
|
# @(#) (VRF 1.5.0) [Patrick Van der Veken]
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# DO NOT CHANGE THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
|
# DO NOT CHANGE THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
|
||||||
#******************************************************************************
|
#******************************************************************************
|
||||||
@ -66,7 +72,7 @@
|
|||||||
# or LOCAL_CONFIG_FILE instead
|
# or LOCAL_CONFIG_FILE instead
|
||||||
|
|
||||||
# define the V.R.F (version/release/fix)
|
# define the V.R.F (version/release/fix)
|
||||||
MY_VRF="1.4.0"
|
MY_VRF="1.5.0"
|
||||||
# name of the global configuration file (script)
|
# name of the global configuration file (script)
|
||||||
GLOBAL_CONFIG_FILE="manage_ssh.conf"
|
GLOBAL_CONFIG_FILE="manage_ssh.conf"
|
||||||
# name of the local configuration file (script)
|
# name of the local configuration file (script)
|
||||||
@ -79,11 +85,13 @@ PATH=${PATH}:/usr/bin:/usr/local/bin
|
|||||||
SCRIPT_NAME=$(basename $0)
|
SCRIPT_NAME=$(basename $0)
|
||||||
SCRIPT_DIR=$(dirname $0)
|
SCRIPT_DIR=$(dirname $0)
|
||||||
OS_NAME="$(uname)"
|
OS_NAME="$(uname)"
|
||||||
|
HOST_NAME="$(hostname)"
|
||||||
KEYS_FILE=""
|
KEYS_FILE=""
|
||||||
KEYS_DIR=""
|
KEYS_DIR=""
|
||||||
TARGETS_FILE=""
|
TARGETS_FILE=""
|
||||||
FIX_CREATE=0
|
FIX_CREATE=0
|
||||||
CAN_DISCOVER_KEYS=0
|
CAN_DISCOVER_KEYS=0
|
||||||
|
CAN_START_AGENT=1
|
||||||
KEY_COUNT=0
|
KEY_COUNT=0
|
||||||
KEY_1024_COUNT=0
|
KEY_1024_COUNT=0
|
||||||
KEY_2048_COUNT=0
|
KEY_2048_COUNT=0
|
||||||
@ -154,6 +162,18 @@ then
|
|||||||
print -u2 "ERROR: no value for the SSH_KEYSCAN_BIN setting in the configuration file"
|
print -u2 "ERROR: no value for the SSH_KEYSCAN_BIN setting in the configuration file"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
# DO_SSH_AGENT
|
||||||
|
if [[ -z "${DO_SSH_AGENT}" ]]
|
||||||
|
then
|
||||||
|
print -u2 "ERROR:no value for the DO_SSH_AGENT setting in the configuration file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# DO_SSH_SLAVE_AGENT
|
||||||
|
if [[ -z "${DO_SSH_SLAVE_AGENT}" ]]
|
||||||
|
then
|
||||||
|
print -u2 "ERROR:no value for the DO_SSH_SLAVE_AGENT setting in the configuration file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
# MAX_BACKGROUND_PROCS
|
# MAX_BACKGROUND_PROCS
|
||||||
if [[ -z "${MAX_BACKGROUND_PROCS}" ]]
|
if [[ -z "${MAX_BACKGROUND_PROCS}" ]]
|
||||||
then
|
then
|
||||||
@ -240,6 +260,15 @@ then
|
|||||||
REMOTE_DIR="${ARG_REMOTE_DIR}"
|
REMOTE_DIR="${ARG_REMOTE_DIR}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
# --slave
|
||||||
|
if (( DO_SLAVE ))
|
||||||
|
then
|
||||||
|
# requires a list of targets (=slave servers)
|
||||||
|
[[ -n "${ARG_TARGETS}" ]] || {
|
||||||
|
print -u2 "ERROR: you must specify a list of targets with the --slave option"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
# --targets
|
# --targets
|
||||||
if [[ -n "${ARG_TARGETS}" ]]
|
if [[ -n "${ARG_TARGETS}" ]]
|
||||||
then
|
then
|
||||||
@ -296,13 +325,12 @@ then
|
|||||||
if [[ -z "${ARG_TARGETS}" ]]
|
if [[ -z "${ARG_TARGETS}" ]]
|
||||||
then
|
then
|
||||||
TARGETS_FILE="${LOCAL_DIR}/targets"
|
TARGETS_FILE="${LOCAL_DIR}/targets"
|
||||||
if [ \( ! -r "${TARGETS_FILE}" \) -a \( ! -r "/var/tmp/targets.${USER}" \) ]
|
if [[ ! -r "${TARGETS_FILE}" ]]
|
||||||
then
|
then
|
||||||
print -u2 "ERROR: cannot read file ${TARGETS_FILE} nor /var/tmp/targets.${USER}"
|
print -u2 "ERROR: cannot read file ${TARGETS_FILE}"
|
||||||
|
print -u2 "ERROR: possibly this is not a master or slave server"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
# override default targets file
|
|
||||||
[[ -r "/var/tmp/targets.${USER}" ]] && TARGETS_FILE="/var/tmp/targets.${USER}"
|
|
||||||
else
|
else
|
||||||
TARGETS_FILE=${TMP_FILE}
|
TARGETS_FILE=${TMP_FILE}
|
||||||
fi
|
fi
|
||||||
@ -353,6 +381,23 @@ then
|
|||||||
print -u2 "WARN: 'ssh-keyscan' tool not found, host key discovery is not possible"
|
print -u2 "WARN: 'ssh-keyscan' tool not found, host key discovery is not possible"
|
||||||
CAN_DISCOVER_KEYS=0
|
CAN_DISCOVER_KEYS=0
|
||||||
fi
|
fi
|
||||||
|
# check for SSH agent pre-requisites
|
||||||
|
if (( DO_SSH_AGENT || DO_SSH_SLAVE_AGENT ))
|
||||||
|
then
|
||||||
|
# ssh-agent
|
||||||
|
which ssh-agent 2>/dev/null
|
||||||
|
if (( $? ))
|
||||||
|
then
|
||||||
|
print -u2 "WARN: ssh-agent not available on ${HOST_NAME}"
|
||||||
|
CAN_START_AGENT=0
|
||||||
|
fi
|
||||||
|
# private key
|
||||||
|
if [[ ! -r "${SSH_PRIVATE_KEY}" ]]
|
||||||
|
then
|
||||||
|
print -u2 "WARN: SSH private key not found ${SSH_PRIVATE_KEY}, ssh-agent disabled"
|
||||||
|
CAN_START_AGENT=0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -465,21 +510,21 @@ Performs basic functions for SSH controls: update SSH keys locally or
|
|||||||
remote, create SSH key fingerprints or copy/distribute the SSH controls files
|
remote, create SSH key fingerprints or copy/distribute the SSH controls files
|
||||||
|
|
||||||
Syntax: ${SCRIPT_DIR}/${SCRIPT_NAME} [--help] | (--backup | --check-syntax | --preview-global | --make-finger | --update ) |
|
Syntax: ${SCRIPT_DIR}/${SCRIPT_NAME} [--help] | (--backup | --check-syntax | --preview-global | --make-finger | --update ) |
|
||||||
(--apply [--remote-dir=<remote_directory>] [--targets=<host1>,<host2>,...]) |
|
(--apply [--slave] [--remote-dir=<remote_directory>] [--targets=<host1>,<host2>,...]) |
|
||||||
((--copy|--distribute) [--remote-dir=<remote_directory> [--targets=<host1>,<host2>,...]]) |
|
((--copy|--distribute) [--slave] [--remote-dir=<remote_directory> [--targets=<host1>,<host2>,...]]) |
|
||||||
(--discover [--targets=<host1>,<host2>,...]) |
|
(--discover [--targets=<host1>,<host2>,...]) |
|
||||||
([--fix-local --fix-dir=<repository_dir> [--create-dir]] | [--fix-remote [--create-dir] [--targets=<host1>,<host2>,...]])
|
([--fix-local --fix-dir=<repository_dir> [--create-dir]] | [--fix-remote [--slave] [--create-dir] [--targets=<host1>,<host2>,...]])
|
||||||
[--local-dir=<local_directory>] [--no-log] [--log-dir=<log_directory>] [--debug]
|
[--local-dir=<local_directory>] [--no-log] [--log-dir=<log_directory>] [--debug]
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
|
|
||||||
--apply|-a : apply SSH controls remotely (~targets)
|
--apply|-a : apply SSH controls remotely (~targets)
|
||||||
--backup|-b : create a backup of the SSH controls repository (SSH master)
|
--backup|-b : create a backup of the SSH controls repository (SSH master)
|
||||||
--create-dir : also create missing directories when fixing the SSH controls
|
|
||||||
repository (see also --fix-local/--fix-remote)
|
|
||||||
--check-syntax|-s : do basic syntax checking on SSH controls configuration
|
--check-syntax|-s : do basic syntax checking on SSH controls configuration
|
||||||
(access, alias & keys files)
|
(access, alias & keys files)
|
||||||
--copy|-c : copy SSH control files to remote host (~targets)
|
--copy|-c : copy SSH control files to remote host (~targets)
|
||||||
|
--create-dir : also create missing directories when fixing the SSH controls
|
||||||
|
repository (see also --fix-local/--fix-remote)
|
||||||
--debug : print extra status messages on STDERR
|
--debug : print extra status messages on STDERR
|
||||||
--discover|-d : discover SSH host keys (STDOUT)
|
--discover|-d : discover SSH host keys (STDOUT)
|
||||||
--distribute : same as --copy
|
--distribute : same as --copy
|
||||||
@ -489,24 +534,25 @@ Parameters:
|
|||||||
--fix-remote : fix permissions on the remote SSH controls repository
|
--fix-remote : fix permissions on the remote SSH controls repository
|
||||||
--help|-h : this help text
|
--help|-h : this help text
|
||||||
--local-dir : location of the SSH control files on the local filesystem.
|
--local-dir : location of the SSH control files on the local filesystem.
|
||||||
[default: ${LOCAL_DIR}]
|
[default: see LOCAL_DIR setting]
|
||||||
--log-dir : specify a log directory location.
|
--log-dir : specify a log directory location.
|
||||||
--no-log : do not log any messages to the script log file.
|
--no-log : do not log any messages to the script log file.
|
||||||
--make-finger|-m : create (local) key fingerprints file
|
--make-finger|-m : create (local) key fingerprints file
|
||||||
--preview-global|-p : dump the global access namespace (after alias resolution)
|
--preview-global|-p : dump the global access namespace (after alias resolution)
|
||||||
--remote-dir : directory where SSH control files are/should be
|
--remote-dir : directory where SSH control files are/should be
|
||||||
located/copied on/to the target host
|
located/copied on/to the target host
|
||||||
[default: ${REMOTE_DIR}]
|
[default: see REMOTE_DIR setting]
|
||||||
|
--slave : perform actions in master->slave mode
|
||||||
--targets : comma-separated list of target hosts to operate on. Override the
|
--targets : comma-separated list of target hosts to operate on. Override the
|
||||||
hosts contained in the 'targets' configuration file.
|
hosts contained in the 'targets' configuration file.
|
||||||
--update|-u : apply SSH controls locally
|
--update|-u : apply SSH controls locally
|
||||||
|
|
||||||
--version|-V : show the script version/release/fix
|
--version|-V : show the script version/release/fix
|
||||||
|
|
||||||
Note 1: distribute and update actions are run in parallel across a maximum of
|
Note 1: copy and apply actions are run in parallel across a maximum of clients
|
||||||
${MAX_BACKGROUND_PROCS} clients at the same time.
|
at the same time [default: see MAX_BACKGROUND_PROCS setting]
|
||||||
|
|
||||||
Note 2: for fix and update actions: make sure correct 'sudo' rules are setup
|
Note 2: for fix and apply actions: make sure correct 'sudo' rules are setup
|
||||||
on the target systems to allow the SSH controls script to run with
|
on the target systems to allow the SSH controls script to run with
|
||||||
elevated privileges.
|
elevated privileges.
|
||||||
|
|
||||||
@ -585,7 +631,7 @@ else
|
|||||||
log "transferred ${KEYS_FILE} to ${SERVER}:${REMOTE_DIR}"
|
log "transferred ${KEYS_FILE} to ${SERVER}:${REMOTE_DIR}"
|
||||||
else
|
else
|
||||||
warn "failed to transfer ${KEYS_FILE} to ${SERVER}:${REMOTE_DIR} [RC=${COPY_RC}]"
|
warn "failed to transfer ${KEYS_FILE} to ${SERVER}:${REMOTE_DIR} [RC=${COPY_RC}]"
|
||||||
ERROR_COUNT = $(( ERROR_COUNT + 1 ))
|
ERROR_COUNT=$(( ERROR_COUNT + 1 ))
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
# discover a keys blacklist file, also copy it across if we find one
|
# discover a keys blacklist file, also copy it across if we find one
|
||||||
@ -605,7 +651,7 @@ then
|
|||||||
log "transferred ${BLACKLIST_FILE} to ${SERVER}:${REMOTE_DIR}"
|
log "transferred ${BLACKLIST_FILE} to ${SERVER}:${REMOTE_DIR}"
|
||||||
else
|
else
|
||||||
warn "failed to transfer ${BLACKLIST_FILE%!*} to ${SERVER}:${REMOTE_DIR} [RC=${COPY_RC}]"
|
warn "failed to transfer ${BLACKLIST_FILE%!*} to ${SERVER}:${REMOTE_DIR} [RC=${COPY_RC}]"
|
||||||
ERROR_COUNT = $(( ERROR_COUNT + 1 ))
|
ERROR_COUNT=$(( ERROR_COUNT + 1 ))
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -613,6 +659,33 @@ fi
|
|||||||
return ${ERROR_COUNT}
|
return ${ERROR_COUNT}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# distribute SSH controls to a single host in slave mode
|
||||||
|
function distribute2slave
|
||||||
|
{
|
||||||
|
SERVER="$1"
|
||||||
|
|
||||||
|
# convert line to hostname
|
||||||
|
SERVER=${SERVER%%;*}
|
||||||
|
resolve_host ${SERVER}
|
||||||
|
if (( $? ))
|
||||||
|
then
|
||||||
|
warn "could not lookup host ${SERVER}, skipping"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "copying SSH controls on ${SERVER} in slave mode, this may take a while ..."
|
||||||
|
( RC=0; ssh -A ${SSH_ARGS} ${SERVER} ${REMOTE_DIR}/${SCRIPT_NAME} --copy;
|
||||||
|
print "$?" > ${TMP_RC_FILE}; exit
|
||||||
|
) 2>&1 | logc
|
||||||
|
|
||||||
|
# fetch return code from subshell
|
||||||
|
RC="$(< ${TMP_RC_FILE})"
|
||||||
|
|
||||||
|
return ${RC}
|
||||||
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
function do_cleanup
|
function do_cleanup
|
||||||
{
|
{
|
||||||
@ -622,7 +695,7 @@ log "performing cleanup ..."
|
|||||||
[[ -f ${TMP_FILE} ]] && rm -f ${TMP_FILE} >/dev/null 2>&1
|
[[ -f ${TMP_FILE} ]] && rm -f ${TMP_FILE} >/dev/null 2>&1
|
||||||
[[ -f ${TMP_MERGE_FILE} ]] && rm -f ${TMP_MERGE_FILE} >/dev/null 2>&1
|
[[ -f ${TMP_MERGE_FILE} ]] && rm -f ${TMP_MERGE_FILE} >/dev/null 2>&1
|
||||||
[[ -f ${TMP_RC_FILE} ]] && rm -f ${TMP_RC_FILE} >/dev/null 2>&1
|
[[ -f ${TMP_RC_FILE} ]] && rm -f ${TMP_RC_FILE} >/dev/null 2>&1
|
||||||
log "*** finish of ${SCRIPT_NAME} [${CMD_LINE}] ***"
|
log "*** finish of ${SCRIPT_NAME} [${CMD_LINE}] /$$@${HOST_NAME}/ ***"
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -643,7 +716,7 @@ then
|
|||||||
warn "could not lookup host ${SERVER}, skipping"
|
warn "could not lookup host ${SERVER}, skipping"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
log "fixing ssh controls on ${SERVER} ..."
|
log "fixing SSH controls on ${SERVER} ..."
|
||||||
if [[ -z "${SSH_UPDATE_USER}" ]]
|
if [[ -z "${SSH_UPDATE_USER}" ]]
|
||||||
then
|
then
|
||||||
# own user w/ sudo
|
# own user w/ sudo
|
||||||
@ -669,14 +742,52 @@ RC="$(< ${TMP_RC_FILE})"
|
|||||||
return ${RC}
|
return ${RC}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# fix SSH controls on a single host/client in slave mode (permissions/ownerships)
|
||||||
|
# !! requires appropriate 'sudo' rules on remote client for privilege elevation
|
||||||
|
function fix2slave
|
||||||
|
{
|
||||||
|
SERVER="$1"
|
||||||
|
SERVER_DIR="$2"
|
||||||
|
|
||||||
|
# convert line to hostname
|
||||||
|
SERVER=${SERVER%%;*}
|
||||||
|
resolve_host ${SERVER}
|
||||||
|
if (( $? ))
|
||||||
|
then
|
||||||
|
warn "could not lookup host ${SERVER}, skipping"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "fixing SSH controls on ${SERVER} in slave mode, this may take a while ..."
|
||||||
|
( RC=0; ssh -A ${SSH_ARGS} ${SERVER} ${REMOTE_DIR}/${SCRIPT_NAME} --fix-remote --fix-dir=${SERVER_DIR};
|
||||||
|
print "$?" > ${TMP_RC_FILE}; exit
|
||||||
|
) 2>&1 | logc
|
||||||
|
|
||||||
|
# fetch return code from subshell
|
||||||
|
RC="$(< ${TMP_RC_FILE})"
|
||||||
|
|
||||||
|
return ${RC}
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
function get_linux_name
|
||||||
|
{
|
||||||
|
LSB_NAME="$(lsb_release -is 2>/dev/null | cut -f2 -d':')"
|
||||||
|
|
||||||
|
print "${LSB_NAME}"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
function get_linux_version
|
function get_linux_version
|
||||||
{
|
{
|
||||||
LSB_VERSION=$(lsb_release -rs 2>/dev/null | cut -f1 -d'.')
|
LSB_VERSION="$(lsb_release -rs 2>/dev/null | cut -f1 -d'.')"
|
||||||
|
|
||||||
if [[ -z "${LSB_VERSION}" ]]
|
if [[ -z "${LSB_VERSION}" ]]
|
||||||
then
|
then
|
||||||
RELEASE_STRING=$(/bin/grep -i 'release' /etc/redhat-release 2>/dev/null)
|
RELEASE_STRING="$(grep -i 'release' /etc/redhat-release 2>/dev/null)"
|
||||||
|
|
||||||
case "${RELEASE_STRING}" in
|
case "${RELEASE_STRING}" in
|
||||||
*release\ 5*)
|
*release\ 5*)
|
||||||
@ -696,8 +807,9 @@ then
|
|||||||
else
|
else
|
||||||
print "${LSB_VERSION}"
|
print "${LSB_VERSION}"
|
||||||
fi
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# log an INFO: message (via ARG).
|
# log an INFO: message (via ARG).
|
||||||
@ -901,6 +1013,78 @@ cd ${OLD_PWD}
|
|||||||
return ${SFTP_RC}
|
return ${SFTP_RC}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# start a SSH agent
|
||||||
|
function start_ssh_agent
|
||||||
|
{
|
||||||
|
log "requested to start an SSH agent on ${HOST_NAME} ..."
|
||||||
|
|
||||||
|
# is there one still running, then we re-use it
|
||||||
|
if [[ -n "${SSH_AGENT_PID}" ]]
|
||||||
|
then
|
||||||
|
log "SSH agent already running on ${HOST_NAME} with PID: ${SSH_AGENT_PID}"
|
||||||
|
else
|
||||||
|
# start the SSH agent
|
||||||
|
eval $(ssh-agent) >/dev/null 2>/dev/null
|
||||||
|
|
||||||
|
if [[ -z "${SSH_AGENT_PID}" ]]
|
||||||
|
then
|
||||||
|
warn "unable to start SSH agent on ${HOST_NAME}"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
log "SSH agent started on ${HOST_NAME}:"
|
||||||
|
log "$(ps -fp ${SSH_AGENT_PID})"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# add the private key
|
||||||
|
log "adding private key ${SSH_PRIVATE_KEY} to SSH agent on ${HOST_NAME} ..."
|
||||||
|
log "$(ssh-add ${SSH_PRIVATE_KEY} 2>&1)"
|
||||||
|
if (( $? ))
|
||||||
|
then
|
||||||
|
warn "unable to add SSH private key to SSH agent on ${HOST_NAME}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
function stop_ssh_agent
|
||||||
|
{
|
||||||
|
# stop the SSH agent
|
||||||
|
log "stopping SSH agent (if needed) on ${HOST_NAME} ..."
|
||||||
|
|
||||||
|
if [[ -n "${SSH_AGENT_PID}" ]]
|
||||||
|
then
|
||||||
|
# SIGTERM
|
||||||
|
log "stopping (TERM) process on ${HOST_NAME} with PID: ${SSH_AGENT_PID}"
|
||||||
|
log "$(ps -fp ${SSH_AGENT_PID})"
|
||||||
|
kill -s TERM ${SSH_AGENT_PID}
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
# SIGKILL
|
||||||
|
if (( $(pgrep -u "${USER}" ssh-agent | grep -c "${SSH_AGENT_PID}") ))
|
||||||
|
then
|
||||||
|
log "stopping (KILL) process on ${HOST_NAME} with PID: ${SSH_AGENT_PID}"
|
||||||
|
log "$(ps -fp ${SSH_AGENT_PID})"
|
||||||
|
kill -s kill ${SSH_AGENT_PID}
|
||||||
|
fi
|
||||||
|
sleep 3
|
||||||
|
else
|
||||||
|
log "no SSH agent running on ${HOST_NAME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# process check
|
||||||
|
if (( $(pgrep -u "${USER}" ssh-agent | grep -c "${SSH_AGENT_PID}") ))
|
||||||
|
then
|
||||||
|
warn "unable to stop running SSH agent on ${HOST_NAME} [PID=${SSH_AGENT_PID}]"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# update SSH controls on a single host/client
|
# update SSH controls on a single host/client
|
||||||
# !! requires appropriate 'sudo' rules on remote client for privilege elevation
|
# !! requires appropriate 'sudo' rules on remote client for privilege elevation
|
||||||
@ -942,6 +1126,32 @@ RC="$(< ${TMP_RC_FILE})"
|
|||||||
return ${RC}
|
return ${RC}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# update SSH controls on a single host/client in slave mode
|
||||||
|
function update2slave
|
||||||
|
{
|
||||||
|
SERVER="$1"
|
||||||
|
|
||||||
|
# convert line to hostname
|
||||||
|
SERVER=${SERVER%%;*}
|
||||||
|
resolve_host ${SERVER}
|
||||||
|
if (( $? ))
|
||||||
|
then
|
||||||
|
warn "could not lookup host ${SERVER}, skipping"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "applying ssh controls on ${SERVER} in slave mode, this may take a while ..."
|
||||||
|
( RC=0; ssh -A ${SSH_ARGS} ${SERVER} ${REMOTE_DIR}/${SCRIPT_NAME} --apply;
|
||||||
|
print "$?" > ${TMP_RC_FILE}; exit
|
||||||
|
) 2>&1 | logc
|
||||||
|
|
||||||
|
# fetch return code from subshell
|
||||||
|
RC="$(< ${TMP_RC_FILE})"
|
||||||
|
|
||||||
|
return ${RC}
|
||||||
|
}
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# update the 'fingerprints' file (must exist beforehand)
|
# update the 'fingerprints' file (must exist beforehand)
|
||||||
function update_fingerprints
|
function update_fingerprints
|
||||||
@ -1138,9 +1348,6 @@ do
|
|||||||
}
|
}
|
||||||
ARG_ACTION=7
|
ARG_ACTION=7
|
||||||
;;
|
;;
|
||||||
-s|--check-syntax|-check-syntax)
|
|
||||||
ARG_ACTION=8
|
|
||||||
;;
|
|
||||||
-fix-local|--fix-local)
|
-fix-local|--fix-local)
|
||||||
(( ARG_ACTION )) && {
|
(( ARG_ACTION )) && {
|
||||||
print -u2 "ERROR: multiple actions specified"
|
print -u2 "ERROR: multiple actions specified"
|
||||||
@ -1155,12 +1362,12 @@ do
|
|||||||
}
|
}
|
||||||
ARG_ACTION=6
|
ARG_ACTION=6
|
||||||
;;
|
;;
|
||||||
-m|-make-finger|--make-finger)
|
-s|-check-syntax|--check-syntax)
|
||||||
(( ARG_ACTION )) && {
|
(( ARG_ACTION )) && {
|
||||||
print -u2 "ERROR: multiple actions specified"
|
print -u2 "ERROR: multiple actions specified"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
ARG_ACTION=3
|
ARG_ACTION=8
|
||||||
;;
|
;;
|
||||||
-u|-update|--update)
|
-u|-update|--update)
|
||||||
(( ARG_ACTION )) && {
|
(( ARG_ACTION )) && {
|
||||||
@ -1199,6 +1406,9 @@ do
|
|||||||
--remote-dir=*)
|
--remote-dir=*)
|
||||||
ARG_REMOTE_DIR="${PARAMETER#--remote-dir=}"
|
ARG_REMOTE_DIR="${PARAMETER#--remote-dir=}"
|
||||||
;;
|
;;
|
||||||
|
-slave|--slave)
|
||||||
|
DO_SLAVE=1
|
||||||
|
;;
|
||||||
-targets=*)
|
-targets=*)
|
||||||
ARG_TARGETS="${PARAMETER#-targets=}"
|
ARG_TARGETS="${PARAMETER#-targets=}"
|
||||||
;;
|
;;
|
||||||
@ -1237,15 +1447,32 @@ check_params && check_config && check_setup && check_logging
|
|||||||
# catch shell signals
|
# catch shell signals
|
||||||
trap 'do_cleanup; exit' 1 2 3 15
|
trap 'do_cleanup; exit' 1 2 3 15
|
||||||
|
|
||||||
log "*** start of ${SCRIPT_NAME} [${CMD_LINE}] ***"
|
log "*** start of ${SCRIPT_NAME} [${CMD_LINE}] /$$@${HOST_NAME}/ ***"
|
||||||
(( ARG_LOG )) && log "logging takes places in ${LOG_FILE}"
|
(( ARG_LOG )) && log "logging takes places in ${LOG_FILE}"
|
||||||
|
|
||||||
log "runtime info: LOCAL_DIR is set to: ${LOCAL_DIR}"
|
log "runtime info: LOCAL_DIR is set to: ${LOCAL_DIR}"
|
||||||
|
|
||||||
case ${ARG_ACTION} in
|
case ${ARG_ACTION} in
|
||||||
1) # apply SSH controls remotely
|
1) # apply SUDO controls remotely
|
||||||
log "ACTION: apply SSH controls remotely"
|
log "ACTION: apply SSH controls remotely"
|
||||||
check_root_user && die "must NOT be run as user 'root'"
|
check_root_user && die "must NOT be run as user 'root'"
|
||||||
|
# start SSH agent (if needed)
|
||||||
|
if (( DO_SSH_AGENT && CAN_START_AGENT ))
|
||||||
|
then
|
||||||
|
start_ssh_agent
|
||||||
|
if (( $? ))
|
||||||
|
then
|
||||||
|
die "problem with launching an SSH agent, bailing out"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if (( DO_SLAVE && DO_SSH_SLAVE_AGENT && CAN_START_AGENT ))
|
||||||
|
then
|
||||||
|
start_ssh_agent
|
||||||
|
if (( $? ))
|
||||||
|
then
|
||||||
|
die "problem with launching an SSH agent, bailing out"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
# build clients list (in array)
|
# build clients list (in array)
|
||||||
cat "${TARGETS_FILE}" | grep -v -E -e '^#' -e '^$' |\
|
cat "${TARGETS_FILE}" | grep -v -E -e '^#' -e '^$' |\
|
||||||
{
|
{
|
||||||
@ -1261,7 +1488,12 @@ case ${ARG_ACTION} in
|
|||||||
COUNT=${MAX_BACKGROUND_PROCS}
|
COUNT=${MAX_BACKGROUND_PROCS}
|
||||||
for CLIENT in ${CLIENTS[@]}
|
for CLIENT in ${CLIENTS[@]}
|
||||||
do
|
do
|
||||||
|
if (( DO_SLAVE ))
|
||||||
|
then
|
||||||
|
update2slave ${CLIENT} &
|
||||||
|
else
|
||||||
update2host ${CLIENT} &
|
update2host ${CLIENT} &
|
||||||
|
fi
|
||||||
PID=$!
|
PID=$!
|
||||||
log "updating ${CLIENT} in background [PID=${PID}] ..."
|
log "updating ${CLIENT} in background [PID=${PID}] ..."
|
||||||
# add PID to list of all child PIDs
|
# add PID to list of all child PIDs
|
||||||
@ -1280,12 +1512,31 @@ case ${ARG_ACTION} in
|
|||||||
# final wait for background processes to be finished completely
|
# final wait for background processes to be finished completely
|
||||||
wait_for_children ${PIDS} || \
|
wait_for_children ${PIDS} || \
|
||||||
warn "$? background jobs (possibly) failed to complete correctly"
|
warn "$? background jobs (possibly) failed to complete correctly"
|
||||||
|
# stop SSH agent if needed
|
||||||
|
(( ( DO_SSH_AGENT || ( DO_SLAVE && DO_SSH_SLAVE_AGENT )) && CAN_START_AGENT )) && \
|
||||||
|
stop_ssh_agent
|
||||||
log "finished applying SSH controls remotely"
|
log "finished applying SSH controls remotely"
|
||||||
;;
|
;;
|
||||||
2) # copy/distribute SSH controls
|
2) # copy/distribute SSH controls
|
||||||
log "ACTION: copy/distribute SSH controls"
|
log "ACTION: copy/distribute SSH controls"
|
||||||
check_root_user && die "must NOT be run as user 'root'"
|
check_root_user && die "must NOT be run as user 'root'"
|
||||||
|
# start SSH agent (if needed)
|
||||||
|
if (( DO_SSH_AGENT && CAN_START_AGENT ))
|
||||||
|
then
|
||||||
|
start_ssh_agent
|
||||||
|
if (( $? ))
|
||||||
|
then
|
||||||
|
die "problem with launching an SSH agent, bailing out"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if (( DO_SLAVE && DO_SSH_SLAVE_AGENT && CAN_START_AGENT ))
|
||||||
|
then
|
||||||
|
start_ssh_agent
|
||||||
|
if (( $? ))
|
||||||
|
then
|
||||||
|
die "problem with launching an SSH agent, bailing out"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
# build clients list (in array)
|
# build clients list (in array)
|
||||||
cat "${TARGETS_FILE}" | grep -v -E -e '^#' -e '^$' |\
|
cat "${TARGETS_FILE}" | grep -v -E -e '^#' -e '^$' |\
|
||||||
{
|
{
|
||||||
@ -1301,7 +1552,12 @@ case ${ARG_ACTION} in
|
|||||||
COUNT=${MAX_BACKGROUND_PROCS}
|
COUNT=${MAX_BACKGROUND_PROCS}
|
||||||
for CLIENT in ${CLIENTS[@]}
|
for CLIENT in ${CLIENTS[@]}
|
||||||
do
|
do
|
||||||
|
if (( DO_SLAVE ))
|
||||||
|
then
|
||||||
|
distribute2slave ${CLIENT} &
|
||||||
|
else
|
||||||
distribute2host ${CLIENT} &
|
distribute2host ${CLIENT} &
|
||||||
|
fi
|
||||||
PID=$!
|
PID=$!
|
||||||
log "copying/distributing to ${CLIENT} in background [PID=${PID}] ..."
|
log "copying/distributing to ${CLIENT} in background [PID=${PID}] ..."
|
||||||
# add PID to list of all child PIDs
|
# add PID to list of all child PIDs
|
||||||
@ -1320,6 +1576,9 @@ case ${ARG_ACTION} in
|
|||||||
# final wait for background processes to be finished completely
|
# final wait for background processes to be finished completely
|
||||||
wait_for_children ${PIDS} || \
|
wait_for_children ${PIDS} || \
|
||||||
warn "$? background jobs (possibly) failed to complete correctly"
|
warn "$? background jobs (possibly) failed to complete correctly"
|
||||||
|
# stop SSH agent if needed
|
||||||
|
(( ( DO_SSH_AGENT || ( DO_SLAVE && DO_SSH_SLAVE_AGENT )) && CAN_START_AGENT )) && \
|
||||||
|
stop_ssh_agent
|
||||||
log "finished copying/distributing SSH controls"
|
log "finished copying/distributing SSH controls"
|
||||||
;;
|
;;
|
||||||
3) # create key fingerprints
|
3) # create key fingerprints
|
||||||
@ -1423,9 +1682,12 @@ case ${ARG_ACTION} in
|
|||||||
# check for SELinux labels
|
# check for SELinux labels
|
||||||
case ${OS_NAME} in
|
case ${OS_NAME} in
|
||||||
*Linux*)
|
*Linux*)
|
||||||
case "$(getenforce)" in
|
LINUX_NAME="$(get_linux_name)"
|
||||||
|
LINUX_VERSION="$(get_linux_version)"
|
||||||
|
case ${LINUX_NAME} in
|
||||||
|
*Centos*|*RHEL*)
|
||||||
|
case "$(getenforce 2>/dev/null)" in
|
||||||
*Permissive*|*Enforcing*)
|
*Permissive*|*Enforcing*)
|
||||||
LINUX_VERSION=$(get_linux_version)
|
|
||||||
case "${LINUX_VERSION}" in
|
case "${LINUX_VERSION}" in
|
||||||
5)
|
5)
|
||||||
chcon -R -t sshd_key_t "${FIX_DIR}/keys.d"
|
chcon -R -t sshd_key_t "${FIX_DIR}/keys.d"
|
||||||
@ -1443,6 +1705,8 @@ case ${ARG_ACTION} in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
:
|
:
|
||||||
;;
|
;;
|
||||||
@ -1455,6 +1719,23 @@ case ${ARG_ACTION} in
|
|||||||
6) # fix remote directory structure/perms/ownerships
|
6) # fix remote directory structure/perms/ownerships
|
||||||
log "ACTION: fix remote SSH controls repository"
|
log "ACTION: fix remote SSH controls repository"
|
||||||
check_root_user && die "must NOT be run as user 'root'"
|
check_root_user && die "must NOT be run as user 'root'"
|
||||||
|
# start SSH agent (if needed)
|
||||||
|
if (( DO_SSH_AGENT && CAN_START_AGENT ))
|
||||||
|
then
|
||||||
|
start_ssh_agent
|
||||||
|
if (( $? ))
|
||||||
|
then
|
||||||
|
die "problem with launching an SSH agent, bailing out"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if (( DO_SLAVE && DO_SSH_SLAVE_AGENT && CAN_START_AGENT ))
|
||||||
|
then
|
||||||
|
start_ssh_agent
|
||||||
|
if (( $? ))
|
||||||
|
then
|
||||||
|
die "problem with launching an SSH agent, bailing out"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
# derive SSH controls repo from $REMOTE_DIR:
|
# derive SSH controls repo from $REMOTE_DIR:
|
||||||
# /etc/ssh_controls/holding -> /etc/ssh_controls
|
# /etc/ssh_controls/holding -> /etc/ssh_controls
|
||||||
FIX_DIR="$(print ${REMOTE_DIR%/*})"
|
FIX_DIR="$(print ${REMOTE_DIR%/*})"
|
||||||
@ -1475,9 +1756,14 @@ case ${ARG_ACTION} in
|
|||||||
COUNT=${MAX_BACKGROUND_PROCS}
|
COUNT=${MAX_BACKGROUND_PROCS}
|
||||||
for CLIENT in ${CLIENTS[@]}
|
for CLIENT in ${CLIENTS[@]}
|
||||||
do
|
do
|
||||||
|
if (( DO_SLAVE ))
|
||||||
|
then
|
||||||
|
fix2slave ${CLIENT} "${FIX_DIR}" &
|
||||||
|
else
|
||||||
fix2host ${CLIENT} "${FIX_DIR}" &
|
fix2host ${CLIENT} "${FIX_DIR}" &
|
||||||
|
fi
|
||||||
PID=$!
|
PID=$!
|
||||||
log "copying/distributing to ${CLIENT} in background [PID=${PID}] ..."
|
log "fixing SSH controls on ${CLIENT} in background [PID=${PID}] ..."
|
||||||
# add PID to list of all child PIDs
|
# add PID to list of all child PIDs
|
||||||
PIDS="${PIDS} ${PID}"
|
PIDS="${PIDS} ${PID}"
|
||||||
COUNT=$(( COUNT - 1 ))
|
COUNT=$(( COUNT - 1 ))
|
||||||
@ -1494,6 +1780,9 @@ case ${ARG_ACTION} in
|
|||||||
# final wait for background processes to be finished completely
|
# final wait for background processes to be finished completely
|
||||||
wait_for_children ${PIDS} || \
|
wait_for_children ${PIDS} || \
|
||||||
warn "$? background jobs (possibly) failed to complete correctly"
|
warn "$? background jobs (possibly) failed to complete correctly"
|
||||||
|
# stop SSH agent if needed
|
||||||
|
(( ( DO_SSH_AGENT || ( DO_SLAVE && DO_SSH_SLAVE_AGENT )) && CAN_START_AGENT )) && \
|
||||||
|
stop_ssh_agent
|
||||||
log "finished applying fixes to the remote SSH control repository"
|
log "finished applying fixes to the remote SSH control repository"
|
||||||
;;
|
;;
|
||||||
7) # dump the configuration namespace
|
7) # dump the configuration namespace
|
||||||
|
Loading…
x
Reference in New Issue
Block a user