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 #!/etc/bin/env bash
# Accept user name as a script argument
# If no username provided
# generate a random username - all lowercase
# Something important fails # Something important fails
# Revert everything back to how it was # Revert everything back to how it was
# Redirect every output to a logfile # Ask the user to NOT logout yet and login as normal user
# Ask the user to NOT logout yet # If he can - great
# 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 # 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
# Report the things
# Root password # Root password
# User Password # User Password
# User SSH-Private Key # User SSH-Private Key
# User SSH-Public key # User SSH-Public key
# Display the root-user's new password on screen # 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? # 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 # Basic checks before starting
@@ -25,30 +35,22 @@
# No root - no good # No root - no good
[ "$(id -u)" != "0" ] && { [ "$(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 exit 1
} }
# Check supported OSes # 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" 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" DEB_VER_STR="stretch"
else 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 exit 1
fi fi
##############################################################
# Display what the script does
##############################################################
# What to do if something fails
# Catastophic failure
# Ignorable failure
# Where to find the log file
############################################################## ##############################################################
# Gather info # Gather info
############################################################## ##############################################################
@@ -59,19 +61,32 @@ clear
echo "Do you want to change root password ? (y/n)" 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.)" 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 while [[ $RESET_ROOT_PWD != "y" && $RESET_ROOT_PWD != "n" ]]; do
read -rp "Select an option [1-2]: " RESET_ROOT_PWD read -rp "Select an option (y/n): " RESET_ROOT_PWD
RESET_ROOT_PWD=$(echo "$RESET_ROOT_PWD" | head -c 1)
done done
# Ask for a 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 "" echo ""
echo "A new non-root user will be created for you." fi
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
done
############################################################## ##############################################################
@@ -84,10 +99,9 @@ CRED="${CSI}1;31m"
CGREEN="${CSI}1;32m" CGREEN="${CSI}1;32m"
CVERTICAL="|" CVERTICAL="|"
CHORIZONTAL="_" 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() { function horizontal_fill() {
local char=$1 local char=$1
@@ -118,6 +132,10 @@ function recap (){
} }
function finally(){ 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 #local what_failed=$1
line_fill "$CHORIZONTAL" 60 line_fill "$CHORIZONTAL" 60
@@ -130,22 +148,26 @@ function finally(){
line_fill "$CHORIZONTAL" 60 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 EVENT=$1
local RESULT=$2 local RESULT=$2
if [ "$RESULT" = "SUCCESSFUL" ] if [ "$RESULT" = "SUCCESSFUL" ]
then then
printf "%30s %7s [${CGREEN}${RESULT}${CEND}]\\n" "$EVENT" " " printf "\r%30s %7s [${CGREEN}${RESULT}${CEND}]\\n" "$EVENT" " "
echo "$(date '+%Y-%m-%d %H:%M:%S')" - "$EVENT" - "$RESULT" >> "$LOGFILE" file_log "${EVENT} - ${RESULT}"
elif [ "$RESULT" = "FAILED" ] elif [ "$RESULT" = "FAILED" ]
then 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" 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 else
printf "%30s %7s [${CRED}..${CEND}]\\r" "$EVENT" " " printf "%30s %7s [${CRED}..${CEND}]" "$EVENT" " "
echo "$(date '+%Y-%m-%d %H:%M:%S')" - "$EVENT" - "begin..." >> "$LOGFILE" file_log "${EVENT} - begin..."
fi fi
} }
@@ -162,32 +184,80 @@ else
fi fi
if [[ $SESSION_TYPE == "remote/ssh" ]]; then if [[ $SESSION_TYPE == "remote/ssh" ]]; then
printf "You are currently connected to an SSH session.\\n" file_log "Connected through SSH session."
else else
printf "You are currently connected using password authentication.\\n" file_log "Connected using password authentication."
fi 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 # Change root's password
############################################################## ##############################################################
if [[ $RESET_ROOT_PWD == 'y' ]]; then if [[ $RESET_ROOT_PWD == 'y' ]]; then
{ {
log "Changing root password" op_log "Changing root password"
# Generate a 15 character random password # Generate a 15 character random password
PASS_ROOT="$(< /dev/urandom tr -cd "[:alnum:]" | head -c 15)" || exit 1 PASS_ROOT="$(< /dev/urandom tr -cd "[:alnum:]" | head -c 15)" || exit 1
file_log "Generated Root Password - ${PASS_ROOT}"
# Change root's password # 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 if [[ $? -eq 0 ]]; then
log "Changing root password" "SUCCESSFUL" op_log "Changing root password" "SUCCESSFUL"
else else
# Low priority - since we are disabling root login anyways # Low priority - since we are disabling root login anyways
log "Changing root password" "FAILED" op_log "Changing root password" "FAILED"
fi fi
fi fi
@@ -196,22 +266,28 @@ fi
# Create a normal user # 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 # Generate a 15 character random password
USER_PASS="$(< /dev/urandom tr -cd "[:alnum:]" | head -c 15)" || exit 1 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 # 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 # Give root privilages to the above user
usermod -aG sudo "$NORM_USER_NAME" || exit 1 usermod -aG sudo "$NORM_USER_NAME" || exit 1
} } 2>> "$LOGFILE" >&2
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
log "Creating new user" "SUCCESSFUL" op_log "Creating new user" "SUCCESSFUL"
else else
log "Creating new user" "FAILED" op_log "Creating new user" "FAILED"
finally "CNU" finally "CNU"
exit 1; exit 1;
fi fi
@@ -221,11 +297,13 @@ fi
# Create SSH Key for the new user # 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 shopt -s nullglob
KEY_FILES=("$SSH_DIR"/"$NORM_USER_NAME".pem*) 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 # Create key file only if it does NOT exist
if [[ ! ${KEY_FILES[0]} ]]; then if [[ ! ${KEY_FILES[0]} ]]; then
SSH_DIR=/home/"$NORM_USER_NAME"/.ssh SSH_DIR=/home/"$NORM_USER_NAME"/.ssh
@@ -233,17 +311,24 @@ fi
# Generate a 15 character random password for key # Generate a 15 character random password for key
KEY_PASS="$(< /dev/urandom tr -cd "[:alnum:]" | head -c 15)" || exit 1 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 # 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 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*) 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
} fi
} 2>> "$LOGFILE" >&2
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
log "Creating SSH Key for new user" "SUCCESSFUL" op_log "Creating SSH Key for new user" "SUCCESSFUL"
else else
log "Creating SSH Key for new user" "FAILED" op_log "Creating SSH Key for new user" "FAILED"
finally "CSK" finally "CSK"
exit 1; exit 1;
fi fi
@@ -253,15 +338,18 @@ fi
# Add generated key to authorized_keys file # 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 # Insert the public key into "authoried_keys" file
cat "${KEY_FILES[1]}" >> "$SSH_DIR"/authorized_keys || exit 1 cat "${KEY_FILES[1]}" >> "$SSH_DIR"/authorized_keys || exit 1
} } 2>> "$LOGFILE" >&2
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
log "Adding SSH Key to 'authorized_keys' file" "SUCCESSFUL" op_log "Adding SSH Key to 'authorized_keys' file" "SUCCESSFUL"
else else
log "Adding SSH Key to 'authorized_keys' file" "FAILED" op_log "Adding SSH Key to 'authorized_keys' file" "FAILED"
finally "ATAF" finally "ATAF"
exit 1; exit 1;
fi fi
@@ -271,7 +359,7 @@ fi
# Secure authorized_keys file # 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 # Set appropriate permissions for ".ssh" dir and "authorized_key" file
chown -R "$NORM_USER_NAME" "$SSH_DIR" && \ chown -R "$NORM_USER_NAME" "$SSH_DIR" && \
@@ -279,11 +367,14 @@ fi
chmod 700 "$SSH_DIR" && \ chmod 700 "$SSH_DIR" && \
chmod 400 "$SSH_DIR"/authorized_keys && \ chmod 400 "$SSH_DIR"/authorized_keys && \
chattr +i "$SSH_DIR"/authorized_keys chattr +i "$SSH_DIR"/authorized_keys
} } 2>> "$LOGFILE" >&2
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
log "Securing 'authorized_keys' file" "SUCCESSFUL" op_log "Securing 'authorized_keys' file" "SUCCESSFUL"
else 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 fi
@@ -368,7 +459,7 @@ function set_config_key(){
} }
{ {
log "Enabling SSH-only login" op_log "Enabling SSH-only login"
# Backup the sshd_config file # Backup the sshd_config file
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak || exit 1 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak || exit 1
@@ -383,11 +474,11 @@ function set_config_key(){
set_config_key "/etc/ssh/sshd_config" "AuthorizedKeysFile" '%h\/\.ssh\/authorized_keys' set_config_key "/etc/ssh/sshd_config" "AuthorizedKeysFile" '%h\/\.ssh\/authorized_keys'
systemctl restart sshd systemctl restart sshd
} } 2>> "$LOGFILE" >&2
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
log "Enabling SSH-only login" "SUCCESSFUL" op_log "Enabling SSH-only login" "SUCCESSFUL"
else else
log "Enabling SSH-only login" "FAILED" op_log "Enabling SSH-only login" "FAILED"
finally "ESOL" finally "ESOL"
exit 1; exit 1;
fi fi
@@ -398,10 +489,10 @@ fi
############################################################## ##############################################################
# Low priority - But what to do if it fails??? # 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 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 sed -i "1,$(wc -l < /etc/apt/sources.list.bak) s/^/#/" /etc/apt/sources.list.bak 2>> "$LOGFILE" >&2
# Default sources list for debian # Default sources list for debian
cat <<TAG > /etc/apt/sources.list || exit 1 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 TAG
# Find any additional sources listed by the provider and comment them out # 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 if [[ ${#SOURCE_FILES[@]} -gt 0 ]]; then
for file in "${SOURCE_FILES[@]}"; for file in "${SOURCE_FILES[@]}";
do do
mv "$file" "$file".bak mv "$file" "$file".bak 2>> "$LOGFILE" >&2
sed -i "1,$(wc -l < "$file") s/^/#/" "$file" >&2 /dev/null sed -i "1,$(wc -l < "$file") s/^/#/" "$file" 2>> "$LOGFILE" >&2
done done
fi fi
# Comment out cloud-init generated templates for sources # 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 if [[ ${#CLOUD_INIT_FILES[@]} -gt 0 ]]; then
for file in "${CLOUD_INIT_FILES[@]}"; for file in "${CLOUD_INIT_FILES[@]}";
do do
mv "$file" "$file".bak mv "$file" "$file".bak 2>> "$LOGFILE" >&2
sed -i "1,$(wc -l < "$file") s/^/#/" "$file" >&2 /dev/null sed -i "1,$(wc -l < "$file") s/^/#/" "$file" 2>> "$LOGFILE" >&2
done done
fi fi
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
log "Changing urls in sources.list to defaults" "FAILED" op_log "Changing urls in sources.list to defaults" "FAILED"
else else
log "Changing urls in sources.list to defaults" "FAILED" op_log "Changing urls in sources.list to defaults" "FAILED"
fi fi
############################################################## ##############################################################
# Install required softwares # 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 # Recap