Redirect all logs to logfile

This commit is contained in:
Pratik
2018-12-07 17:43:57 +05:30
parent 04e3daedf1
commit 07b240a9f7

View File

@@ -1,23 +1,33 @@
#!/etc/bin/env bash
# Accept user name as a script argument
# If no username provided
# generate a random username - all lowercase
# Something important fails
# Revert everything back to how it was
# Redirect every output to a logfile
# Ask the user to NOT logout yet
# Ask him to report back if he can login using the new user -with the ssh-private key
# If not
# Remove the SSH-only login and ask the user to login using password
# If he can - great - tell him to talk to the server provider's support to get help regarding SSH-only access
# Report the things
# Root password
# User Password
# User SSH-Private Key
# User SSH-Public key
# Display the root-user's new password on screen
# Ask the user to NOT logout yet and login as normal user
# If he can - great
# Remove the SSH-only login and ask the user to login using password
# Report
# Root password
# User Password
# User SSH-Private Key
# User SSH-Public key
# If not
# Ask him to report back if he can login using the new user -with the ssh-private key
# - tell him to talk to the server provider's support to get help regarding SSH-only access
# What to do if making .bkp file fails?
# Add timestamp to all backup files filename.071218_171731_bak
#Test
# 1 - Deb 9.x
# 2 - Deb 8.x
# 3 - Ubuntu 14.x
# 4 - Ubuntu 16.x
# 5 - Ubuntu 18.x
# DigitalOcean
# OVH
# Hetzner
SCRIPT_NAME=server_harden
SCRIPT_VERSION=0.2
LOGFILE=/tmp/"$SCRIPT_NAME"_v"$SCRIPT_VERSION".log
##############################################################
# Basic checks before starting
@@ -25,30 +35,22 @@
# No root - no good
[ "$(id -u)" != "0" ] && {
echo "Error: You must be root to run this script, please login as root and execute the script again."
printf "ERROR: You must be root to run this script.\\nPlease login as root and execute the script again."
exit 1
}
# Check supported OSes
if [[ $(sed 's/\..*//' /etc/debian_version) -eq 8 ]]; then
if [[ $(cut -d. -f 1 < /etc/debian_version) -eq 8 ]]; then
DEB_VER_STR="jessie"
elif [[ $(sed 's/\..*//' /etc/debian_version) -eq 9 ]]; then
elif [[ $(cut -d. -f 1 < /etc/debian_version) -eq 9 ]]; then
DEB_VER_STR="stretch"
else
printf "This version of Debian is NOT supported.\\n"
printf "This script only supports Debian Stretch (9.x) and Debian Jessie (8.x).\\n"
printf "Your OS is NOT supported.\\n"
exit 1
fi
##############################################################
# Display what the script does
##############################################################
# What to do if something fails
# Catastophic failure
# Ignorable failure
# Where to find the log file
##############################################################
# Gather info
##############################################################
@@ -58,21 +60,34 @@ fi
clear
echo "Do you want to change root password ? (y/n)"
echo "(You might want to do this if you received it as an email from your host.)"
while [[ $RESET_ROOT_PWD != "y" && $RESET_ROOT_PWD != "n" ]]; do
read -rp "Select an option [1-2]: " RESET_ROOT_PWD
while [[ $RESET_ROOT_PWD != "y" && $RESET_ROOT_PWD != "n" ]]; do
read -rp "Select an option (y/n): " RESET_ROOT_PWD
RESET_ROOT_PWD=$(echo "$RESET_ROOT_PWD" | head -c 1)
done
# Ask for a user name
echo ""
echo "A new non-root user will be created for you."
read -rp "Please provide a user name - " NORM_USER_NAME
# If the user exists - ask for a different username
while [[ ! "$NORM_USER_NAME" ]] && [[ $(getent passwd "$NORM_USER_NAME" | wc -l) -gt 0 ]]; do
echo "User name either already exists or you provided an invalid username."
read -rp "Please provide a user name - " NORM_USER_NAME
echo "Allow this script to randomly generate a username for you ? (y/n)"
while [[ $AUTO_GEN_USERNAME != "y" && $AUTO_GEN_USERNAME != "n" ]]; do
read -rp "Select an option (y/n): " AUTO_GEN_USERNAME
done
if [[ $AUTO_GEN_USERNAME == 'n' ]]; then
while [[ ! "$NORM_USER_NAME" ]]; do
printf "Please provide a user name - \\n"
printf "%2s - [a-zA-Z0-9] [-] [_] are allowed\\n%2s - NO special characters.\\n%2s - NO spaces.\\n:" " " " " " "
read -r NORM_USER_NAME
# If the user exists or invalid characters - ask for a different username
if [[ $(echo "$NORM_USER_NAME" | grep -Pnc '^[a-zA-Z0-9_-]+$') -eq 0 ]] ||
[[ $(getent passwd "$NORM_USER_NAME" | wc -l) -gt 0 ]]; then
NORM_USER_NAME=""
printf "%2s !!! User name already exists or \\n%2s !!! Invalid characters in the User name.\\n" " " " "
continue
fi
done
else
echo ""
fi
##############################################################
# Log
@@ -84,10 +99,9 @@ CRED="${CSI}1;31m"
CGREEN="${CSI}1;32m"
CVERTICAL="|"
CHORIZONTAL="_"
SCRIPT_NAME=server_harden
SCRIPT_VERSION=0.2
LOGFILE=/tmp/"$SCRIPT_NAME"_v"$SCRIPT_VERSION".log
# Reset privilous log file
printf "" > "$LOGFILE"
function horizontal_fill() {
local char=$1
@@ -118,6 +132,10 @@ function recap (){
}
function finally(){
# Check if $what_failed is one of the catastrophic failures
# if - Catastrofic failure - Check if any .bkp file exist and revert them to original
# Let user know nothing was changed
# if - Non-catastrophic failure - Inform user of side effects
#local what_failed=$1
line_fill "$CHORIZONTAL" 60
@@ -130,22 +148,26 @@ function finally(){
line_fill "$CHORIZONTAL" 60
}
function log() {
function file_log(){
printf "%s - %s\\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >> "$LOGFILE"
}
function op_log() {
local EVENT=$1
local RESULT=$2
if [ "$RESULT" = "SUCCESSFUL" ]
then
printf "%30s %7s [${CGREEN}${RESULT}${CEND}]\\n" "$EVENT" " "
echo "$(date '+%Y-%m-%d %H:%M:%S')" - "$EVENT" - "$RESULT" >> "$LOGFILE"
printf "\r%30s %7s [${CGREEN}${RESULT}${CEND}]\\n" "$EVENT" " "
file_log "${EVENT} - ${RESULT}"
elif [ "$RESULT" = "FAILED" ]
then
printf "%30s %7s [${CRED}${RESULT}${CEND}]\\n" "$EVENT" " "
printf "\r%30s %7s [${CRED}${RESULT}${CEND}]\\n" "$EVENT" " "
printf "\\n\\nPlease look at %s\\n\\n" "$LOGFILE"
echo "$(date '+%Y-%m-%d %H:%M:%S')" - "$EVENT" - "$RESULT" >> "$LOGFILE"
file_log "${EVENT} - ${RESULT}"
else
printf "%30s %7s [${CRED}..${CEND}]\\r" "$EVENT" " "
echo "$(date '+%Y-%m-%d %H:%M:%S')" - "$EVENT" - "begin..." >> "$LOGFILE"
printf "%30s %7s [${CRED}..${CEND}]" "$EVENT" " "
file_log "${EVENT} - begin..."
fi
}
@@ -162,32 +184,80 @@ else
fi
if [[ $SESSION_TYPE == "remote/ssh" ]]; then
printf "You are currently connected to an SSH session.\\n"
file_log "Connected through SSH session."
else
printf "You are currently connected using password authentication.\\n"
file_log "Connected using password authentication."
fi
##############################################################
# Display what the script does
##############################################################
clear
cat <<INFORM | more
!!! READ BELOW & PRESS ENTER TO CONTINUE !!!
##################################################################
This script performs the following tasks :-
1 - Change your root password (unless you have choosen NOT to)
2 - Create a non-root user (unless provided by you a random
username will be created)
3 - Generate SSH keys on the server and store them at ~/.ssh
4 - Adds the public key from the above step to
~/.ssh/authorized_keys file
5 - Restricts access to the SSH ~/.ssh folder
6 - Restricts login method to SSH-only by editing
/etc/ssh/sshd_config file to enable
7 - Restores the /etc/apt/sources.list
(Most server provider alter these to serve software from
their CDNs)
8 - Installs "sudo" "curl" "screen"
9 - Display the following at the end
a) root password (if changed)
b) user name
c) user password
d) SSH Private Key
e) SSH Public Key
Before editing any file, script creates a back up of that file
(filename.bak) in the same directory. If script detects any
catastrophic error, then it restores the original files. Script
assumes you are running this on a brand new VPS and that DATALOSS
OR LOSS OF ACCESS TO THE SERVER IS NOT A MAJOR CONCERN. If you do
however lose access to the server - most VPS provider allow to
create a new one easily.
A log file can be found at ${LOGFILE}
TO CONTINUE (press any key)...
TO EXIT (ctrl + c)...
INFORM
read -r
clear
##############################################################
# Change root's password
##############################################################
if [[ $RESET_ROOT_PWD == 'y' ]]; then
{
log "Changing root password"
op_log "Changing root password"
# Generate a 15 character random password
PASS_ROOT="$(< /dev/urandom tr -cd "[:alnum:]" | head -c 15)" || exit 1
file_log "Generated Root Password - ${PASS_ROOT}"
# Change root's password
echo -e "${PASS_ROOT}\\n${PASS_ROOT}" | passwd > /dev/null
}
echo -e "${PASS_ROOT}\\n${PASS_ROOT}" | passwd
} 2>> "$LOGFILE" >&2
if [[ $? -eq 0 ]]; then
log "Changing root password" "SUCCESSFUL"
op_log "Changing root password" "SUCCESSFUL"
else
# Low priority - since we are disabling root login anyways
log "Changing root password" "FAILED"
op_log "Changing root password" "FAILED"
fi
fi
@@ -196,22 +266,28 @@ fi
# Create a normal user
##############################################################
{
log "Creating new user"
op_log "Creating new user"
if [[ $AUTO_GEN_USERNAME == 'y' ]]; then
NORM_USER_NAME="$(< /dev/urandom tr -cd 'a-z' | head -c 6)""$(< /dev/urandom tr -cd '0-9' | head -c 2)" || exit 1
file_log "Generated user name - ${NORM_USER_NAME}"
fi
# Generate a 15 character random password
USER_PASS="$(< /dev/urandom tr -cd "[:alnum:]" | head -c 15)" || exit 1
file_log "Generated user password - ${USER_PASS}"
# Create the user and assign the above password
echo -e "${USER_PASS}\\n${USER_PASS}" | adduser "$NORM_USER_NAME" -q --gecos "First Last,RoomNumber,WorkPhone,HomePhone" 2> /dev/null
echo -e "${USER_PASS}\\n${USER_PASS}" | adduser "$NORM_USER_NAME" -q --gecos "First Last,RoomNumber,WorkPhone,HomePhone"
# Give root privilages to the above user
usermod -aG sudo "$NORM_USER_NAME" || exit 1
}
} 2>> "$LOGFILE" >&2
if [[ $? -eq 0 ]]; then
log "Creating new user" "SUCCESSFUL"
op_log "Creating new user" "SUCCESSFUL"
else
log "Creating new user" "FAILED"
op_log "Creating new user" "FAILED"
finally "CNU"
exit 1;
fi
@@ -221,11 +297,13 @@ fi
# Create SSH Key for the new user
##############################################################
{
log "Creating SSH Key for new user"
op_log "Creating SSH Key for new user"
shopt -s nullglob
KEY_FILES=("$SSH_DIR"/"$NORM_USER_NAME".pem*)
#TODO - If SSH files already exist - rename them to .timestamp_bkp
# Create key file only if it does NOT exist
if [[ ! ${KEY_FILES[0]} ]]; then
SSH_DIR=/home/"$NORM_USER_NAME"/.ssh
@@ -233,17 +311,24 @@ fi
# Generate a 15 character random password for key
KEY_PASS="$(< /dev/urandom tr -cd "[:alnum:]" | head -c 15)" || exit 1
file_log "Generated SSH Key Passphrase - ${KEY_PASS}"
# Create a OpenSSH-compliant ed25519-type key
ssh-keygen -a 1000 -o -t ed25519 -N "$KEY_PASS" -C "$NORM_USER_NAME" -f "$SSH_DIR"/"$NORM_USER_NAME".pem -q || exit 1
# See if the files actually got created
KEY_FILES=("$SSH_DIR"/"$NORM_USER_NAME".pem*)
if [[ ${#KEY_FILES[@]} -eq 0 ]]; then
file_log "Unknown error occured."
file_log "Could not create SSH key files."
exit 1
fi
fi
}
} 2>> "$LOGFILE" >&2
if [[ $? -eq 0 ]]; then
log "Creating SSH Key for new user" "SUCCESSFUL"
op_log "Creating SSH Key for new user" "SUCCESSFUL"
else
log "Creating SSH Key for new user" "FAILED"
op_log "Creating SSH Key for new user" "FAILED"
finally "CSK"
exit 1;
fi
@@ -253,15 +338,18 @@ fi
# Add generated key to authorized_keys file
##############################################################
{
log "Adding SSH Key to 'authorized_keys' file"
op_log "Adding SSH Key to 'authorized_keys' file"
# Create authorized_keys if it does not exist yet
touch "$SSH_DIR"/authorized_keys
# Insert the public key into "authoried_keys" file
cat "${KEY_FILES[1]}" >> "$SSH_DIR"/authorized_keys || exit 1
}
} 2>> "$LOGFILE" >&2
if [[ $? -eq 0 ]]; then
log "Adding SSH Key to 'authorized_keys' file" "SUCCESSFUL"
op_log "Adding SSH Key to 'authorized_keys' file" "SUCCESSFUL"
else
log "Adding SSH Key to 'authorized_keys' file" "FAILED"
op_log "Adding SSH Key to 'authorized_keys' file" "FAILED"
finally "ATAF"
exit 1;
fi
@@ -271,7 +359,7 @@ fi
# Secure authorized_keys file
##############################################################
{
log "Securing 'authorized_keys' file"
op_log "Securing 'authorized_keys' file"
# Set appropriate permissions for ".ssh" dir and "authorized_key" file
chown -R "$NORM_USER_NAME" "$SSH_DIR" && \
@@ -279,11 +367,14 @@ fi
chmod 700 "$SSH_DIR" && \
chmod 400 "$SSH_DIR"/authorized_keys && \
chattr +i "$SSH_DIR"/authorized_keys
}
} 2>> "$LOGFILE" >&2
if [[ $? -eq 0 ]]; then
log "Securing 'authorized_keys' file" "SUCCESSFUL"
op_log "Securing 'authorized_keys' file" "SUCCESSFUL"
else
log "Securing 'authorized_keys' file" "FAILED"
file_log "Setting restrictive permissions for '~/.ssh/' directory failed"
file_log "Please do 'ls -lAh ~/.ssh/' and check manually to see what went wrong."
file_log "Rest of the tasks will continue."
op_log "Securing 'authorized_keys' file" "FAILED"
fi
@@ -368,13 +459,13 @@ function set_config_key(){
}
{
log "Enabling SSH-only login"
op_log "Enabling SSH-only login"
# Backup the sshd_config file
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak || exit 1
# Remove root login
set_config_key "/etc/ssh/sshd_config" "PermitRootLogin" "no"
set_config_key "/etc/ssh/sshd_config" "PermitRootLogin" "no"
# Disable password login
set_config_key "/etc/ssh/sshd_config" "PasswordAuthentication" "no"
@@ -383,11 +474,11 @@ function set_config_key(){
set_config_key "/etc/ssh/sshd_config" "AuthorizedKeysFile" '%h\/\.ssh\/authorized_keys'
systemctl restart sshd
}
} 2>> "$LOGFILE" >&2
if [[ $? -eq 0 ]]; then
log "Enabling SSH-only login" "SUCCESSFUL"
op_log "Enabling SSH-only login" "SUCCESSFUL"
else
log "Enabling SSH-only login" "FAILED"
op_log "Enabling SSH-only login" "FAILED"
finally "ESOL"
exit 1;
fi
@@ -398,10 +489,10 @@ fi
##############################################################
# Low priority - But what to do if it fails???
log "Changing urls in sources.list to defaults"
op_log "Changing urls in sources.list to defaults"
mv /etc/apt/sources.list /etc/apt/sources.list.bak
sed -i "1,$(wc -l < /etc/apt/sources.list.bak) s/^/#/" /etc/apt/sources.list.bak
mv /etc/apt/sources.list /etc/apt/sources.list.bak 2>> "$LOGFILE" >&2
sed -i "1,$(wc -l < /etc/apt/sources.list.bak) s/^/#/" /etc/apt/sources.list.bak 2>> "$LOGFILE" >&2
# Default sources list for debian
cat <<TAG > /etc/apt/sources.list || exit 1
@@ -421,37 +512,44 @@ deb-src https://deb.debian.org/debian ${DEB_VER_STR}-backports main
TAG
# Find any additional sources listed by the provider and comment them out
SOURCE_FILES=(/etc/apt/source*/*.list)
SOURCE_FILES=(/etc/apt/source*/*.list) 2>> "$LOGFILE" >&2
if [[ ${#SOURCE_FILES[@]} -gt 0 ]]; then
for file in "${SOURCE_FILES[@]}";
do
mv "$file" "$file".bak
sed -i "1,$(wc -l < "$file") s/^/#/" "$file" >&2 /dev/null
mv "$file" "$file".bak 2>> "$LOGFILE" >&2
sed -i "1,$(wc -l < "$file") s/^/#/" "$file" 2>> "$LOGFILE" >&2
done
fi
# Comment out cloud-init generated templates for sources
CLOUD_INIT_FILES=(/etc/cloud/templates*/*.tmpl)
CLOUD_INIT_FILES=(/etc/cloud/templates*/*.tmpl) 2>> "$LOGFILE" >&2
if [[ ${#CLOUD_INIT_FILES[@]} -gt 0 ]]; then
for file in "${CLOUD_INIT_FILES[@]}";
do
mv "$file" "$file".bak
sed -i "1,$(wc -l < "$file") s/^/#/" "$file" >&2 /dev/null
mv "$file" "$file".bak 2>> "$LOGFILE" >&2
sed -i "1,$(wc -l < "$file") s/^/#/" "$file" 2>> "$LOGFILE" >&2
done
fi
if [[ $? -eq 0 ]]; then
log "Changing urls in sources.list to defaults" "FAILED"
op_log "Changing urls in sources.list to defaults" "FAILED"
else
log "Changing urls in sources.list to defaults" "FAILED"
op_log "Changing urls in sources.list to defaults" "FAILED"
fi
##############################################################
# Install required softwares
##############################################################
apt-get update && apt-get upgrade -y && apt-get install -y sudo curl screen
{
op_log "Installing required softwares"
apt-get update && apt-get upgrade -y && apt-get install -y sudo curl screen 2>> "$LOGFILE" >&2
}
if [[ $? -eq 0 ]]; then
op_log "Installing required softwares" "FAILED"
else
op_log "Installing required softwares" "FAILED"
fi
##############################################################
# Recap