Merge pull request #207 from JRGTH/master

Feature add, create empty jail and minor maintenance
This commit is contained in:
Christer Edwards
2020-05-20 09:51:16 -06:00
committed by GitHub
4 changed files with 333 additions and 264 deletions

View File

@@ -3,16 +3,16 @@
##################### #####################
## default paths ## default paths
bastille_prefix=/usr/local/bastille ## default: "/usr/local/bastille" bastille_prefix="/usr/local/bastille" ## default: "/usr/local/bastille"
bastille_backupsdir=${bastille_prefix}/backups ## default: ${bastille_prefix}/backups bastille_backupsdir="${bastille_prefix}/backups" ## default: "${bastille_prefix}/backups"
bastille_cachedir=${bastille_prefix}/cache ## default: ${bastille_prefix}/cache bastille_cachedir="${bastille_prefix}/cache" ## default: "${bastille_prefix}/cache"
bastille_jailsdir=${bastille_prefix}/jails ## default: ${bastille_prefix}/jails bastille_jailsdir="${bastille_prefix}/jails" ## default: "${bastille_prefix}/jails"
bastille_logsdir=${bastille_prefix}/logs ## default: ${bastille_prefix}/logs bastille_logsdir="${bastille_prefix}/logs" ## default: "${bastille_prefix}/logs"
bastille_releasesdir=${bastille_prefix}/releases ## default: ${bastille_prefix}/releases bastille_releasesdir="${bastille_prefix}/releases" ## default: "${bastille_prefix}/releases"
bastille_templatesdir=${bastille_prefix}/templates ## default: ${bastille_prefix}/templates bastille_templatesdir="${bastille_prefix}/templates" ## default: "${bastille_prefix}/templates"
## bastille scripts directory (assumed by bastille pkg) ## bastille scripts directory (assumed by bastille pkg)
bastille_sharedir=/usr/local/share/bastille ## default: "/usr/local/share/bastille" bastille_sharedir="/usr/local/share/bastille" ## default: "/usr/local/share/bastille"
## bootstrap archives (base, lib32, ports, src, test) ## bootstrap archives (base, lib32, ports, src, test)
bastille_bootstrap_archives="base" ## default: "base" bastille_bootstrap_archives="base" ## default: "base"

View File

