manage_ssh.sh: moved essential configuration items of the script into a separate configuration file (global/local), fix in wait_for_children (VRF 1.2.0) [Patrick Van der Veken]

update_ssh.pl: VRF 1.1.0: replace uname/hostname syscalls, now support for FQDN via $use_fqdn, other fixes [Patrick Van der Veken]
This commit is contained in:
patvdv 2015-08-15 21:58:04 +02:00
parent 9ce94e58d8
commit c927fe8f1f
4 changed files with 123 additions and 57 deletions

49
manage_ssh.conf Normal file
View File

@ -0,0 +1,49 @@
#******************************************************************************
# manage_ssh.sh configuration file
#******************************************************************************
#
# Lines starting with '#' (hash) are comment lines
#
# Format: option=<value>
#
# Use double or single quotes around the option values in case of strings.
#
# name of the user account performing the SSH controls copies
# (leave blank for current user)
SSH_TRANSFER_USER=""
# name of the OS group that should own the SSH controls files
SSH_OWNER_GROUP="sshadmin"
# extra arguments/options for the SFTP command
SFTP_ARGS="-o StrictHostKeyChecking=no -o ConnectTimeout=10 -b - "
# extra arguments/options for the SSH command
SSH_ARGS="-o StrictHostKeyChecking=no -o ConnectTimeout=10 -n"
# location of the local SSH controls directory
LOCAL_DIR="/etc/ssh_master"
# location of the remote SSH controls directory
REMOTE_DIR="/etc/ssh_controls/holding"
# name of the user account performing the SSH controls update
# (leave blank for current user but user should have remote sudo root privs)
SSH_UPDATE_USER=""
# options to pass to manage_ssh.sh when executing a key update
SSH_UPDATE_OPTS="--verbose --remove"
# maximum number of background process to spawn (~maxuprc, ~nstrpty etc)
MAX_BACKGROUND_PROCS=30
# location of the backup directory (for configuration & key files)
BACKUP_DIR="${LOCAL_DIR}/backup"
# location of log directory (default), see --log-dir)
LOG_DIR="/var/log"
#******************************************************************************
# End of FILE
#******************************************************************************

View File

