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
# remote, create SSH key fingerprints or distribute the SSH controls files
# EXPECTS: (see --help for more options)
# REQUIRES: check_config(), check_logging(), check_params(), check_setup(),
# check_syntax(), count_fields(), die(), display_usage(),
# REQUIRES: check_config(), check_logging(), check_params(), check_root_user(),
# check_setup(), check_syntax(), count_fields(), die(), display_usage(),
# distribute2host(), do_cleanup(), fix2host(), get_linux_version(),
# 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()
#
# @(#) HISTORY:
@ -35,6 +35,9 @@
# @(#) 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-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!
#******************************************************************************
@ -44,32 +47,15 @@
#******************************************************************************
# ------------------------- 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)
MY_VRF="1.1.4"
# 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"
MY_VRF="1.2.0"
# name of the global configuration file (script)
GLOBAL_CONFIG_FILE="manage_ssh.conf"
# name of the local configuration file (script)
LOCAL_CONFIG_FILE="manage_ssh.conf.local"
# location of temporary working storage
TMP_DIR="/var/tmp"
# ------------------------- CONFIGURATION ends here ---------------------------
@ -322,7 +308,8 @@ if (( ARG_ACTION == 1 || ARG_ACTION == 2 || ARG_ACTION == 4 ))
then
for FILE in "${LOCAL_DIR}/update_ssh.pl" \
"${LOCAL_DIR}/update_ssh.conf" \
"${SCRIPT_DIR}/${SCRIPT_NAME}"
"${SCRIPT_DIR}/${SCRIPT_NAME}" \
"${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}"
do
if [[ ! -r "${FILE}" ]]
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
elevated privileges.
Note 3: only GLOBAL configuration files will be distributed to target hosts.
EOT
return 0
@ -491,7 +480,8 @@ for FILE in "${LOCAL_DIR}/access!660" \
"${LOCAL_DIR}/alias!660" \
"${LOCAL_DIR}/update_ssh.pl!770" \
"${LOCAL_DIR}/update_ssh.conf!660" \
"${SCRIPT_DIR}/${SCRIPT_NAME}!770"
"${SCRIPT_DIR}/${SCRIPT_NAME}!770" \
"${SCRIPT_DIR}/${GLOBAL_CONFIG_FILE}!660"
do
# sftp transfer
sftp_file ${FILE} ${SERVER}
@ -518,7 +508,7 @@ then
log "keys are stored in a DIRECTORY, first merging all keys into ${TMP_MERGE_FILE}"
cat ${KEYS_DIR}/* >${TMP_MERGE_FILE}
# sftp transfer
sftp_file "${TMP_MERGE_FILE}!440" ${SERVER}
sftp_file "${TMP_MERGE_FILE}!640" ${SERVER}
COPY_RC=$?
if (( ! COPY_RC ))
then
@ -528,7 +518,7 @@ then
fi
[[ -d ${TMP_WORK_DIR} ]] && rm -rf ${TMP_WORK_DIR} 2>/dev/null
else
sftp_file "${KEYS_FILE}!440" ${SERVER}
sftp_file "${KEYS_FILE}!640" ${SERVER}
COPY_RC=$?
if (( ! COPY_RC ))
then
@ -703,7 +693,7 @@ OLD_PWD=$(pwd) && cd ${TRANSFER_DIR}
sftp ${SFTP_ARGS} ${SSH_TRANSFER_USER}@${TRANSFER_HOST} >/dev/null <<EOT
cd ${REMOTE_DIR}
put ${SOURCE_FILE}
#chmod ${TRANSFER_PERMS} ${SOURCE_FILE}
chmod ${TRANSFER_PERMS} ${SOURCE_FILE}
EOT
SFTP_RC=$?
@ -814,10 +804,10 @@ do
# the child might have already ended before we get here (caveat emptor)
elif $(wait ${PID})
then
log "child process ${PID} exited"
else
log "child process ${PID} exited"
log "child process ${PID} exited [NOK]"
WAIT_ERRORS=$(( WAIT_ERRORS + 1 ))
else
log "child process ${PID} exited [OK]"
fi
done
# break loop if we no child PIDs left
@ -948,6 +938,21 @@ do
esac
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
check_params && check_config && check_setup && check_logging
@ -988,7 +993,7 @@ case ${ARG_ACTION} in
then
# wait until all background processes are completed
wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly"
warn "$? background jobs (possibly) failed to complete correctly"
PIDS=''
# reset max updates in background
COUNT=${MAX_BACKGROUND_PROCS}
@ -996,7 +1001,7 @@ case ${ARG_ACTION} in
done
# final wait for background processes to be finished completely
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"
;;
@ -1028,7 +1033,7 @@ case ${ARG_ACTION} in
then
# wait until all background processes are completed
wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly"
warn "$? background jobs (possibly) failed to complete correctly"
PIDS=''
# reset max updates in background
COUNT=${MAX_BACKGROUND_PROCS}
@ -1036,7 +1041,7 @@ case ${ARG_ACTION} in
done
# final wait for background processes to be finished completely
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"
;;
3) # create key fingerprints
@ -1194,7 +1199,7 @@ case ${ARG_ACTION} in
then
# wait until all background processes are completed
wait_for_children ${PIDS} || \
warn "$? background jobs failed to complete correctly"
warn "$? background jobs (possibly) failed to complete correctly"
PIDS=''
# reset max updates in background
COUNT=${MAX_BACKGROUND_PROCS}
@ -1202,7 +1207,7 @@ case ${ARG_ACTION} in
done
# final wait for background processes to be finished completely
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"
;;
7) # dump the configuration namespace

View File

@ -9,11 +9,14 @@
# 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
access_dir=/etc/ssh_controls/keys.d
access_dir=/etc/kudos/ssh_controls/keys.d
# location of the keys blacklist file
blacklist_file=/etc/ssh_controls/keys.blacklisted
blacklist_file=/etc/kudos/ssh_controls/keys.blacklisted
#******************************************************************************
# End of FILE

View File

@ -29,6 +29,8 @@
#******************************************************************************
use strict;
use Net::Domain qw(hostfqdn hostname);
use POSIX qw(uname);
use Data::Dumper;
use Getopt::Long;
use Pod::Usage;
@ -40,7 +42,7 @@ use Pod::Usage;
# ------------------------- CONFIGURATION starts here -------------------------
# 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)
my $global_config_file = "update_ssh.conf";
# 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');
# ------------------------- CONFIGURATION ends here ---------------------------
# 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 (%options, @accounts, %aliases, %keys, %access, @blacklist);
my ($os, $host, $hostname, $run_dir);
my (%options, @uname, @accounts, %aliases, %keys, %access, @blacklist);
my ($os, $hostname, $run_dir);
my ($selinux_status, $selinux_context, $linux_version, $has_selinux) = ("","","",0);
$|++;
@ -94,6 +96,10 @@ sub parse_config_file {
if (/^\s*$/ || /^#/) {
next;
} 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*$/) {
$access_dir = $1;
do_log ("DEBUG: picking up setting: access_dir=${access_dir}");
@ -215,8 +221,8 @@ if ($options{'debug'}) {
$verbose = 1 if ($options{'verbose'});
# what am I?
$os = `uname`;
chomp ($os);
@uname = uname();
$os = $uname[0];
# who am I?
unless ($preview and $global) {
if ($< != 0) {
@ -225,12 +231,10 @@ unless ($preview and $global) {
}
}
# where am I?
$host = `hostname`;
chomp ($host);
if ($host =~ /\./) {
($hostname) = $host =~ /(.*?)\./;
unless ($use_fqdn) {
$hostname = hostfqdn();
} else {
$hostname = $host;
$hostname = hostname();
}
$0 =~ /^(.+[\\\/])[^\\\/]+[\\\/]*$/;
my $run_dir = $1 || ".";
@ -549,7 +553,11 @@ unless ($preview) {
} else {
$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;
};
}
@ -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-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-15: VRF 1.1.0: replace uname/hostname syscalls, now support for FQDN via $use_fqdn, other fixes [Patrick Van der Veken]