Secure Setup [CentOS7]

by alrux
62 deployments · 5 still active · last rev. 1 month ago

- SSH disable root login and move to non-standard port
- passwordless admin user with public keys from GitHub user
- iptables filtering

Compatible with: CentOS 7
						#!/bin/bash
#
# StackScript Server Setup
#
# Copyright (c) 2015 ALRUX Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice, this
# list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# * Neither the name of ALRUX Inc. nor the names of its contributors may be
# used to endorse or promote products derived from this software without specific prior
# written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.

# <udf name="email" label="Admin email" example="Off-site email address to which to forward root's email." />

# <udf name="hostname" label="Hostname" example="Remember to set up Reverse DNS."/>
# <udf name="timezone" label="Time zone" default="America/Toronto"/>
# <udf name="ssh_port" label="SSH port" default="" example="Choose a non-standard port on which to run ssh."/>
# <udf name="admin_user" label="Admin username" default="admin" example="User to create with sudo privileges."/>
# <udf name="github_user_1" label="GitHub user" example="GitHub user from which to import public key(s)."/>
# <udf name="github_user_2" label="GitHub user" default="" example="GitHub user from which to import public key(s)."/>
# <udf name="github_user_3" label="GitHub user" default="" example="GitHub user from which to import public key(s)."/>
#
# <udf name="install_nginx" label="Install Nginx" oneof="Yes,No" default="Yes" example="Do you want to install and configure Nginx?"/>
# <udf name="nginx_ver" label="Nginx version" default="1.10.3" example="Nginx version to install."/>
# <udf name="nginx_user" label="Nginx user" default="www" example="Unprivileged user under which Nginx will run its workers."/>
#
# <udf name="tcp_ports" label="TCP ports" default="" example="Additional TCP ports to open for incoming connections. Comma separated."/>
# <udf name="udp_ports" label="UDP ports" default="" example="Additional UDP ports to open for incoming connections. Comma separated."/>

LOG_FILE="/root/stackscript.log"
LOCK_FILE="/root/stackscript.lock"

# send output to log file, but also to stdout (in case anyone is watching on a lish console)
exec &> >(tee -a "$LOG_FILE")

# Include lib/system.sh
source <ssinclude StackScriptID="12636">

# it seems two instances of the script are run in parallel; only keep the first
ID="$(random_string)"
echo $ID >> "$LOCK_FILE"

if [[ "$ID" == "$(head -n 1 "$LOCK_FILE")" ]]; then
	echo "StackScript instance ${ID} started $(date)"
else
	echo "StackScript instance ${ID} aborted $(date)"
	exit 1;
fi

# lock-down
iptables_setup
restart_services

# update all packages and ensure the basics are present
system_update
system_ensure_basics

# keep track of changes in /etc with git
system_start_etc_dir_versioning

set_hostname $HOSTNAME
system_record_etc_dir_changes "Updated hostname"

set_timezone $TIMEZONE
system_record_etc_dir_changes "Updated timezone"

ssh_setup $SSH_PORT
system_record_etc_dir_changes "Configured SSH"

postfix_install_loopback_only
system_record_etc_dir_changes "Installed Postfix, loopback only"

forward_root_mail "$EMAIL"
system_record_etc_dir_changes "Forwarded root's mail to ${EMAIL}"


AUTH_KEYS=$(cat <<EOD
$(get_github_user_keys "$GITHUB_USER_1") $GITHUB_USER_1

EOD
)

if [[ "$GITHUB_USER_2" != "" ]]; then
	AUTH_KEYS=$(cat <<EOD
$AUTH_KEYS
$(get_github_user_keys "$GITHUB_USER_2") $GITHUB_USER_2

EOD
	)
fi

if [[ "$GITHUB_USER_3" != "" ]]; then
	AUTH_KEYS=$(cat <<EOD
$AUTH_KEYS
$(get_github_user_keys "$GITHUB_USER_3") $GITHUB_USER_3

EOD
	)
fi

adduser "$ADMIN_USER"
user_add_pubkey "$ADMIN_USER" "$AUTH_KEYS"
user_sudoer_nopasswd "$ADMIN_USER"
PUB_KEYS=$(cat <<EOD
$PUB_KEYS
$ADMIN_USER:
$(user_gen_keys "$ADMIN_USER")

EOD
)

system_record_etc_dir_changes "Set up Admin ($ADMIN_USER) user"

user_lock "root"
PUB_KEYS=$(cat <<EOD
$PUB_KEYS
root:
$(user_gen_keys "root")

EOD
)

system_record_etc_dir_changes "Set up root user"


# Start preparing setup message, so we can add to it conditionally for optional services
cat > ~/setup_message <<EOD
Hi,

Linode $LINODE_ID ($HOSTNAME) is configured.

SSH is running on port $SSH_PORT and you can log in as $ADMIN_USER with any of
the keys authorized for the GitHub user $GITHUB_USER.

The mail for root is being forwarded to $EMAIL.

EOD


if [[ "$INSTALL_NGINX" == "Yes" ]]; then
	adduser "$NGINX_USER"
	user_add_pubkey "$NGINX_USER" "$AUTH_KEYS"
	ssh_sftp_only user "$NGINX_USER" /var/www
	PUB_KEYS=$(cat <<EOD
$PUB_KEYS
$NGINX_USER:
$(user_gen_keys "$NGINX_USER")

EOD
)
	system_record_etc_dir_changes "Set up Nginx ($NGINX_USER) user"

	# Include lib/nginx.sh
	source <ssinclude StackScriptID="12650">
	nginx_install "$NGINX_VER" "$NGINX_USER"

	iptables_open 80 "tcp"
	iptables_open 443 "tcp"

	system_record_etc_dir_changes "Installed Nginx"

cat >> ~/setup_message <<EOD
Nginx version $NGINX_VER is installed and set up to run its workers as $NGINX_USER.

EOD

fi # [[ "$INSTALL_NGINX" == "Yes" ]]


while IFS=',' read -ra PORTS; do
	  for PORT in "${PORTS[@]}"; do
		  iptables_open "$PORT" "tcp"
	  done
done <<< "$TCP_PORTS"

while IFS=',' read -ra PORTS; do
	  for PORT in "${PORTS[@]}"; do
		  iptables_open "$PORT" "udp"
	  done
done <<< "$UDP_PORTS"

system_record_etc_dir_changes "Opened additional ports TCP($TCP_PORTS), UDP($UDP_PORTS)"


user_niceties
restart_services
system_record_etc_dir_changes "Added user niceties and restarted services"


echo
echo "##############################"
echo "# Firewall rules IPv4"
echo "##############################"
iptables -L -v -n
echo
echo "##############################"
echo "# Firewall rules IPv6"
echo "##############################"
ip6tables -L -v -n


cat >> ~/setup_message <<EOD
The following public keys can be used to grant users access to remote services:
$PUB_KEYS


Attached is the log of the setup process.

Enjoy!


--- /home/${ADMIN_USER}/.ssh/authorized_keys BEGINS ---
EOD
cat >> ~/setup_message < /home/${ADMIN_USER}/.ssh/authorized_keys
cat >> ~/setup_message <<EOD
--- /home/${ADMIN_USER}/.ssh/authorized_keys ENDS ---
EOD

cat ~/setup_message | mailx -s "Linode $LINODE_ID ($HOSTNAME) setup complete" -a $LOG_FILE root

rm -f $LOCK_FILE