Files
BastilleBSD_bastille/usr/local/share/bastille/setup.sh

533 lines
19 KiB
Bash
Raw Normal View History

2023-07-14 21:02:14 -06:00
#!/bin/sh
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright (c) 2018-2025, Christer Edwards <christer.edwards@gmail.com>
2023-07-14 21:02:14 -06:00
# 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 the copyright holder 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.
. /usr/local/share/bastille/common.sh
usage() {
2025-12-06 23:19:19 -07:00
error_notify "Usage: bastille setup [option(s)] [bridge|linux|loopback|netgraph|firewall|shared|storage|vnet]"
2025-05-16 15:32:56 -06:00
cat << EOF
2025-09-23 18:51:04 +02:00
2025-05-16 15:32:56 -06:00
Options:
2025-12-06 23:19:19 -07:00
-y | --yes Do not prompt. Assume always yes.
-x | --debug Enable debug mode.
2025-05-16 15:32:56 -06:00
EOF
exit 1
2023-07-14 21:02:14 -06:00
}
2025-05-16 18:41:44 -06:00
# Handle options.
AUTO_YES=0
while [ "$#" -gt 0 ]; do
case "${1}" in
-h|--help|help)
usage
;;
-y|--yes)
AUTO_YES=1
shift
;;
-x|--debug)
enable_debug
shift
;;
2025-09-23 18:51:04 +02:00
-*)
2025-05-16 18:41:44 -06:00
for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do
case ${_opt} in
y) AUTO_YES=1 ;;
x) enable_debug ;;
*) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;;
esac
done
shift
;;
*)
break
;;
esac
done
# Check for too many args
2025-05-19 20:01:59 -06:00
if [ "$#" -gt 2 ]; then
2023-07-14 21:02:14 -06:00
usage
fi
2025-05-16 18:41:44 -06:00
OPT_CONFIG="${1}"
2025-05-19 20:06:23 -06:00
OPT_ARG="${2}"
2025-05-16 18:41:44 -06:00
bastille_root_check
configure_linux() {
if ! kldstat -qn linux || \
! kldstat -qn linux64 || \
! kldstat -qm fdescfs || \
! kldstat -qm linprocfs || \
! kldstat -qm linsysfs || \
! kldstat -qm tmpfs; then
2025-11-27 21:01:23 -05:00
local required_mods="fdescfs linprocfs linsysfs tmpfs"
local linuxarc_mods="linux linux64"
# Enable required modules
for mod in ${required_mods}; do
if ! kldstat -qm ${mod}; then
if [ ! "$(sysrc -f /boot/loader.conf -qn ${mod}_load)" = "YES" ] && [ ! "$(sysrc -f /boot/loader.conf.local -qn ${mod}_load)" = "YES" ]; then
info "\nLoading kernel module: ${mod}"
2025-11-27 21:01:23 -05:00
kldload ${mod}
info "\nPersisting module: ${mod}"
sysrc -f /boot/loader.conf ${mod}_load=YES
else
info "\nLoading kernel module: ${mod}"
2025-11-27 21:01:23 -05:00
kldload ${mod}
fi
fi
done
# Mandatory Linux modules/rc.
for mod in ${linuxarc_mods}; do
if ! kldstat -qn ${mod}; then
info "\nLoading kernel module: ${mod}"
2025-11-27 21:01:59 -05:00
kldload ${mod}
fi
done
# Enable linux
if [ ! "$(sysrc -qn linux_enable)" = "YES" ] && [ ! "$(sysrc -f /etc/rc.conf.local -qn linux_enable)" = "YES" ]; then
sysrc linux_enable=YES
fi
# Install debootstrap package
if ! which -s debootstrap; then
pkg install -y debootstrap
fi
info "\nLinux has been successfully configured!"
else
info "\nLinux has already been configured!"
fi
}
2025-04-25 14:33:38 -06:00
# Configure netgraph
configure_netgraph() {
if ! kldstat -qm netgraph || \
! kldstat -qm ng_netflow || \
! kldstat -qm ng_ksocket || \
! kldstat -qm ng_ether || \
! kldstat -qm ng_bridge || \
! kldstat -qm ng_eiface || \
! kldstat -qm ng_socket; then
2025-05-16 21:48:41 -06:00
# Ensure jib script is in place for VNET jails
if [ ! "$(command -v jng)" ]; then
if [ -f "/usr/share/examples/jails/jng" ] && [ ! -f "/usr/local/bin/jng" ]; then
2025-05-16 21:48:41 -06:00
install -m 0544 /usr/share/examples/jails/jng /usr/local/bin/jng
fi
fi
2025-11-27 21:01:23 -05:00
local required_mods="netgraph ng_netflow ng_ksocket ng_ether ng_bridge ng_eiface ng_socket"
2025-05-16 21:48:41 -06:00
info "\nConfiguring netgraph modules..."
# Load requried netgraph kernel modules
2025-11-27 21:01:23 -05:00
for mod in ${required_mods}; do
if ! kldstat -qm ${mod}; then
info "\nLoading kernel module: ${mod}"
kldload -v ${mod}
info "\nPersisting module: ${mod}"
sysrc -f /boot/loader.conf ${mod}_load=YES
fi
done
# Set bastille_network_vnet_type to netgraph
sysrc -f "${BASTILLE_CONFIG}" bastille_network_vnet_type="netgraph"
2025-11-27 21:01:23 -05:00
2025-05-16 21:48:41 -06:00
info "\nNetgraph has been successfully configured!"
2025-04-25 14:33:38 -06:00
else
2025-05-16 21:48:41 -06:00
info "\nNetgraph has already been configured!"
2025-04-25 14:33:38 -06:00
fi
}
# Configure bastille loopback network interface
configure_loopback_interface() {
if [ -z "$(sysrc -f ${BASTILLE_CONFIG} -n bastille_network_loopback)" ] || ! sysrc -n cloned_interfaces | grep -oq "lo1"; then
2025-05-16 21:48:41 -06:00
info "\nConfiguring bastille0 loopback interface"
sysrc cloned_interfaces+=lo1
2025-04-22 12:59:38 -06:00
sysrc ifconfig_lo1_name="bastille0"
2025-05-16 21:48:41 -06:00
info "\nBringing up new interface: [bastille0]"
service netif cloneup
sysrc -f "${BASTILLE_CONFIG}" bastille_network_loopback="bastille0"
sysrc -f "${BASTILLE_CONFIG}" bastille_network_shared=""
2025-05-16 21:48:41 -06:00
info "\nLoopback interface successfully configured: [bastille0]"
else
2025-05-16 21:48:41 -06:00
info "\nLoopback interface has already been configured: [bastille0]"
fi
2023-07-14 21:02:14 -06:00
}
configure_shared_interface() {
2025-05-19 20:01:59 -06:00
_auto_if="${1}"
_interface_list="$(ifconfig -l)"
_interface_count=0
2025-05-19 20:01:59 -06:00
if [ -z "${_interface_list}" ]; then
error_exit "Unable to detect interfaces, exiting."
fi
if [ -z "$(sysrc -f ${BASTILLE_CONFIG} -n bastille_network_shared)" ]; then
2025-05-16 21:48:41 -06:00
info "\nAttempting to configure shared interface for bastille..."
info "\nListing available interfaces..."
2025-05-19 20:01:59 -06:00
if [ -z "${_auto_if}" ]; then
for _if in ${_interface_list}; do
echo "[${_interface_count}] ${_if}"
_if_num="${_if_num} [${_interface_count}]${_if}"
_interface_count=$(expr ${_interface_count} + 1)
done
# shellcheck disable=SC3045
read -p "Please select the interface you would like to use: " _interface_choice
if ! echo "${_interface_choice}" | grep -Eq "^[0-9]+$"; then
error_exit "Invalid input number, aborting!"
else
_interface_select=$(echo "${_if_num}" | grep -wo "\[${_interface_choice}\][^ ]*" | sed 's/\[.*\]//g')
fi
else
2025-05-19 20:01:59 -06:00
_interface_select="${_auto_if}"
fi
2025-05-19 20:01:59 -06:00
# Adjust bastille.conf to reflect above choices
sysrc -f "${BASTILLE_CONFIG}" bastille_network_loopback=""
2025-04-22 20:32:53 -06:00
sysrc cloned_interfaces-="lo1"
ifconfig bastille0 destroy 2>/dev/null
sysrc -f "${BASTILLE_CONFIG}" bastille_network_shared="${_interface_select}"
2025-05-16 21:48:41 -06:00
info "\nShared interface successfully configured: [${_interface_select}]"
else
2025-05-16 21:48:41 -06:00
info "\nShared interface has already been configured: [$(sysrc -f ${BASTILLE_CONFIG} -n bastille_network_shared)]"
fi
}
configure_bridge() {
2025-05-19 20:01:59 -06:00
_auto_if="${1}"
_interface_list="$(ifconfig -l)"
_interface_count=0
2025-05-19 20:01:59 -06:00
if [ -z "${_interface_list}" ]; then
error_exit "Unable to detect interfaces, exiting."
fi
if ! ifconfig -g bridge | grep -oqw "${_bridge_name}"; then
2025-05-16 21:48:41 -06:00
info "\nConfiguring ${_bridge_name} bridge interface..."
2025-05-19 20:01:59 -06:00
if [ -z "${_auto_if}" ]; then
info "\nListing available interfaces..."
for _if in ${_interface_list}; do
if ifconfig -g bridge | grep -oqw "${_if}" || ifconfig -g lo | grep -oqw "${_if}"; then
continue
else
echo "[${_interface_count}] ${_if}"
_if_num="${_if_num} [${_interface_count}]${_if}"
_interface_count=$(expr ${_interface_count} + 1)
fi
done
# shellcheck disable=SC3045
read -p "Please select the interface to attach the bridge to: " _interface_choice
if ! echo "${_interface_choice}" | grep -Eq "^[0-9]+$"; then
error_exit "Invalid input number, aborting!"
else
2025-05-19 20:01:59 -06:00
_interface_select=$(echo "${_if_num}" | grep -wo "\[${_interface_choice}\][^ ]*" | sed 's/\[.*\]//g')
fi
else
2025-05-19 20:01:59 -06:00
_interface_select="${_auto_if}"
fi
# Create bridge and persist on reboot
2025-05-22 10:31:13 -06:00
_bridge_name="${_interface_select}bridge"
ifconfig bridge0 create
2025-05-22 10:31:13 -06:00
ifconfig bridge0 name ${_bridge_name}
ifconfig ${_bridge_name} addm ${_interface_select} up
sysrc cloned_interfaces+="bridge0"
2025-05-22 10:31:13 -06:00
sysrc ifconfig_bridge0_name="${_bridge_name}"
sysrc ifconfig_${_bridge_name}="addm ${_interface_select} up"
# Set some sysctl values
sysctl net.inet.ip.forwarding=1
sysctl net.link.bridge.pfil_bridge=0
sysctl net.link.bridge.pfil_onlyip=0
sysctl net.link.bridge.pfil_member=0
echo net.inet.ip.forwarding=1 >> /etc/sysctl.conf
echo net.link.bridge.pfil_bridge=0 >> /etc/sysctl.conf
echo net.link.bridge.pfil_onlyip=0 >> /etc/sysctl.conf
echo net.link.bridge.pfil_member=0 >> /etc/sysctl.conf
2025-05-16 21:48:41 -06:00
info "\nBridge interface successfully configured: [${_bridge_name}]"
else
2025-05-16 21:48:41 -06:00
info "\nBridge has alread been configured: [${_bridge_name}]"
fi
}
configure_vnet() {
2025-11-10 13:18:06 -07:00
# Ensure proper jail helper script
if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then
if [ ! "$(command -v jib)" ]; then
if [ -f "/usr/share/examples/jails/jib" ] && [ ! -f "/usr/local/bin/jib" ]; then
2025-11-10 13:18:06 -07:00
install -m 0544 /usr/share/examples/jails/jib /usr/local/bin/jib
fi
fi
elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then
if [ ! "$(command -v jng)" ]; then
if [ -f "/usr/share/examples/jails/jng" ] && [ ! -f "/usr/local/bin/jng" ]; then
2025-11-10 13:18:06 -07:00
install -m 0544 /usr/share/examples/jails/jng /usr/local/bin/jng
fi
fi
fi
2025-11-10 13:18:06 -07:00
# Create default VNET ruleset
if [ ! -f "/etc/devfs.rules" ] || ! grep -oq "bastille_vnet=13" /etc/devfs.rules; then
2025-05-16 21:48:41 -06:00
info "\nCreating bastille_vnet devfs.rules"
cat << EOF > /etc/devfs.rules
[bastille_vnet=13]
add include \$devfsrules_hide_all
add include \$devfsrules_unhide_basic
add include \$devfsrules_unhide_login
add include \$devfsrules_jail
add include \$devfsrules_jail_vnet
add path 'bpf*' unhide
EOF
else
2025-05-16 21:48:41 -06:00
info "\nVNET has already been configured!"
fi
2023-07-14 21:02:14 -06:00
}
# Configure pf firewall
2023-07-14 21:02:14 -06:00
configure_pf() {
# shellcheck disable=SC2154
if [ ! -f "${bastille_pf_conf}" ]; then
# shellcheck disable=SC3043
local ext_if
ext_if=$(netstat -rn | awk '/default/ {print $4}' | head -n1)
2025-05-16 21:48:41 -06:00
info "\nDetermined default network interface: ($ext_if)"
echo "${bastille_pf_conf} does not exist: creating..."
## creating pf.conf
cat << EOF > "${bastille_pf_conf}"
## generated by bastille setup
2023-07-14 21:02:14 -06:00
ext_if="$ext_if"
set block-policy return
scrub in on \$ext_if all fragment reassemble
set skip on lo
table <jails> persist
nat on \$ext_if from <jails> to any -> (\$ext_if:0)
rdr-anchor "rdr/*"
block in all
pass out quick keep state
antispoof for \$ext_if inet
pass in proto tcp from any to any port ssh flags S/SA keep state
2023-07-14 21:02:14 -06:00
EOF
sysrc pf_enable=YES
warn "pf ruleset created, please review ${bastille_pf_conf} and enable it using 'service pf start'."
else
2025-05-16 21:48:41 -06:00
info "\nFirewall (pf) has already been configured!"
fi
2023-07-14 21:02:14 -06:00
}
2025-05-15 18:55:00 -06:00
# Configure storage
configure_storage() {
2025-05-19 20:01:59 -06:00
2025-05-16 21:39:16 -06:00
if mount | grep "zfs" >/dev/null 2>/dev/null; then
2025-05-19 20:01:59 -06:00
2025-05-19 20:06:23 -06:00
_auto_zpool="${1}"
2025-05-15 18:55:00 -06:00
if [ ! "$(kldstat -m zfs)" ]; then
2025-05-16 21:48:41 -06:00
info "\nZFS module not loaded; skipping..."
2025-05-15 18:55:00 -06:00
elif sysrc -f ${BASTILLE_CONFIG} -n bastille_zfs_enable | grep -Eoq "([Y|y][E|e][S|s])"; then
2025-05-16 21:48:41 -06:00
info "\nZFS has already been configured!"
2025-05-15 18:55:00 -06:00
else
2025-05-19 20:06:23 -06:00
if [ -z "${_auto_zpool}" ]; then
_zpool_list=$(zpool list | grep -v NAME | awk '{print $1}')
_zpool_count=0
if [ "$(zpool list | grep -v NAME | awk '{print $1}' | wc -l)" -eq 1 ]; then
_bastille_zpool="${_zpool_list}"
2025-05-19 20:01:59 -06:00
else
2025-05-19 20:06:23 -06:00
info "\nMultiple zpools detected:"
for _zpool in ${_zpool_list}; do
echo "[${_zpool_count}] ${_zpool}"
_zpool_num="${_zpool_num} [${_zpool_count}]${_zpool}"
_zpool_count=$(expr ${_zpool_count} + 1)
done
# shellcheck disable=SC3045
read -p "Please select the zpool for Bastille to use: " _zpool_choice
if ! echo "${_zpool_choice}" | grep -Eq "^[0-9]+$"; then
error_exit "Invalid input number, aborting!"
else
_zpool_select=$(echo "${_zpool_num}" | grep -wo "\[${_zpool_choice}\][^ ]*" | sed 's/\[.*\]//g')
fi
2025-05-19 20:01:59 -06:00
fi
2025-05-19 20:06:23 -06:00
else
_bastille_zpool="${_auto_zpool}"
2025-05-15 18:55:00 -06:00
fi
sysrc -f "${BASTILLE_CONFIG}" bastille_zfs_enable=YES
2025-05-19 20:01:59 -06:00
sysrc -f "${BASTILLE_CONFIG}" bastille_zfs_zpool="${_bastille_zpool}"
2025-05-15 18:55:00 -06:00
info "\nUsing ZFS filesystem."
fi
2025-05-16 21:39:16 -06:00
elif mount | grep "ufs" >/dev/null 2>/dev/null; then
2025-05-15 18:55:00 -06:00
info "\nUsing UFS filesystem."
fi
}
# Run all base functions (w/o vnet) if no args
if [ $# -eq 0 ]; then
sysrc bastille_enable=YES
2025-05-17 11:52:04 -06:00
configure_storage
2025-04-22 22:56:14 -06:00
configure_loopback_interface
configure_pf
2025-05-02 08:22:38 -06:00
info "\nBastille has successfully been configured.\n"
exit 0
fi
2025-05-16 18:46:00 -06:00
case "${OPT_CONFIG}" in
2025-05-16 18:29:35 -06:00
pf|firewall)
2025-04-22 11:16:25 -06:00
configure_pf
;;
linux)
if [ "${AUTO_YES}" -eq 1 ]; then
configure_linux
else
warn "[WARNING]: Running linux jails requires loading additional kernel"
warn "modules, as well as installing the 'debootstrap' package."
# shellcheck disable=SC3045
read -p "Do you want to proceed with setup? [y|n]:" _answer
case "${_answer}" in
[Yy]|[Yy][Ee][Ss])
configure_linux
;;
[Nn]|[Nn][Oo])
error_exit "Linux setup cancelled."
;;
*)
error_exit "Invalid selection. Please answer 'y' or 'n'"
;;
esac
fi
;;
2025-05-16 18:29:35 -06:00
netgraph)
2025-05-16 15:32:56 -06:00
if [ "${AUTO_YES}" -eq 1 ]; then
configure_vnet
configure_netgraph
else
warn "[WARNING]: Bastille only allows using either 'if_bridge' or 'netgraph'"
warn "as VNET network options. You CANNOT use both on the same system. If you have"
warn "already started using bastille with 'if_bridge' do not continue."
# shellcheck disable=SC3045
read -p "Do you really want to continue setting up netgraph for Bastille? [y|n]:" _answer
case "${_answer}" in
[Yy]|[Yy][Ee][Ss])
configure_vnet
configure_netgraph
;;
[Nn]|[Nn][Oo])
error_exit "Netgraph setup cancelled."
;;
*)
error_exit "Invalid selection. Please answer 'y' or 'n'"
;;
esac
fi
2025-04-25 14:33:38 -06:00
;;
2025-05-16 18:29:35 -06:00
loopback)
2025-05-16 15:32:56 -06:00
if [ "${AUTO_YES}" -eq 1 ]; then
configure_loopback_interface
else
warn "[WARNING]: Bastille only allows using either the 'loopback' or 'shared'"
warn "interface to be configured ant one time. If you continue, the 'shared'"
warn "interface will be disabled, and the 'loopback' interface will be used as default."
# shellcheck disable=SC3045
read -p "Do you really want to continue setting up the loopback interface? [y|n]:" _answer
case "${_answer}" in
[Yy]|[Yy][Ee][Ss])
configure_loopback_interface
;;
[Nn]|[Nn][Oo])
error_exit "Loopback interface setup cancelled."
;;
*)
error_exit "Invalid selection. Please answer 'y' or 'n'"
;;
esac
fi
;;
2025-05-16 18:29:35 -06:00
shared)
2025-05-16 15:32:56 -06:00
if [ "${AUTO_YES}" -eq 1 ]; then
2025-05-16 18:43:29 -06:00
error_exit "[ERROR]: 'shared' does not support [-y|--yes]."
2025-05-16 15:32:56 -06:00
else
warn "[WARNING]: Bastille only allows using either the 'loopback' or 'shared'"
warn "interface to be configured at one time. If you continue, the 'loopback'"
warn "interface will be disabled, and the shared interface will be used as default."
# shellcheck disable=SC3045
read -p "Do you really want to continue setting up the shared interface? [y|n]:" _answer
case "${_answer}" in
[Yy]|[Yy][Ee][Ss])
2025-05-19 20:06:23 -06:00
configure_shared_interface "${OPT_ARG}"
2025-05-16 15:32:56 -06:00
;;
[Nn]|[Nn][Oo])
error_exit "Shared interface setup cancelled."
;;
*)
error_exit "Invalid selection. Please answer 'y' or 'n'"
;;
esac
fi
2025-04-22 11:16:25 -06:00
;;
2025-05-16 18:29:35 -06:00
storage)
2025-05-19 20:06:23 -06:00
configure_storage "${OPT_ARG}"
2025-04-22 11:16:25 -06:00
;;
2025-05-16 18:29:35 -06:00
vnet)
2025-04-22 11:16:25 -06:00
configure_vnet
;;
2025-05-16 18:29:35 -06:00
bridge)
2025-05-16 15:32:56 -06:00
if [ "${AUTO_YES}" -eq 1 ]; then
2025-05-16 18:43:29 -06:00
error_exit "[ERROR]: 'bridge' does not support [-y|--yes]."
2025-05-16 15:32:56 -06:00
else
configure_vnet
2025-05-19 20:06:23 -06:00
configure_bridge "${OPT_ARG}"
2025-05-16 15:32:56 -06:00
fi
;;
2025-05-01 17:39:50 -06:00
*)
error_exit "[ERROR]: Unknown option: \"${1}\""
;;
2025-05-09 15:11:44 -06:00
esac