@ -20,11 +20,11 @@
# 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 or distribute the SSH controls files
# EXPECTS: (see --help for more options) # EXPECTS: (see --help for more options)
# REQUIRES: check_config(), check_logging(), check_params(), check_setup(), # REQUIRES: check_config(), check_logging(), check_params(), check_root_user(),
# check_syntax(), count_fields(), die(), display_usage(), # check_setup(), check_syntax(), count_fields(), die(), display_usage(),
# distribute2host(), do_cleanup(), fix2host(), get_linux_version(), # distribute2host(), do_cleanup(), fix2host(), get_linux_version(),
# log(), resolve_host(), sftp_file(), update2host(), # log(), resolve_host(), sftp_file(), update2host(),
# update_fingerprints(), warn() # 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:
@ -35,6 +35,9 @@
# @(#) 2015-02-03: use 'sudo -n' (VRF 1.1.2) [Patrick Van der Veken] # @(#) 2015-02-03: use 'sudo -n' (VRF 1.1.2) [Patrick Van der Veken]
# @(#) 2015-04-10: fix in --fix-local routine (VRF 1.1.3) [Patrick Van der Veken] # @(#) 2015-04-10: fix in --fix-local routine (VRF 1.1.3) [Patrick Van der Veken]
# @(#) 2015-05-16: added SSH_OWNER_GROUP (VRF 1.1.4) [Patrick Van der Veken] # @(#) 2015-05-16: added SSH_OWNER_GROUP (VRF 1.1.4) [Patrick Van der Veken]
# @(#) 2015-08-15: moved essential configuration items of the script into a
# @(#) separate configuration file (global/local), fix in
# @(#) wait_for_children (VRF 1.2.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!
#****************************************************************************** #******************************************************************************
@ -44,32 +47,15 @@
#****************************************************************************** #******************************************************************************
# ------------------------- CONFIGURATION starts here ------------------------- # ------------------------- CONFIGURATION starts here -------------------------
# Below configuration values should not be changed. Use the GLOBAL_CONFIG_FILE
# or LOCAL_CONFIG_FILE instead
# define the V.R.F (version/release/fix) # define the V.R.F (version/release/fix)
MY_VRF="1.1.4" MY_VRF="1.2.0"
# name of the user account performing the SSH controls copies # name of the global configuration file (script)
# (leave blank for current user) GLOBAL_CONFIG_FILE="manage_ssh.conf"
SSH_TRANSFER_USER="" # name of the local configuration file (script)
# name of the OS group that should own the SSH controls files LOCAL_CONFIG_FILE="manage_ssh.conf.local"
SSH_OWNER_GROUP="sshadmin"
# extra arguments/options for the SFTP command
SFTP_ARGS="-o StrictHostKeyChecking=no -o ConnectTimeout=10 -b - "
# extra arguments/options for the SSH command
SSH_ARGS="-o StrictHostKeyChecking=no -o ConnectTimeout=10 -n"
# location of the local SSH controls directory
LOCAL_DIR="/etc/ssh_master"
# location of the remote SSH controls directory
REMOTE_DIR="/etc/ssh_controls/holding"
# name of the user account performing the SSH controls update
# (leave blank for current user but user should have remote sudo root privs)
SSH_UPDATE_USER=""
# options to pass to manage_ssh.sh when executing a key update
SSH_UPDATE_OPTS="--verbose --remove"
# maximum number of background process to spawn (~maxuprc, ~nstrpty etc)
MAX_BACKGROUND_PROCS=30
# location of the backup directory (for configuration & key files)
BACKUP_DIR="${LOCAL_DIR}/backup"
# location of log directory (default), see --log-dir)
LOG_DIR="/var/log"
# location of temporary working storage # location of temporary working storage
TMP_DIR="/var/tmp" TMP_DIR="/var/tmp"
# ------------------------- CONFIGURATION ends here --------------------------- # ------------------------- CONFIGURATION ends here ---------------------------
@ -322,7 +308,8 @@ if (( ARG_ACTION == 1 || ARG_ACTION == 2 || ARG_ACTION == 4 ))
then then
for FILE in "${LOCAL_DIR}/update_ssh.pl" \ for FILE in "${LOCAL_DIR}/update_ssh.pl" \
"${LOCAL_DIR}/update_ssh.conf" \ "${LOCAL_DIR}/update_ssh.conf" \
"${SCRIPT_DIR}/${SCRIPT_NAME}" "${SCRIPT_DIR}/${SCRIPT_NAME}" \
"${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}"
do do
if [[ ! -r "${FILE}" ]] if [[ ! -r "${FILE}" ]]
then then
@ -465,6 +452,8 @@ Note 2: for fix and update 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.
Note 3: only GLOBAL configuration files will be distributed to target hosts.
EOT EOT
return 0 return 0
@ -491,7 +480,8 @@ for FILE in "${LOCAL_DIR}/access!660" \
"${LOCAL_DIR}/alias!660" \ "${LOCAL_DIR}/alias!660" \
"${LOCAL_DIR}/update_ssh.pl!770" \ "${LOCAL_DIR}/update_ssh.pl!770" \
"${LOCAL_DIR}/update_ssh.conf!660" \ "${LOCAL_DIR}/update_ssh.conf!660" \
"${SCRIPT_DIR}/${SCRIPT_NAME}!770" "${SCRIPT_DIR}/${SCRIPT_NAME}!770" \
"${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}!660"
do do
# sftp transfer # sftp transfer
sftp_file ${FILE} ${SERVER} sftp_file ${FILE} ${SERVER}
@ -518,7 +508,7 @@ then
log "keys are stored in a DIRECTORY, first merging all keys into ${TMP_MERGE_FILE}" log "keys are stored in a DIRECTORY, first merging all keys into ${TMP_MERGE_FILE}"
cat ${KEYS_DIR}/* >${TMP_MERGE_FILE} cat ${KEYS_DIR}/* >${TMP_MERGE_FILE}
# sftp transfer # sftp transfer
sftp_file "${TMP_MERGE_FILE}!440" ${SERVER} sftp_file "${TMP_MERGE_FILE}!640" ${SERVER}
COPY_RC=$? COPY_RC=$?
if (( ! COPY_RC )) if (( ! COPY_RC ))
then then
@ -528,7 +518,7 @@ then
fi fi
[[ -d ${TMP_WORK_DIR} ]] && rm -rf ${TMP_WORK_DIR} 2>/dev/null [[ -d ${TMP_WORK_DIR} ]] && rm -rf ${TMP_WORK_DIR} 2>/dev/null
else else
sftp_file "${KEYS_FILE}!440" ${SERVER} sftp_file "${KEYS_FILE}!640" ${SERVER}
COPY_RC=$? COPY_RC=$?
if (( ! COPY_RC )) if (( ! COPY_RC ))
then then
@ -703,7 +693,7 @@ OLD_PWD=$(pwd) && cd ${TRANSFER_DIR}
sftp ${SFTP_ARGS} ${SSH_TRANSFER_USER}@${TRANSFER_HOST} >/dev/null <<EOT sftp ${SFTP_ARGS} ${SSH_TRANSFER_USER}@${TRANSFER_HOST} >/dev/null <<EOT
cd ${REMOTE_DIR} cd ${REMOTE_DIR}
put ${SOURCE_FILE} put ${SOURCE_FILE}
#chmod ${TRANSFER_PERMS} ${SOURCE_FILE} chmod ${TRANSFER_PERMS} ${SOURCE_FILE}
EOT EOT
SFTP_RC=$? SFTP_RC=$?
@ -814,10 +804,10 @@ do
# the child might have already ended before we get here (caveat emptor) # the child might have already ended before we get here (caveat emptor)
elif $(wait ${PID}) elif $(wait ${PID})
then then
log "child process ${PID} exited" log "child process ${PID} exited [NOK]"
else
log "child process ${PID} exited"
WAIT_ERRORS=$(( WAIT_ERRORS + 1 )) WAIT_ERRORS=$(( WAIT_ERRORS + 1 ))
else
log "child process ${PID} exited [OK]"
fi fi
done done
# break loop if we no child PIDs left # break loop if we no child PIDs left
@ -948,6 +938,21 @@ do
esac esac
done done
# check for configuration files (local overrides local)
if [[ -r "${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}" || -r "${SCRIPT_DIR}/${LOCAL_CONFIG_FILE}" ]]
then
if [[ -r "${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}" ]]
then
. "${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}"
fi
if [[ -r "${SCRIPT_DIR}/${LOCAL_CONFIG_FILE}" ]]
then
. "${SCRIPT_DIR}/${LOCAL_CONFIG_FILE}"
fi
else
print -u2 "ERROR: could not find global or local configuration file"
fi
# startup checks # startup checks
check_params && check_config && check_setup && check_logging check_params && check_config && check_setup && check_logging
@ -988,7 +993,7 @@ case ${ARG_ACTION} in
then then
# wait until all background processes are completed # wait until all background processes are completed
wait_for_children ${PIDS} || \ wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
PIDS='' PIDS=''
# reset max updates in background # reset max updates in background
COUNT=${MAX_BACKGROUND_PROCS} COUNT=${MAX_BACKGROUND_PROCS}
@ -996,7 +1001,7 @@ case ${ARG_ACTION} in
done done
# 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 failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
log "finished applying SSH controls remotely" log "finished applying SSH controls remotely"
;; ;;
@ -1028,7 +1033,7 @@ case ${ARG_ACTION} in
then then
# wait until all background processes are completed # wait until all background processes are completed
wait_for_children ${PIDS} || \ wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
PIDS='' PIDS=''
# reset max updates in background # reset max updates in background
COUNT=${MAX_BACKGROUND_PROCS} COUNT=${MAX_BACKGROUND_PROCS}
@ -1036,7 +1041,7 @@ case ${ARG_ACTION} in
done done
# 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 failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
log "finished copying/distributing SSH controls" log "finished copying/distributing SSH controls"
;; ;;
3) # create key fingerprints 3) # create key fingerprints
@ -1194,7 +1199,7 @@ case ${ARG_ACTION} in
then then
# wait until all background processes are completed # wait until all background processes are completed
wait_for_children ${PIDS} || \ wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
PIDS='' PIDS=''
# reset max updates in background # reset max updates in background
COUNT=${MAX_BACKGROUND_PROCS} COUNT=${MAX_BACKGROUND_PROCS}
@ -1202,7 +1207,7 @@ case ${ARG_ACTION} in
done done
# 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 failed to complete correctly" warn "$? background jobs (possibly) failed to complete correctly"
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

View File

@ -9,11 +9,14 @@
# Do not use double or single quotes around the option values # Do not use double or single quotes around the option values
# #
# use short hostnames or FQDN (0=short names; 1=FQDN) [default: 0]
use_fqdn=1
# target directory for allowed SSH key files # target directory for allowed SSH key files
access_dir=/etc/ssh_controls/keys.d access_dir=/etc/kudos/ssh_controls/keys.d
# location of the keys blacklist file # location of the keys blacklist file
blacklist_file=/etc/ssh_controls/keys.blacklisted blacklist_file=/etc/kudos/ssh_controls/keys.blacklisted
#****************************************************************************** #******************************************************************************
# End of FILE # End of FILE

View File

@ -29,6 +29,8 @@
#****************************************************************************** #******************************************************************************
use strict; use strict;
use Net::Domain qw(hostfqdn hostname);
use POSIX qw(uname);
use Data::Dumper; use Data::Dumper;
use Getopt::Long; use Getopt::Long;
use Pod::Usage; use Pod::Usage;
@ -40,7 +42,7 @@ use Pod::Usage;
# ------------------------- CONFIGURATION starts here ------------------------- # ------------------------- CONFIGURATION starts here -------------------------
# define the V.R.F (version/release/fix) # define the V.R.F (version/release/fix)
my $MY_VRF = "1.0.2"; my $MY_VRF = "1.1.0";
# name of global configuration file (no path, must be located in the script directory) # name of global configuration file (no path, must be located in the script directory)
my $global_config_file = "update_ssh.conf"; my $global_config_file = "update_ssh.conf";
# name of localized configuration file (no path, must be located in the script directory) # name of localized configuration file (no path, must be located in the script directory)
@ -51,10 +53,10 @@ my %selinux_contexts = ( '5' => 'sshd_key_t',
'7' => 'ssh_home_t'); '7' => 'ssh_home_t');
# ------------------------- CONFIGURATION ends here --------------------------- # ------------------------- CONFIGURATION ends here ---------------------------
# initialize variables # initialize variables
my ($debug, $verbose, $preview, $remove, $global) = (0,0,0,0,0); my ($debug, $verbose, $preview, $remove, $global, $use_fqdn) = (0,0,0,0,0,0);
my (@config_files, @zombie_files, $access_dir, $blacklist_file); my (@config_files, @zombie_files, $access_dir, $blacklist_file);
my (%options, @accounts, %aliases, %keys, %access, @blacklist); my (%options, @uname, @accounts, %aliases, %keys, %access, @blacklist);
my ($os, $host, $hostname, $run_dir); my ($os, $hostname, $run_dir);
my ($selinux_status, $selinux_context, $linux_version, $has_selinux) = ("","","",0); my ($selinux_status, $selinux_context, $linux_version, $has_selinux) = ("","","",0);
$|++; $|++;
@ -94,6 +96,10 @@ sub parse_config_file {
if (/^\s*$/ || /^#/) { if (/^\s*$/ || /^#/) {
next; next;
} else { } else {
if (/^\s*use_fqdn\s*=\s*([0-9]+)\s*$/) {
$use_fqdn = $1;
do_log ("DEBUG: picking up setting: use_fqdn=${use_fqdn}");
}
if (/^\s*access_dir\s*=\s*([0-9A-Za-z_\-\.\/~]+)\s*$/) { if (/^\s*access_dir\s*=\s*([0-9A-Za-z_\-\.\/~]+)\s*$/) {
$access_dir = $1; $access_dir = $1;
do_log ("DEBUG: picking up setting: access_dir=${access_dir}"); do_log ("DEBUG: picking up setting: access_dir=${access_dir}");
@ -215,8 +221,8 @@ if ($options{'debug'}) {
$verbose = 1 if ($options{'verbose'}); $verbose = 1 if ($options{'verbose'});
# what am I? # what am I?
$os = `uname`; @uname = uname();
chomp ($os); $os = $uname[0];
# who am I? # who am I?
unless ($preview and $global) { unless ($preview and $global) {
if ($< != 0) { if ($< != 0) {
@ -225,12 +231,10 @@ unless ($preview and $global) {
} }
} }
# where am I? # where am I?
$host = `hostname`; unless ($use_fqdn) {
chomp ($host); $hostname = hostfqdn();
if ($host =~ /\./) {
($hostname) = $host =~ /(.*?)\./;
} else { } else {
$hostname = $host; $hostname = hostname();
} }
$0 =~ /^(.+[\\\/])[^\\\/]+[\\\/]*$/; $0 =~ /^(.+[\\\/])[^\\\/]+[\\\/]*$/;
my $run_dir = $1 || "."; my $run_dir = $1 || ".";
@ -549,7 +553,11 @@ unless ($preview) {
} else { } else {
$selinux_context = $selinux_contexts{$linux_version}; $selinux_context = $selinux_contexts{$linux_version};
} }
do_log ("INFO: runtime info: OS major version $linux_version, SELinux context $selinux_context on $hostname"); if ($has_selinux) {
do_log ("INFO: runtime info: OS major version $linux_version, SELinux context $selinux_context on $hostname");
} else {
do_log ("INFO: runtime info: OS major version $linux_version on $hostname");
}
last SWITCH_OS; last SWITCH_OS;
}; };
} }
@ -762,3 +770,4 @@ S< >Show version of the script.
@(#) 2014-12-04: VRF 1.0.0: first version [Patrick Van der Veken] @(#) 2014-12-04: VRF 1.0.0: first version [Patrick Van der Veken]
@(#) 2014-12-16: VRF 1.0.1: added SELinux context, new config option 'selinux_context' [Patrick Van der Veken] @(#) 2014-12-16: VRF 1.0.1: added SELinux context, new config option 'selinux_context' [Patrick Van der Veken]
@(#) 2015-08-08: VRF 1.0.2: small fix for 'cut' command [Patrick Van der Veken] @(#) 2015-08-08: VRF 1.0.2: small fix for 'cut' command [Patrick Van der Veken]
@(#) 2015-08-15: VRF 1.1.0: replace uname/hostname syscalls, now support for FQDN via $use_fqdn, other fixes [Patrick Van der Veken]