@@ -36,13 +36,25 @@ usage() {
exit 1 exit 1
} }
error_notify() {
# Notify message on error and exit
echo -e "$*" >&2
exit 1
}
running_jail() { running_jail() {
if [ -n "$(jls name | awk "/^${NAME}$/")" ]; then if [ -n "$(jls name | awk "/^${NAME}$/")" ]; then
echo -e "${COLOR_RED}A running jail matches name.${COLOR_RESET}" error_notify "${COLOR_RED}A running jail matches name.${COLOR_RESET}"
exit 1
elif [ -d "${bastille_jailsdir}/${NAME}" ]; then elif [ -d "${bastille_jailsdir}/${NAME}" ]; then
echo -e "${COLOR_RED}Jail: ${NAME} already created.${COLOR_RESET}" error_notify "${COLOR_RED}Jail: ${NAME} already created.${COLOR_RESET}"
exit 1 fi
}
validate_name() {
local NAME_VERIFY=${NAME}
local NAME_SANITY=$(echo "${NAME_VERIFY}" | tr -c -d 'a-zA-Z0-9-_')
if [ "${NAME_VERIFY}" != "${NAME_SANITY}" ]; then
error_notify "${COLOR_RED}Container names may not contain special characters!${COLOR_RESET}"
fi fi
} }
@@ -72,8 +84,7 @@ validate_ip() {
echo -e "${COLOR_GREEN}Valid: (${IP}).${COLOR_RESET}" echo -e "${COLOR_GREEN}Valid: (${IP}).${COLOR_RESET}"
fi fi
else else
echo -e "${COLOR_RED}Invalid: (${IP}).${COLOR_RESET}" error_notify "${COLOR_RED}Invalid: (${IP}).${COLOR_RESET}"
exit 1
fi fi
fi fi
} }
@@ -83,15 +94,13 @@ validate_netif() {
if echo "${LIST_INTERFACES} VNET" | grep -qwo "${INTERFACE}"; then if echo "${LIST_INTERFACES} VNET" | grep -qwo "${INTERFACE}"; then
echo -e "${COLOR_GREEN}Valid: (${INTERFACE}).${COLOR_RESET}" echo -e "${COLOR_GREEN}Valid: (${INTERFACE}).${COLOR_RESET}"
else else
echo -e "${COLOR_RED}Invalid: (${INTERFACE}).${COLOR_RESET}" error_notify "${COLOR_RED}Invalid: (${INTERFACE}).${COLOR_RESET}"
exit 1
fi fi
} }
validate_netconf() { validate_netconf() {
if [ -n "${bastille_network_loopback}" ] && [ -n "${bastille_network_shared}" ]; then if [ -n "${bastille_network_loopback}" ] && [ -n "${bastille_network_shared}" ]; then
echo -e "${COLOR_RED}Invalid network configuration.${COLOR_RESET}" error_notify "${COLOR_RED}Invalid network configuration.${COLOR_RESET}"
exit 1
fi fi
} }
@@ -104,6 +113,17 @@ validate_release() {
fi fi
} }
generate_minimal_conf() {
cat << EOF > "${bastille_jail_conf}"
${NAME} {
host.hostname = ${NAME};
mount.fstab = ${bastille_jail_fstab};
path = ${bastille_jail_path};
}
EOF
touch "${bastille_jail_fstab}"
}
generate_jail_conf() { generate_jail_conf() {
cat << EOF > "${bastille_jail_conf}" cat << EOF > "${bastille_jail_conf}"
${NAME} { ${NAME} {
@@ -187,18 +207,15 @@ create_jail() {
fi fi
fi fi
else else
mkdir -p "${bastille_jailsdir}/${NAME}" mkdir -p "${bastille_jailsdir}/${NAME}/root"
fi fi
fi fi
if [ -z "${EMPTY_JAIL}" ]; then
if [ ! -d "${bastille_jail_base}" ]; then if [ ! -d "${bastille_jail_base}" ]; then
mkdir -p "${bastille_jail_base}" mkdir -p "${bastille_jail_base}"
fi fi
if [ ! -d "${bastille_jail_path}/usr/home" ]; then
mkdir -p "${bastille_jail_path}/usr/home"
fi
if [ ! -d "${bastille_jail_path}/usr/local" ]; then if [ ! -d "${bastille_jail_path}/usr/local" ]; then
mkdir -p "${bastille_jail_path}/usr/local" mkdir -p "${bastille_jail_path}/usr/local"
fi fi
@@ -247,14 +264,12 @@ create_jail() {
echo echo
if [ -z "${THICK_JAIL}" ]; then if [ -z "${THICK_JAIL}" ]; then
for _link in bin boot lib libexec rescue sbin usr/bin usr/include usr/lib usr/lib32 usr/libdata usr/libexec usr/sbin usr/share usr/src; do LINK_LIST="bin boot lib libexec rescue sbin usr/bin usr/include usr/lib usr/lib32 usr/libdata usr/libexec usr/sbin usr/share usr/src"
for _link in ${LINK_LIST}; do
ln -sf /.bastille/${_link} ${_link} ln -sf /.bastille/${_link} ${_link}
done done
fi fi
## link home properly
ln -s usr/home home
if [ -z "${THICK_JAIL}" ]; then if [ -z "${THICK_JAIL}" ]; then
## rw ## rw
## copy only required files for thin jails ## copy only required files for thin jails
@@ -264,9 +279,8 @@ create_jail() {
cp -a "${bastille_releasesdir}/${RELEASE}/${files}" "${bastille_jail_path}/${files}" cp -a "${bastille_releasesdir}/${RELEASE}/${files}" "${bastille_jail_path}/${files}"
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
## notify and clean stale files/directories ## notify and clean stale files/directories
echo -e "${COLOR_RED}Failed to copy release files, please retry create!${COLOR_RESET}"
bastille destroy "${NAME}" bastille destroy "${NAME}"
exit 1 error_notify "${COLOR_RED}Failed to copy release files, please retry create!${COLOR_RESET}"
fi fi
fi fi
done done
@@ -295,9 +309,8 @@ create_jail() {
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
## notify and clean stale files/directories ## notify and clean stale files/directories
echo -e "${COLOR_RED}Failed release base replication, please retry create!${COLOR_RESET}"
bastille destroy "${NAME}" bastille destroy "${NAME}"
exit 1 error_notify "${COLOR_RED}Failed release base replication, please retry create!${COLOR_RESET}"
fi fi
fi fi
else else
@@ -305,22 +318,36 @@ create_jail() {
cp -a "${bastille_releasesdir}/${RELEASE}/" "${bastille_jail_path}" cp -a "${bastille_releasesdir}/${RELEASE}/" "${bastille_jail_path}"
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
## notify and clean stale files/directories ## notify and clean stale files/directories
echo -e "${COLOR_RED}Failed to copy release files, please retry create!${COLOR_RESET}"
bastille destroy "${NAME}" bastille destroy "${NAME}"
exit 1 error_notify "${COLOR_RED}Failed to copy release files, please retry create!${COLOR_RESET}"
fi fi
fi fi
fi fi
## create home directory if missing
if [ ! -d "${bastille_jail_path}/usr/home" ]; then
mkdir -p "${bastille_jail_path}/usr/home"
fi
## link home properly
if [ ! -L "home" ]; then
ln -s usr/home home
fi
## rc.conf ## rc.conf
## + syslogd_flags="-ss" ## + syslogd_flags="-ss"
## + sendmail_none="NONE" ## + sendmail_enable="NO"
## + sendmail_submit_enable="NO"
## + sendmail_outbound_enable="NO"
## + sendmail_msp_queue_enable="NO"
## + cron_flags="-J 60" ## cedwards 20181118 ## + cron_flags="-J 60" ## cedwards 20181118
if [ ! -f "${bastille_jail_rc_conf}" ]; then if [ ! -f "${bastille_jail_rc_conf}" ]; then
touch "${bastille_jail_rc_conf}" touch "${bastille_jail_rc_conf}"
sysrc -f "${bastille_jail_rc_conf}" syslogd_flags=-ss sysrc -f "${bastille_jail_rc_conf}" syslogd_flags="-ss"
sysrc -f "${bastille_jail_rc_conf}" sendmail_enable=NONE sysrc -f "${bastille_jail_rc_conf}" sendmail_enable="NO"
sysrc -f "${bastille_jail_rc_conf}" cron_flags='-J 60' sysrc -f "${bastille_jail_rc_conf}" sendmail_submit_enable="NO"
sysrc -f "${bastille_jail_rc_conf}" sendmail_outbound_enable="NO"
sysrc -f "${bastille_jail_rc_conf}" sendmail_msp_queue_enable="NO"
sysrc -f "${bastille_jail_rc_conf}" cron_flags="-J 60"
## VNET specific ## VNET specific
if [ -n "${VNET_JAIL}" ]; then if [ -n "${VNET_JAIL}" ]; then
@@ -357,6 +384,10 @@ create_jail() {
## TZ: configurable (default: Etc/UTC) ## TZ: configurable (default: Etc/UTC)
ln -s "/usr/share/zoneinfo/${bastille_tzdata}" etc/localtime ln -s "/usr/share/zoneinfo/${bastille_tzdata}" etc/localtime
else
## Generate minimal configuration for empty jail
generate_minimal_conf
fi
} }
# Handle special-case commands first. # Handle special-case commands first.
@@ -372,6 +403,7 @@ if echo "$3" | grep '@'; then
fi fi
## reset this options ## reset this options
EMPTY_JAIL=""
THICK_JAIL="" THICK_JAIL=""
VNET_JAIL="" VNET_JAIL=""
@@ -384,6 +416,10 @@ if [ "${1}" = "-T" -o "${1}" = "--thick" -o "${1}" = "thick" ] && \
else else
## handle single options ## handle single options
case "${1}" in case "${1}" in
-E|--empty|empty)
shift
EMPTY_JAIL="1"
;;
-T|--thick|thick) -T|--thick|thick)
shift shift
THICK_JAIL="1" THICK_JAIL="1"
@@ -404,16 +440,22 @@ RELEASE="$2"
IP="$3" IP="$3"
INTERFACE="$4" INTERFACE="$4"
if [ -n "${EMPTY_JAIL}" ]; then
if [ $# -ne 1 ]; then
usage
fi
else
if [ $# -gt 4 ] || [ $# -lt 3 ]; then if [ $# -gt 4 ] || [ $# -lt 3 ]; then
usage usage
fi fi
## don't allow for dots(.) in container names
if echo "${NAME}" | grep -q "[.]"; then
echo -e "${COLOR_RED}Container names may not contain a dot(.)!${COLOR_RESET}"
exit 1
fi fi
## validate jail name
if [ -n "${NAME}" ]; then
validate_name
fi
if [ -z "${EMPTY_JAIL}" ]; then
## verify release ## verify release
case "${RELEASE}" in case "${RELEASE}" in
*-RELEASE|*-release|*-RC1|*-rc1|*-RC2|*-rc2) *-RELEASE|*-release|*-RC1|*-rc1|*-RC2|*-rc2)
@@ -454,19 +496,12 @@ esac
## check for name/root/.bastille ## check for name/root/.bastille
if [ -d "${bastille_jailsdir}/${NAME}/root/.bastille" ]; then if [ -d "${bastille_jailsdir}/${NAME}/root/.bastille" ]; then
echo -e "${COLOR_RED}Jail: ${NAME} already created. ${NAME}/root/.bastille exists.${COLOR_RESET}" error_notify "${COLOR_RED}Jail: ${NAME} already created. ${NAME}/root/.bastille exists.${COLOR_RESET}"
exit 1
fi fi
## check for required release ## check for required release
if [ ! -d "${bastille_releasesdir}/${RELEASE}" ]; then if [ ! -d "${bastille_releasesdir}/${RELEASE}" ]; then
echo -e "${COLOR_RED}Release must be bootstrapped first; see 'bastille bootstrap'.${COLOR_RESET}" error_notify "${COLOR_RED}Release must be bootstrapped first; see 'bastille bootstrap'.${COLOR_RESET}"
exit 1
fi
## check if a running jail matches name or already exist
if [ -n "${NAME}" ]; then
running_jail
fi fi
## check if ip address is valid ## check if ip address is valid
@@ -483,5 +518,13 @@ if [ -n "${INTERFACE}" ]; then
else else
validate_netconf validate_netconf
fi fi
else
echo -e "${COLOR_GREEN}Creating empty jail: ${NAME}.${COLOR_RESET}"
fi
## check if a running jail matches name or already exist
if [ -n "${NAME}" ]; then
running_jail
fi
create_jail "${NAME}" "${RELEASE}" "${IP}" "${INTERFACE}" create_jail "${NAME}" "${RELEASE}" "${IP}" "${INTERFACE}"

View File

@@ -42,6 +42,14 @@ error_notify() {
exit 1 exit 1
} }
validate_name() {
local NAME_VERIFY=${NEWNAME}
local NAME_SANITY=$(echo "${NAME_VERIFY}" | tr -c -d 'a-zA-Z0-9-_')
if [ "${NAME_VERIFY}" != "${NAME_SANITY}" ]; then
error_notify "${COLOR_RED}Container names may not contain special characters!${COLOR_RESET}"
fi
}
# Handle special-case commands first # Handle special-case commands first
case "$1" in case "$1" in
help|-h|--help) help|-h|--help)
@@ -57,21 +65,16 @@ TARGET="${1}"
NEWNAME="${2}" NEWNAME="${2}"
shift shift
if echo "${NEWNAME}" | grep -q "[.]"; then
echo -e "${COLOR_RED}Container names may not contain a dot(.)!${COLOR_RESET}"
exit 1
fi
update_jailconf() { update_jailconf() {
# Update jail.conf # Update jail.conf
JAIL_CONFIG="${bastille_jailsdir}/${NEWNAME}/jail.conf" JAIL_CONFIG="${bastille_jailsdir}/${NEWNAME}/jail.conf"
if [ -f "${JAIL_CONFIG}" ]; then if [ -f "${JAIL_CONFIG}" ]; then
if ! grep -qw "path = ${bastille_jailsdir}/${NEWNAME}/root;" "${JAIL_CONFIG}"; then if ! grep -qw "path = ${bastille_jailsdir}/${NEWNAME}/root;" "${JAIL_CONFIG}"; then
sed -i '' "s|host.hostname = ${TARGET};|host.hostname = ${NEWNAME};|" "${JAIL_CONFIG}" sed -i '' "s|host.hostname.*=.*${TARGET};|host.hostname = ${NEWNAME};|" "${JAIL_CONFIG}"
sed -i '' "s|exec.consolelog = .*;|exec.consolelog = ${bastille_logsdir}/${NEWNAME}_console.log;|" "${JAIL_CONFIG}" sed -i '' "s|exec.consolelog.*=.*;|exec.consolelog = ${bastille_logsdir}/${NEWNAME}_console.log;|" "${JAIL_CONFIG}"
sed -i '' "s|path = .*;|path = ${bastille_jailsdir}/${NEWNAME}/root;|" "${JAIL_CONFIG}" sed -i '' "s|path.*=.*;|path = ${bastille_jailsdir}/${NEWNAME}/root;|" "${JAIL_CONFIG}"
sed -i '' "s|mount.fstab = .*;|mount.fstab = ${bastille_jailsdir}/${NEWNAME}/fstab;|" "${JAIL_CONFIG}" sed -i '' "s|mount.fstab.*=.*;|mount.fstab = ${bastille_jailsdir}/${NEWNAME}/fstab;|" "${JAIL_CONFIG}"
sed -i '' "s|${TARGET} {|${NEWNAME} {|" "${JAIL_CONFIG}" sed -i '' "s|${TARGET}.*{|${NEWNAME} {|" "${JAIL_CONFIG}"
fi fi
fi fi
} }
@@ -97,15 +100,34 @@ change_name() {
if [ -d "${bastille_jailsdir}/${TARGET}" ]; then if [ -d "${bastille_jailsdir}/${TARGET}" ]; then
echo -e "${COLOR_GREEN}Attempting to rename '${TARGET}' to ${NEWNAME}...${COLOR_RESET}" echo -e "${COLOR_GREEN}Attempting to rename '${TARGET}' to ${NEWNAME}...${COLOR_RESET}"
if [ "${bastille_zfs_enable}" = "YES" ]; then if [ "${bastille_zfs_enable}" = "YES" ]; then
if [ -n "${bastille_zfs_zpool}" ]; then if [ -n "${bastille_zfs_zpool}" ] && [ -n "${bastille_zfs_prefix}" ]; then
# Rename ZFS dataset and mount points accordingly # Check and rename container ZFS dataset accordingly
# Perform additional checks in case of non-zfs existing containers
if zfs list | grep -qw "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}"; then
zfs rename "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NEWNAME}" zfs rename "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NEWNAME}"
zfs set mountpoint="${bastille_jailsdir}/${NEWNAME}/root" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NEWNAME}/root" else
# Check and rename container directory instead
if ! zfs list | grep -qw "jails/${TARGET}$"; then
mv "${bastille_jailsdir}/${TARGET}" "${bastille_jailsdir}/${NEWNAME}"
fi
fi
fi
else
# Check if container is a zfs/dataset before rename attempt
# Perform additional checks in case of bastille.conf miss-configuration
if zfs list | grep -qw "jails/${TARGET}$"; then
ZFS_DATASET_ORIGIN=$(zfs list | grep -w "jails/${TARGET}$" | awk '{print $1}')
ZFS_DATASET_TARGET=$(echo "${ZFS_DATASET_ORIGIN}" | sed "s|\/${TARGET}||")
if [ -n "${ZFS_DATASET_ORIGIN}" ] && [ -n "${ZFS_DATASET_TARGET}" ]; then
zfs rename "${ZFS_DATASET_ORIGIN}" "${ZFS_DATASET_TARGET}/${NEWNAME}"
else
error_notify "${COLOR_RED}Can't determine the zfs origin path of '${TARGET}'.${COLOR_RESET}"
fi fi
else else
# Just rename the jail directory # Just rename the jail directory
mv "${bastille_jailsdir}/${TARGET}" "${bastille_jailsdir}/${NEWNAME}" mv "${bastille_jailsdir}/${TARGET}" "${bastille_jailsdir}/${NEWNAME}"
fi fi
fi
else else
error_notify "${COLOR_RED}${TARGET} not found. See bootstrap.${COLOR_RESET}" error_notify "${COLOR_RED}${TARGET} not found. See bootstrap.${COLOR_RESET}"
fi fi
@@ -114,10 +136,7 @@ change_name() {
update_jailconf update_jailconf
update_fstab update_fstab
# Remove the old jail directory if exist # Check exit status and notify
if [ -d "${bastille_jailsdir}/${TARGET}" ]; then
rm -r "${bastille_jailsdir}/${TARGET}"
fi
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
error_notify "${COLOR_RED}An error has occurred while attempting to rename '${TARGET}'.${COLOR_RESET}" error_notify "${COLOR_RED}An error has occurred while attempting to rename '${TARGET}'.${COLOR_RESET}"
else else
@@ -125,9 +144,16 @@ change_name() {
fi fi
} }
# Check if container is running ## check if a running jail matches name or already exist
if [ -n "$(jls name | awk "/^${TARGET}$/")" ]; then if [ "$(jls name | awk "/^${TARGET}$/")" ]; then
error_notify "${COLOR_RED}${TARGET} is running, See 'bastille stop'.${COLOR_RESET}" error_notify "${COLOR_RED}Warning: ${TARGET} is running or the name does match.${COLOR_RESET}"
elif [ -d "${bastille_jailsdir}/${NEWNAME}" ]; then
error_notify "${COLOR_RED}Jail: ${NEWNAME} already exist.${COLOR_RESET}"
fi
## validate jail name
if [ -n "${NEWNAME}" ]; then
validate_name
fi fi
change_name change_name