diff --git a/README.md b/README.md index f4bba938..b94d3f96 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Available Commands: bootstrap Bootstrap a FreeBSD release for container base. clone Clone an existing container. cmd Execute arbitrary command on targeted container(s). + config Get or set a config value for the targeted container(s). console Console into a running container. convert Convert a thin container into a thick container. cp cp(1) files from host to targeted container(s). @@ -71,14 +72,14 @@ Available Commands: update Update container base -pX release. upgrade Upgrade container release to X.Y-RELEASE. verify Verify bootstrapped release or automation template. - zfs Manage (get|set) zfs attributes on targeted container(s). + zfs Manage (get|set) ZFS attributes on targeted container(s). Use "bastille -v|--version" for version information. Use "bastille command -h|--help" for more information about a command. ``` -## 0.7-beta +## 0.8-beta This document outlines the basic usage of the Bastille container management framework. This release is still considered beta. @@ -367,10 +368,6 @@ VNET also requires a custom `devfs` ruleset. Create the file as needed on the ho **/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 path 'bpf*' unhide ``` @@ -678,9 +675,10 @@ Note: SYSRC requires NO quotes or that quotes (`"`) be escaped. ie; `\"`) Any name provided in the ARG file can be used as a variable in the other hooks. For example, `name=value` in the ARG file will cause instances of `${name}` -to be replaced with `value`. The `RENDER` hook can be used to specify files or -directories whose contents should have the variables replaced. Values can be specified -either through the command line when applying the template or as a default in the ARG file. +to be replaced with `value`. The `RENDER` hook can be used to specify existing files or +directories inside the jail whose contents should have the variables replaced. Values can be +specified either through the command line when applying the template or as a default in the ARG +file. In addition to supporting template hooks, Bastille supports overlaying files into the container. This is done by placing the files in their full path, using the @@ -716,7 +714,8 @@ followed by its arguments (omitting the target, which is deduced from the Variables can also be defined using `ARG` with one `name=value` pair per line. Subsequent references to `${name}` would be replaced by `value`. Note that argument values are not available for use until after the point -at which they are defined in the file. +at which they are defined in the file. Both `${JAIL_NAME}` and `${JAIL_IP}` +are made available in templates without having to define them as args. Bastillefile example: @@ -747,6 +746,11 @@ CMD hostname > /usr/local/www/nginx-dist/hostname.txt RDR tcp 80 80 ``` +Use the following command to convert a hook-based template into the Bastillefile format: +```shell +bastille template --convert my-template +``` + Applying Templates ------------------ @@ -943,7 +947,7 @@ validation are not used. bastille zfs ------------ -This sub-command allows managing zfs attributes for the targeted container(s). +This sub-command allows managing ZFS attributes for the targeted container(s). Common usage includes setting container quotas. **set quota** @@ -969,7 +973,7 @@ Note: On UFS systems containers must be stopped before export. ```shell ishmael ~ # bastille export folsom Exporting 'folsom' to a compressed .xz archive. -Sending zfs data stream... +Sending ZFS data stream... 100 % 1057.2 KiB / 9231.5 KiB = 0.115 0:01 Exported '/usr/local/bastille/jails/backups/folsom_2020-01-26-19:23:04.xz' successfully. @@ -984,7 +988,7 @@ ishmael ~ # bastille import folsom_2020-01-26-19:22:23.xz Validating file: folsom_2020-01-26-19:22:23.xz... File validation successful! Importing 'folsom' from compressed .xz archive. -Receiving zfs data stream... +Receiving ZFS data stream... /usr/local/bastille/jails/backups/folsom_2020-01-26-19:22:23.xz (1/1) 100 % 626.4 KiB / 9231.5 KiB = 0.068 0:02 Container 'folsom' imported successfully. diff --git a/docs/chapters/installation.rst b/docs/chapters/installation.rst index 19b89c85..25c1c852 100644 --- a/docs/chapters/installation.rst +++ b/docs/chapters/installation.rst @@ -4,7 +4,7 @@ Bastille is available in the official FreeBSD ports tree at `sysutils/bastille`. Binary packages available in `quarterly` and `latest` repositories. -Current version is `0.7.20200714`. +Current version is `0.8.20210101`. To install from the FreeBSD package repository: diff --git a/docs/chapters/networking.rst b/docs/chapters/networking.rst index 6a4cc3e9..fb52e8a8 100644 --- a/docs/chapters/networking.rst +++ b/docs/chapters/networking.rst @@ -76,10 +76,6 @@ host system: ## /etc/devfs.rules (NOT .conf) [bastille_vnet=13] - add include $devfsrules_hide_all - add include $devfsrules_unhide_basic - add include $devfsrules_unhide_login - add include $devfsrules_jail add path 'bpf*' unhide Lastly, you may want to consider these three `sysctl` values: @@ -90,6 +86,29 @@ Lastly, you may want to consider these three `sysctl` values: net.link.bridge.pfil_onlyip=0 net.link.bridge.pfil_member=0 +**Regarding Routes** + +Bastille will attempt to auto-detect the default route from the host system and +assign it to the VNET container. This auto-detection may not always be accurate +for your needs for the particular container. In this case you'll need to add +a default route manually or define the preferred default route in the +`bastille.conf`. + +.. code-block:: shell + + bastille sysrc TARGET defaultrouter=aa.bb.cc.dd + bastille service TARGET routing restart + +To define a default route / gateway for all VNET containers define the value in +`bastille.conf`: + +.. code-block:: shell + + bastille_network_gateway=aa.bb.cc.dd + +This config change will apply the defined gateway to any new containers. +Existing containers will need to be manually updated. + Public Network ============== diff --git a/docs/chapters/usage.rst b/docs/chapters/usage.rst index e6f4f78a..fb6b9e55 100644 --- a/docs/chapters/usage.rst +++ b/docs/chapters/usage.rst @@ -14,6 +14,7 @@ Usage bootstrap Bootstrap a FreeBSD release for container base. cmd Execute arbitrary command on targeted container(s). clone Clone an existing container. + config Get or set a config value for the targeted container(s). console Console into a running container. convert Convert a Thin container into a Thick container. cp cp(1) files from host to targeted container(s). @@ -24,6 +25,7 @@ Usage help Help about any command. htop Interactive process viewer (requires htop). import Import a specified container. + limits Apply resources limits to targeted container(s). See rctl(8). list List containers (running and stopped). mount Mount a volume inside the targeted container(s). pkg Manipulate binary packages within targeted container(s). See pkg(8). @@ -40,7 +42,7 @@ Usage update Update container base -pX release. upgrade Upgrade container release to X.Y-RELEASE. verify Compare release against a "known good" index. - zfs Manage (get|set) zfs attributes on targeted container(s). + zfs Manage (get|set) ZFS attributes on targeted container(s). Use "bastille -v|--version" for version information. Use "bastille command -h|--help" for more information about a command. diff --git a/docs/conf.py b/docs/conf.py index e8d83fbe..ca3c958e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,9 +12,9 @@ copyright = '2018-2020, Christer Edwards' author = 'Christer Edwards' # The short X.Y version -version = '0.7.20200714' +version = '0.8.20210101' # The full version, including alpha/beta/rc tags -release = '0.7.20200714-beta' +release = '0.8.20210101-beta' # -- General configuration --------------------------------------------------- diff --git a/usr/local/bin/bastille b/usr/local/bin/bastille index 62b97bb7..46ec8f2d 100755 --- a/usr/local/bin/bastille +++ b/usr/local/bin/bastille @@ -70,7 +70,7 @@ bastille_perms_check() { bastille_perms_check ## version -BASTILLE_VERSION="0.7.20200714" +BASTILLE_VERSION="0.8.20210101" usage() { cat << EOF @@ -84,6 +84,7 @@ Available Commands: bootstrap Bootstrap a FreeBSD release for container base. cmd Execute arbitrary command on targeted container(s). clone Clone an existing container. + config Get or set a config value for the targeted container(s). console Console into a running container. convert Convert a Thin container into a Thick container. cp cp(1) files from host to targeted container(s). @@ -94,6 +95,7 @@ Available Commands: help Help about any command. htop Interactive process viewer (requires htop). import Import a specified container. + limits Apply resources limits to targeted container(s). See rctl(8). list List containers (running and stopped). mount Mount a volume inside the targeted container(s). pkg Manipulate binary packages within targeted container(s). See pkg(8). @@ -110,7 +112,7 @@ Available Commands: update Update container base -pX release. upgrade Upgrade container release to X.Y-RELEASE. verify Compare release against a "known good" index. - zfs Manage (get|set) zfs attributes on targeted container(s). + zfs Manage (get|set) ZFS attributes on targeted container(s). Use "bastille -v|--version" for version information. Use "bastille command -h|--help" for more information about a command. @@ -127,7 +129,7 @@ shift # Handle special-case commands first. case "${CMD}" in version|-v|--version) - echo -e "${COLOR_GREEN}${BASTILLE_VERSION}${COLOR_RESET}" + info "${BASTILLE_VERSION}" exit 0 ;; help|-h|--help) @@ -136,7 +138,7 @@ help|-h|--help) bootstrap|create|destroy|import|list|rdr|restart|start|update|upgrade|verify) # Nothing "extra" to do for these commands. -- cwells ;; -clone|cmd|console|convert|cp|edit|export|htop|limits|mount|pkg|rename|service|stop|sysrc|template|top|umount|zfs) +clone|config|cmd|console|convert|cp|edit|export|htop|limits|mount|pkg|rename|service|stop|sysrc|template|top|umount|zfs) # Parse the target and ensure it exists. -- cwells if [ $# -eq 0 ]; then # No target was given, so show the command's help. -- cwells PARAMS='help' @@ -153,8 +155,11 @@ clone|cmd|console|convert|cp|edit|export|htop|limits|mount|pkg|rename|service|st JAILS="${JAILS} ${_jail}" fi done + elif [ "${CMD}" = 'template' ] && [ "${TARGET}" = '--convert' ]; then + # This command does not act on a jail, so we are temporarily bypassing the presence/started + # checks. The command will simply convert a template from hooks to a Bastillefile. -- cwells else - JAILS=$(jls name | awk "/^${TARGET}$/") + JAILS="${TARGET}" # Ensure the target exists. -- cwells if [ ! -d "${bastille_jailsdir}/${TARGET}" ]; then diff --git a/usr/local/etc/bastille/bastille.conf.sample b/usr/local/etc/bastille/bastille.conf.sample index e7bbf5dc..a47da946 100644 --- a/usr/local/etc/bastille/bastille.conf.sample +++ b/usr/local/etc/bastille/bastille.conf.sample @@ -48,3 +48,10 @@ bastille_decompress_xz_options="-c -d -v" ## default bastille_network_loopback="bastille0" ## default: "bastille0" bastille_network_shared="" ## default: "" bastille_network_gateway="" ## default: "" + +## Default Templates +bastille_template_base="default/base" ## default: "default/base" +bastille_template_empty="default/empty" ## default: "default/empty" +bastille_template_thick="default/thick" ## default: "default/thick" +bastille_template_thin="default/thin" ## default: "default/thin" +bastille_template_vnet="default/vnet" ## default: "default/vnet" diff --git a/usr/local/share/bastille/bootstrap.sh b/usr/local/share/bastille/bootstrap.sh index 7608cc1d..504ddae6 100644 --- a/usr/local/share/bastille/bootstrap.sh +++ b/usr/local/share/bastille/bootstrap.sh @@ -42,7 +42,21 @@ help|-h|--help) ;; esac -# Validate ZFS parameters first. +#Validate if ZFS is enabled in rc.conf and bastille.conf. +if [ "$(sysrc -n zfs_enable)" = "YES" ] && [ ! "${bastille_zfs_enable}" = "YES" ]; then + warn "ZFS is enabled in rc.conf but not bastille.conf. Do you want to continue? (N|y)" + read answer + case $answer in + no|No|n|N|"") + error_exit "ERROR: Missing ZFS parameters. See bastille_zfs_enable." + ;; + yes|Yes|y|Y) + continue + ;; + esac +fi + +# Validate ZFS parameters. if [ "${bastille_zfs_enable}" = "YES" ]; then ## check for the ZFS pool and bastille prefix if [ -z "${bastille_zfs_zpool}" ]; then @@ -68,7 +82,7 @@ validate_release_url() { if ! fetch -qo /dev/null "${UPSTREAM_URL}/MANIFEST" 2>/dev/null; then error_exit "Unable to fetch MANIFEST. See 'bootstrap urls'." fi - echo -e "${COLOR_GREEN}Bootstrapping ${PLATFORM_OS} distfiles...${COLOR_RESET}" + info "Bootstrapping ${PLATFORM_OS} distfiles..." # Alternate RELEASE/ARCH fetch support if [ "${OPTION}" = "--i386" -o "${OPTION}" = "--32bit" ]; then @@ -164,6 +178,7 @@ bootstrap_directories() { else mkdir -p "${bastille_templatesdir}" fi + ln -s "${bastille_sharedir}/templates/default" "${bastille_templatesdir}/default" fi ## ${bastille_releasesdir} @@ -203,7 +218,7 @@ bootstrap_release() { if [ -z "${bastille_bootstrap_archives}" ]; then error_exit "Bootstrap appears complete." else - echo -e "${COLOR_GREEN}Bootstrapping additional distfiles...${COLOR_RESET}" + info "Bootstrapping additional distfiles..." fi fi @@ -211,7 +226,7 @@ bootstrap_release() { ## check if the dist files already exists then extract FETCH_VALIDATION="0" if [ -f "${bastille_cachedir}/${RELEASE}/${_archive}.txz" ]; then - echo -e "${COLOR_GREEN}Extracting ${PLATFORM_OS} ${RELEASE} ${_archive}.txz.${COLOR_RESET}" + info "Extracting ${PLATFORM_OS} ${RELEASE} ${_archive}.txz." if /usr/bin/tar -C "${bastille_releasesdir}/${RELEASE}" -xf "${bastille_cachedir}/${RELEASE}/${_archive}.txz"; then ## silence motd at container login touch "${bastille_releasesdir}/${RELEASE}/root/.hushlogin" @@ -267,15 +282,15 @@ bootstrap_release() { rm "${bastille_cachedir}/${RELEASE}/${_archive}.txz" error_exit "Failed validation for ${_archive}.txz. Please retry bootstrap!" else - echo -e "${COLOR_GREEN}Validated checksum for ${RELEASE}:${_archive}.txz.${COLOR_RESET}" - echo -e "${COLOR_GREEN}MANIFEST:${SHA256_DIST}${COLOR_RESET}" - echo -e "${COLOR_GREEN}DOWNLOAD:${SHA256_FILE}${COLOR_RESET}" + info "Validated checksum for ${RELEASE}: ${_archive}.txz" + info "MANIFEST: ${SHA256_DIST}" + info "DOWNLOAD: ${SHA256_FILE}" fi fi ## extract the fetched dist files if [ -f "${bastille_cachedir}/${RELEASE}/${_archive}.txz" ]; then - echo -e "${COLOR_GREEN}Extracting ${PLATFORM_OS} ${RELEASE} ${_archive}.txz.${COLOR_RESET}" + info "Extracting ${PLATFORM_OS} ${RELEASE} ${_archive}.txz." if /usr/bin/tar -C "${bastille_releasesdir}/${RELEASE}" -xf "${bastille_cachedir}/${RELEASE}/${_archive}.txz"; then ## silence motd at container login touch "${bastille_releasesdir}/${RELEASE}/root/.hushlogin" @@ -288,8 +303,8 @@ bootstrap_release() { done echo - echo -e "${COLOR_GREEN}Bootstrap successful.${COLOR_RESET}" - echo -e "${COLOR_GREEN}See 'bastille --help' for available commands.${COLOR_RESET}" + info "Bootstrap successful." + info "See 'bastille --help' for available commands." echo } @@ -304,6 +319,7 @@ bootstrap_template() { else mkdir -p "${bastille_templatesdir}" fi + ln -s "${bastille_sharedir}/templates/default" "${bastille_templatesdir}/default" fi ## define basic variables diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index e3badf25..bc9c34e6 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -54,7 +54,7 @@ validate_ip() { IP6_MODE="disable" ip6=$(echo "${IP}" | grep -E '^(([a-fA-F0-9:]+$)|([a-fA-F0-9:]+\/[0-9]{1,3}$))') if [ -n "${ip6}" ]; then - echo -e "${COLOR_GREEN}Valid: (${ip6}).${COLOR_RESET}" + info "Valid: (${ip6})." IPX_ADDR="ip6.addr" IP6_MODE="new" else @@ -69,9 +69,9 @@ validate_ip() { fi done if ifconfig | grep -qw "${TEST_IP}"; then - echo -e "${COLOR_YELLOW}Warning: ip address already in use (${TEST_IP}).${COLOR_RESET}" + warn "Warning: IP address already in use (${TEST_IP})." else - echo -e "${COLOR_GREEN}Valid: (${IP}).${COLOR_RESET}" + info "Valid: (${IP})." fi else error_exit "Invalid: (${IP})." @@ -144,7 +144,7 @@ update_fstab() { clone_jail() { # Attempt container clone - echo -e "${COLOR_GREEN}Attempting to clone '${TARGET}' to ${NEWNAME}...${COLOR_RESET}" + info "Attempting to clone '${TARGET}' to ${NEWNAME}..." if ! [ -d "${bastille_jailsdir}/${NEWNAME}" ]; then if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then @@ -183,7 +183,7 @@ clone_jail() { if [ "$?" -ne 0 ]; then error_exit "An error has occurred while attempting to clone '${TARGET}'." else - echo -e "${COLOR_GREEN}Cloned '${TARGET}' to '${NEWNAME}' successfully.${COLOR_RESET}" + info "Cloned '${TARGET}' to '${NEWNAME}' successfully." fi } diff --git a/usr/local/share/bastille/cmd.sh b/usr/local/share/bastille/cmd.sh index dcb63506..3ebc1ad3 100644 --- a/usr/local/share/bastille/cmd.sh +++ b/usr/local/share/bastille/cmd.sh @@ -46,7 +46,7 @@ if [ $# -eq 0 ]; then fi for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" jexec -l "${_jail}" "$@" echo done diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index 285b843e..4dd30c1a 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -40,3 +40,11 @@ error_exit() { error_notify $@ exit 1 } + +info() { + echo -e "${COLOR_GREEN}$*${COLOR_RESET}" +} + +warn() { + echo -e "${COLOR_YELLOW}$*${COLOR_RESET}" +} diff --git a/usr/local/share/bastille/config.sh b/usr/local/share/bastille/config.sh new file mode 100644 index 00000000..42f0160c --- /dev/null +++ b/usr/local/share/bastille/config.sh @@ -0,0 +1,115 @@ +#!/bin/sh +# +# Copyright (c) 2018-2020, Christer Edwards +# 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 +. /usr/local/etc/bastille/bastille.conf + +usage() { + error_exit "Usage: bastille config TARGET get|set propertyName [newValue]" +} + +# Handle special-case commands first. +case "$1" in +help|-h|--help) + usage + ;; +esac + +if [ $# -eq 1 ] || [ $# -gt 3 ]; then + usage +fi + +ACTION=$1 +shift + +case $ACTION in + get) + if [ $# -ne 1 ]; then + error_notify 'Too many parameters for a "get" operation.' + usage + fi + ;; + set) ;; + *) error_exit 'Only get and set are supported.' ;; +esac + +PROPERTY=$1 +shift +VALUE="$@" + +for _jail in ${JAILS}; do + FILE="${bastille_jailsdir}/${_jail}/jail.conf" + if [ ! -f "${FILE}" ]; then + error_notify "jail.conf does not exist for jail: ${_jail}" + continue + fi + + ESCAPED_PROPERTY=$(echo "${PROPERTY}" | sed 's/\./\\\./g') + MATCH_LINE=$(grep "^[[:blank:]]*${ESCAPED_PROPERTY}[[:blank:]=;]" "${FILE}" 2>/dev/null) + MATCH_FOUND=$? + + if [ "${ACTION}" = 'get' ]; then + if [ $MATCH_FOUND -ne 0 ]; then + warn "not set" + elif ! echo "${MATCH_LINE}" | grep '=' > /dev/null 2>&1; then + echo "enabled" + else + VALUE=$(echo "${MATCH_LINE}" | sed -E 's/.+= *(.+) *;$/\1/' 2>/dev/null) + if [ $? -ne 0 ]; then + error_notify "Failed to get value." + else + echo "${VALUE}" + fi + fi + else # Setting the value. -- cwells + if [ -n "${VALUE}" ]; then + VALUE=$(echo "${VALUE}" | sed 's/\//\\\//g') + if echo "${VALUE}" | grep ' ' > /dev/null 2>&1; then # Contains a space, so wrap in quotes. -- cwells + VALUE="'${VALUE}'" + fi + LINE=" ${PROPERTY} = ${VALUE};" + else + LINE=" ${PROPERTY};" + fi + + if [ $MATCH_FOUND -ne 0 ]; then # No match, so insert the property at the end. -- cwells + echo "$(awk -v line="${LINE}" '$0 == "}" { print line; } 1 { print $0; }' "${FILE}")" > "${FILE}" + else # Replace the existing value. -- cwells + sed -i '' -E "s/ *${ESCAPED_PROPERTY}[ =;].*/${LINE}/" "${FILE}" + fi + fi +done + +# Only display this message once at the end (not for every jail). -- cwells +if [ "${ACTION}" = 'set' ]; then + info "A restart is required for the changes to be applied. See 'bastille restart ${TARGET}'." +fi + +exit 0 diff --git a/usr/local/share/bastille/console.sh b/usr/local/share/bastille/console.sh index 149291d1..baec8da6 100644 --- a/usr/local/share/bastille/console.sh +++ b/usr/local/share/bastille/console.sh @@ -29,6 +29,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. . /usr/local/share/bastille/common.sh +. /usr/local/etc/bastille/bastille.conf usage() { error_exit "Usage: bastille console TARGET [user]'" @@ -64,12 +65,22 @@ validate_user() { fi } +check_fib() { + fib=$(grep 'exec.fib' "${bastille_jailsdir}/${_jail}/jail.conf" | awk '{print $3}' | sed 's/\;//g') + if [ -n "${fib}" ]; then + _setfib="setfib -F ${fib}" + else + _setfib="" + fi +} + for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" if [ -n "${USER}" ]; then validate_user else - jexec -l "${_jail}" /usr/bin/login -f root + check_fib + ${_setfib} jexec -l "${_jail}" /usr/bin/login -f root fi echo done diff --git a/usr/local/share/bastille/convert.sh b/usr/local/share/bastille/convert.sh index 7ecc76cf..29aa7af7 100644 --- a/usr/local/share/bastille/convert.sh +++ b/usr/local/share/bastille/convert.sh @@ -101,7 +101,7 @@ revert_convert() { start_convert() { # Attempt container conversion and handle some errors if [ -d "${bastille_jailsdir}/${TARGET}" ]; then - echo -e "${COLOR_GREEN}Converting '${TARGET}' into a thickjail, this may take a while...${COLOR_RESET}" + info "Converting '${TARGET}' into a thickjail. This may take a while..." # Set some variables RELEASE=$(grep -owE '([1-9]{2,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-2])|([0-9]{1,2}-stable-build-[0-9]{1,3})|(current-build)-([0-9]{1,3})|(current-BUILD-LATEST)|([0-9]{1,2}-stable-BUILD-LATEST)|(current-BUILD-LATEST)' "${bastille_jailsdir}/${TARGET}/fstab") @@ -118,7 +118,7 @@ start_convert() { sed -i '' -E "s|${FSTABMOD}|# Converted from thin to thick container on $(date)|g" "${bastille_jailsdir}/${TARGET}/fstab" mv "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/root/.bastille.old" - echo -e "${COLOR_GREEN}Conversion of '${TARGET}' completed successfully!${COLOR_RESET}" + info "Conversion of '${TARGET}' completed successfully!" exit 0 else error_exit "Can't determine release version. See 'bastille bootstrap'." diff --git a/usr/local/share/bastille/cp.sh b/usr/local/share/bastille/cp.sh index 8c59ba69..0ed44734 100644 --- a/usr/local/share/bastille/cp.sh +++ b/usr/local/share/bastille/cp.sh @@ -50,8 +50,8 @@ CPSOURCE="${1}" CPDEST="${2}" for _jail in ${JAILS}; do - bastille_jail_path="$(jls -j "${_jail}" path)" - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" + bastille_jail_path="${bastille_jailsdir}/${_jail}/root" cp -av "${CPSOURCE}" "${bastille_jail_path}/${CPDEST}" RETURN="$?" if [ "${TARGET}" = "ALL" ]; then diff --git a/usr/local/share/bastille/create.sh b/usr/local/share/bastille/create.sh index 8e69a0c8..1be81266 100644 --- a/usr/local/share/bastille/create.sh +++ b/usr/local/share/bastille/create.sh @@ -56,7 +56,7 @@ validate_ip() { IP6_MODE="disable" ip6=$(echo "${IP}" | grep -E '^(([a-fA-F0-9:]+$)|([a-fA-F0-9:]+\/[0-9]{1,3}$))') if [ -n "${ip6}" ]; then - echo -e "${COLOR_GREEN}Valid: (${ip6}).${COLOR_RESET}" + info "Valid: (${ip6})." IPX_ADDR="ip6.addr" IP6_MODE="new" else @@ -72,9 +72,9 @@ validate_ip() { fi done if ifconfig | grep -qw "${TEST_IP}"; then - echo -e "${COLOR_YELLOW}Warning: ip address already in use (${TEST_IP}).${COLOR_RESET}" + warn "Warning: IP address already in use (${TEST_IP})." else - echo -e "${COLOR_GREEN}Valid: (${IP}).${COLOR_RESET}" + info "Valid: (${IP})." fi else error_exit "Invalid: (${IP})." @@ -85,7 +85,7 @@ validate_ip() { validate_netif() { local LIST_INTERFACES=$(ifconfig -l) if echo "${LIST_INTERFACES} VNET" | grep -qwo "${INTERFACE}"; then - echo -e "${COLOR_GREEN}Valid: (${INTERFACE}).${COLOR_RESET}" + info "Valid: (${INTERFACE})." else error_exit "Invalid: (${INTERFACE})." fi @@ -248,12 +248,12 @@ create_jail() { ## MAKE SURE WE'RE IN THE RIGHT PLACE cd "${bastille_jail_path}" echo - echo -e "${COLOR_GREEN}NAME: ${NAME}.${COLOR_RESET}" - echo -e "${COLOR_GREEN}IP: ${IP}.${COLOR_RESET}" + info "NAME: ${NAME}." + info "IP: ${IP}." if [ -n "${INTERFACE}" ]; then - echo -e "${COLOR_GREEN}INTERFACE: ${INTERFACE}.${COLOR_RESET}" + info "INTERFACE: ${INTERFACE}." fi - echo -e "${COLOR_GREEN}RELEASE: ${RELEASE}.${COLOR_RESET}" + info "RELEASE: ${RELEASE}." echo if [ -z "${THICK_JAIL}" ]; then @@ -278,7 +278,7 @@ create_jail() { fi done else - echo -e "${COLOR_GREEN}Creating a thickjail, this may take a while...${COLOR_RESET}" + info "Creating a thickjail. This may take a while..." if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then ## perform release base replication @@ -326,71 +326,68 @@ create_jail() { ln -s usr/home home fi - ## rc.conf - ## + syslogd_flags="-ss" - ## + sendmail_enable="NO" - ## + sendmail_submit_enable="NO" - ## + sendmail_outbound_enable="NO" - ## + sendmail_msp_queue_enable="NO" - ## + cron_flags="-J 60" ## cedwards 20181118 - if [ ! -f "${bastille_jail_rc_conf}" ]; then - touch "${bastille_jail_rc_conf}" - sysrc -f "${bastille_jail_rc_conf}" syslogd_flags="-ss" - sysrc -f "${bastille_jail_rc_conf}" sendmail_enable="NO" - 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" + ## TZ: configurable (default: Etc/UTC) + ln -s "/usr/share/zoneinfo/${bastille_tzdata}" etc/localtime - ## VNET specific - if [ -n "${VNET_JAIL}" ]; then - ## rename interface to generic vnet0 - uniq_epair=$(grep vnet.interface "${bastille_jailsdir}/${NAME}/jail.conf" | awk '{print $3}' | sed 's/;//') - /usr/sbin/sysrc -f "${bastille_jail_rc_conf}" "ifconfig_${uniq_epair}_name"=vnet0 + # Post-creation jail misc configuration + # Create a dummy fstab file + touch "etc/fstab" + # Disables adjkerntz, avoids spurious error messages + sed -i '' 's|[0-9],[0-9]\{2\}.*[0-9]-[0-9].*root.*kerntz -a|#& # Disabled by bastille|' "etc/crontab" - ## if 0.0.0.0 set DHCP - ## else set static address - if [ "${IP}" == "0.0.0.0" ]; then - /usr/sbin/sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="SYNCDHCP" - else - /usr/sbin/sysrc -f "${bastille_jail_rc_conf}" ifconfig_vnet0="inet ${IP}" - if [ -n "${bastille_network_gateway}" ]; then - /usr/sbin/sysrc -f "${bastille_jail_rc_conf}" defaultrouter="${bastille_network_gateway}" - else - /usr/sbin/sysrc -f "${bastille_jail_rc_conf}" defaultrouter="$(netstat -rn | awk '/default/ {print $2}')" - fi - fi - - ## VNET requires jib script - if [ ! "$(command -v jib)" ]; then - if [ -f /usr/share/examples/jails/jib ] && [ ! -f /usr/local/bin/jib ]; then - install -m 0544 /usr/share/examples/jails/jib /usr/local/bin/jib - fi + ## VNET specific + if [ -n "${VNET_JAIL}" ]; then + ## VNET requires jib script + if [ ! "$(command -v jib)" ]; then + if [ -f /usr/share/examples/jails/jib ] && [ ! -f /usr/local/bin/jib ]; then + install -m 0544 /usr/share/examples/jails/jib /usr/local/bin/jib fi fi fi - - ## resolv.conf (default: copy from host) - if [ ! -f "${bastille_jail_resolv_conf}" ]; then - cp -L "${bastille_resolv_conf}" "${bastille_jail_resolv_conf}" - fi - - ## TZ: configurable (default: Etc/UTC) - ln -s "/usr/share/zoneinfo/${bastille_tzdata}" etc/localtime else ## Generate minimal configuration for empty jail generate_minimal_conf fi - # Post-creation jail misc configuration - # Creates a dummy fstab file - # Disables adjkerntz, avoids spurious error messages # Set strict permissions on the jail by default - if [ -z "${EMPTY_JAIL}" ]; then - touch "etc/fstab" - sed -i '' 's|[0-9],[0-9]\{2\}.*[0-9]-[0-9].*root.*kerntz -a|#& # Disabled by bastille|' "etc/crontab" - fi chmod 0700 "${bastille_jailsdir}/${NAME}" + + # Jail must be started before applying the default template. -- cwells + bastille start "${NAME}" + + if [ -n "${VNET_JAIL}" ]; then + if [ -n ${bastille_template_vnet} ]; then + ## rename interface to generic vnet0 + uniq_epair=$(grep vnet.interface "${bastille_jailsdir}/${NAME}/jail.conf" | awk '{print $3}' | sed 's/;//') + + _gateway='' + _ifconfig=SYNCDHCP + if [ "${IP}" != "0.0.0.0" ]; then # not using DHCP, so set static address. + _ifconfig="inet ${IP}" + if [ -n "${bastille_network_gateway}" ]; then + _gateway="${bastille_network_gateway}" + else + _gateway="$(netstat -rn | awk '/default/ {print $2}')" + fi + fi + bastille template "${NAME}" ${bastille_template_vnet} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" --arg EPAIR="${uniq_epair}" --arg GATEWAY="${_gateway}" --arg IFCONFIG="${_ifconfig}" + fi + elif [ -n "${THICK_JAIL}" ]; then + if [ -n ${bastille_template_thick} ]; then + bastille template "${NAME}" ${bastille_template_thick} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" + fi + elif [ -n "${EMPTY_JAIL}" ]; then + if [ -n ${bastille_template_empty} ]; then + bastille template "${NAME}" ${bastille_template_empty} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" + fi + else # Thin jail. + if [ -n ${bastille_template_thin} ]; then + bastille template "${NAME}" ${bastille_template_thin} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" + fi + fi + + # Apply values changed by the template. -- cwells + bastille restart "${NAME}" } # Handle special-case commands first. @@ -520,14 +517,14 @@ if [ -z "${EMPTY_JAIL}" ]; then fi ## check if interface is valid - if [ -n "${INTERFACE}" ]; then + if [ -n "${INTERFACE}" ]; then validate_netif validate_netconf else validate_netconf fi else - echo -e "${COLOR_GREEN}Creating empty jail: ${NAME}.${COLOR_RESET}" + info "Creating empty jail: ${NAME}." fi ## check if a running jail matches name or already exist @@ -535,4 +532,27 @@ if [ -n "${NAME}" ]; then running_jail fi +# May not exist on deployments created before Bastille 0.7.20200714, so creating it. -- cwells +if [ ! -e "${bastille_templatesdir}/default" ]; then + ln -s "${bastille_sharedir}/templates/default" "${bastille_templatesdir}/default" +fi + +# These variables were added after Bastille 0.7.20200714, so they may not exist in the user's config. +# We're checking for existence of the variables rather than empty since empty is a valid value. -- cwells +if [ -z ${bastille_template_base+x} ]; then + bastille_template_base='default/base' +fi +if [ -z ${bastille_template_empty+x} ]; then + bastille_template_empty='default/empty' +fi +if [ -z ${bastille_template_thick+x} ]; then + bastille_template_thick='default/thick' +fi +if [ -z ${bastille_template_thin+x} ]; then + bastille_template_thin='default/thin' +fi +if [ -z ${bastille_template_vnet+x} ]; then + bastille_template_vnet='default/vnet' +fi + create_jail "${NAME}" "${RELEASE}" "${IP}" "${INTERFACE}" diff --git a/usr/local/share/bastille/destroy.sh b/usr/local/share/bastille/destroy.sh index fb28e360..a4bb3c57 100644 --- a/usr/local/share/bastille/destroy.sh +++ b/usr/local/share/bastille/destroy.sh @@ -54,7 +54,7 @@ destroy_jail() { fi if [ -d "${bastille_jail_base}" ]; then - echo -e "${COLOR_GREEN}Deleting Jail: ${TARGET}.${COLOR_RESET}" + info "Deleting Jail: ${TARGET}." if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then if [ -n "${TARGET}" ]; then @@ -79,13 +79,13 @@ destroy_jail() { ## archive jail log if [ -f "${bastille_jail_log}" ]; then mv "${bastille_jail_log}" "${bastille_jail_log}"-"$(date +%F)" - echo -e "${COLOR_GREEN}Note: jail console logs archived.${COLOR_RESET}" - echo -e "${COLOR_GREEN}${bastille_jail_log}-$(date +%F)${COLOR_RESET}" + info "Note: jail console logs archived." + info "${bastille_jail_log}-$(date +%F)" fi ## clear any active rdr rules if [ ! -z "$(pfctl -a "rdr/${TARGET}" -Psn 2>/dev/null)" ]; then - echo -e "${COLOR_GREEN}Clearing RDR rules:${COLOR_RESET}" + info "Clearing RDR rules:" pfctl -a "rdr/${TARGET}" -Fn fi echo @@ -120,7 +120,7 @@ destroy_rel() { error_exit "Release base not found." else if [ "${BASE_HASCHILD}" -eq "0" ]; then - echo -e "${COLOR_GREEN}Deleting base: ${TARGET}.${COLOR_RESET}" + info "Deleting base: ${TARGET}" if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then if [ -n "${TARGET}" ]; then diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index 09256b12..398c1632 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -90,8 +90,8 @@ jail_export() if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ]; then FILE_EXT="xz" - echo -e "${COLOR_GREEN}Exporting '${TARGET}' to a compressed .${FILE_EXT} archive.${COLOR_RESET}" - echo -e "${COLOR_GREEN}Sending zfs data stream...${COLOR_RESET}" + info "Exporting '${TARGET}' to a compressed .${FILE_EXT} archive." + info "Sending ZFS data stream..." # Take a recursive temporary snapshot zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_export_${DATE}" @@ -104,7 +104,7 @@ jail_export() else # Create standard backup archive FILE_EXT="txz" - echo -e "${COLOR_GREEN}Exporting '${TARGET}' to a compressed .${FILE_EXT} archive...${COLOR_RESET}" + info "Exporting '${TARGET}' to a compressed .${FILE_EXT} archive..." cd "${bastille_jailsdir}" && tar -cf - "${TARGET}" | xz ${bastille_compress_xz_options} > "${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}" fi @@ -114,7 +114,7 @@ jail_export() # Generate container checksum file cd "${bastille_backupsdir}" sha256 -q "${TARGET}_${DATE}.${FILE_EXT}" > "${TARGET}_${DATE}.sha256" - echo -e "${COLOR_GREEN}Exported '${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}' successfully.${COLOR_RESET}" + info "Exported '${bastille_backupsdir}/${TARGET}_${DATE}.${FILE_EXT}' successfully." exit 0 fi } diff --git a/usr/local/share/bastille/htop.sh b/usr/local/share/bastille/htop.sh index 6f1bdf20..df792eea 100644 --- a/usr/local/share/bastille/htop.sh +++ b/usr/local/share/bastille/htop.sh @@ -51,7 +51,7 @@ for _jail in ${JAILS}; do if [ ! -x "${bastille_jail_path}/usr/local/bin/htop" ]; then error_notify "htop not found on ${_jail}." elif [ -x "${bastille_jail_path}/usr/local/bin/htop" ]; then - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" jexec -l ${_jail} /usr/local/bin/htop fi echo -e "${COLOR_RESET}" diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index eecad9f1..75d50268 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -56,34 +56,34 @@ validate_archive() { if [ "${FILE_EXT}" != ".tar.gz" ] && [ "${FILE_EXT}" != ".tar" ]; then if [ -f "${bastille_backupsdir}/${TARGET}" ]; then if [ -f "${bastille_backupsdir}/${FILE_TRIM}.sha256" ]; then - echo -e "${COLOR_GREEN}Validating file: ${TARGET}...${COLOR_RESET}" + info "Validating file: ${TARGET}..." SHA256_DIST=$(cat "${bastille_backupsdir}/${FILE_TRIM}.sha256") SHA256_FILE=$(sha256 -q "${bastille_backupsdir}/${TARGET}") if [ "${SHA256_FILE}" != "${SHA256_DIST}" ]; then error_exit "Failed validation for ${TARGET}." else - echo -e "${COLOR_GREEN}File validation successful!${COLOR_RESET}" + info "File validation successful!" fi else # Check if user opt to force import if [ "${OPTION}" = "-f" -o "${OPTION}" = "force" ]; then - echo -e "${COLOR_YELLOW}Warning: Skipping archive validation!${COLOR_RESET}" + warn "Warning: Skipping archive validation!" else error_exit "Checksum file not found. See 'bastille import TARGET -f'." fi fi fi else - echo -e "${COLOR_YELLOW}Warning: Skipping archive validation!${COLOR_RESET}" + warn "Warning: Skipping archive validation!" fi } update_zfsmount() { - # Update the mountpoint property on the received zfs data stream + # Update the mountpoint property on the received ZFS data stream OLD_ZFS_MOUNTPOINT=$(zfs get -H mountpoint "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" | awk '{print $3}') NEW_ZFS_MOUNTPOINT="${bastille_jailsdir}/${TARGET_TRIM}/root" if [ "${NEW_ZFS_MOUNTPOINT}" != "${OLD_ZFS_MOUNTPOINT}" ]; then - echo -e "${COLOR_GREEN}Updating zfs mountpoint...${COLOR_RESET}" + info "Updating ZFS mountpoint..." zfs set mountpoint="${bastille_jailsdir}/${TARGET_TRIM}/root" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" fi @@ -101,7 +101,7 @@ update_jailconf() { JAIL_CONFIG="${bastille_jailsdir}/${TARGET_TRIM}/jail.conf" if [ -f "${JAIL_CONFIG}" ]; then if ! grep -qw "path = ${bastille_jailsdir}/${TARGET_TRIM}/root;" "${JAIL_CONFIG}"; then - echo -e "${COLOR_GREEN}Updating jail.conf...${COLOR_RESET}" + info "Updating jail.conf..." sed -i '' "s|exec.consolelog.*=.*;|exec.consolelog = ${bastille_logsdir}/${TARGET_TRIM}_console.log;|" "${JAIL_CONFIG}" sed -i '' "s|path.*=.*;|path = ${bastille_jailsdir}/${TARGET_TRIM}/root;|" "${JAIL_CONFIG}" sed -i '' "s|mount.fstab.*=.*;|mount.fstab = ${bastille_jailsdir}/${TARGET_TRIM}/fstab;|" "${JAIL_CONFIG}" @@ -119,7 +119,7 @@ update_fstab() { if [ -n "${FSTAB_CURRENT}" ] && [ -n "${FSTAB_NEWCONF}" ]; then # If both variables are set, compare and update as needed if ! grep -qw "${bastille_releasesdir}/${FSTAB_RELEASE}.*${bastille_jailsdir}/${TARGET_TRIM}/root/.bastille" "${FSTAB_CONFIG}"; then - echo -e "${COLOR_GREEN}Updating fstab...${COLOR_RESET}" + info "Updating fstab..." sed -i '' "s|${FSTAB_CURRENT}|${FSTAB_NEWCONF}|" "${FSTAB_CONFIG}" fi fi @@ -128,7 +128,7 @@ update_fstab() { generate_config() { # Attempt to read previous config file and set required variables accordingly # If we can't get a valid interface, fallback to lo1 and warn user - echo -e "${COLOR_GREEN}Generating jail.conf...${COLOR_RESET}" + info "Generating jail.conf..." if [ "${FILE_EXT}" = ".zip" ]; then # Gather some bits from foreign/iocage config files @@ -188,7 +188,7 @@ generate_config() { IPX_ADDR="ip4.addr" IP_CONFIG="-" IP6_MODE="disable" - echo -e "${COLOR_YELLOW}Warning: See 'bastille edit ${TARGET_TRIM} jail.conf' for manual network configuration${COLOR_RESET}" + warn "Warning: See 'bastille edit ${TARGET_TRIM} jail.conf' for manual network configuration." fi if [ "${FILE_EXT}" = ".tar.gz" ]; then @@ -196,7 +196,7 @@ generate_config() { if [ -z "${CONFIG_RELEASE}" ]; then # Fallback to host version CONFIG_RELEASE=$(freebsd-version | sed 's/\-[pP].*//') - echo -e "${COLOR_YELLOW}Warning: ${CONFIG_RELEASE} was set by default!${COLOR_RESET}" + warn "Warning: ${CONFIG_RELEASE} was set by default!" fi mkdir "${bastille_jailsdir}/${TARGET_TRIM}/root/.bastille" echo "${bastille_releasesdir}/${CONFIG_RELEASE} ${bastille_jailsdir}/${TARGET_TRIM}/root/.bastille nullfs ro 0 0" \ @@ -241,7 +241,7 @@ update_config() { if [ -z "${CONFIG_RELEASE}" ]; then # Fallback to host version CONFIG_RELEASE=$(freebsd-version | sed 's/\-[pP].*//') - echo -e "${COLOR_YELLOW}Warning: ${CONFIG_RELEASE} was set by default!${COLOR_RESET}" + warn "Warning: ${CONFIG_RELEASE} was set by default!" fi mkdir "${bastille_jailsdir}/${TARGET_TRIM}/root/.bastille" echo "${bastille_releasesdir}/${CONFIG_RELEASE} ${bastille_jailsdir}/${TARGET_TRIM}/root/.bastille nullfs ro 0 0" \ @@ -282,11 +282,11 @@ update_symlinks() { # Just warn user to bootstrap the release if missing if [ ! -d "${bastille_releasesdir}/${CONFIG_RELEASE}" ]; then - echo -e "${COLOR_YELLOW}Warning: ${CONFIG_RELEASE} must be bootstrapped, See 'bastille bootstrap'.${COLOR_RESET}" + warn "Warning: ${CONFIG_RELEASE} must be bootstrapped. See 'bastille bootstrap'." fi # Update old symlinks - echo -e "${COLOR_GREEN}Updating symlinks...${COLOR_RESET}" + info "Updating symlinks..." for _link in ${SYMLINKS}; do if [ -L "${_link}" ]; then ln -sf /.bastille/${_link} ${_link} @@ -296,8 +296,8 @@ update_symlinks() { create_zfs_datasets() { # Prepare the ZFS environment and restore from file - echo -e "${COLOR_GREEN}Importing '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive.${COLOR_RESET}" - echo -e "${COLOR_GREEN}Preparing zfs environment...${COLOR_RESET}" + info "Importing '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive." + info "Preparing ZFS environment..." # Create required ZFS datasets, mountpoint inherited from system zfs create ${bastille_zfs_options} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" @@ -321,8 +321,8 @@ jail_import() { if [ -n "${bastille_zfs_zpool}" ]; then if [ "${FILE_EXT}" = ".xz" ]; then # Import from compressed xz on ZFS systems - echo -e "${COLOR_GREEN}Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} archive.${COLOR_RESET}" - echo -e "${COLOR_GREEN}Receiving zfs data stream...${COLOR_RESET}" + info "Importing '${TARGET_TRIM}' from compressed ${FILE_EXT} archive." + info "Receiving ZFS data stream..." xz ${bastille_decompress_xz_options} "${bastille_backupsdir}/${TARGET}" | \ zfs receive -u "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" @@ -334,7 +334,7 @@ jail_import() { create_zfs_datasets # Extract required files to the new datasets - echo -e "${COLOR_GREEN}Extracting files from '${TARGET}' archive...${COLOR_RESET}" + info "Extracting files from '${TARGET}' archive..." tar --exclude='root' -Jxf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}" tar -Jxf "${bastille_backupsdir}/${TARGET}" --strip-components 2 -C "${bastille_jailsdir}/${TARGET_TRIM}/root" "${TARGET_TRIM}/root" if [ "$?" -ne 0 ]; then @@ -342,8 +342,8 @@ jail_import() { fi elif [ "${FILE_EXT}" = ".zip" ]; then # Attempt to import a foreign/iocage container - echo -e "${COLOR_GREEN}Importing '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive.${COLOR_RESET}" - # Sane bastille zfs options + info "Importing '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive." + # Sane bastille ZFS options ZFS_OPTIONS=$(echo ${bastille_zfs_options} | sed 's/-o//g') # Extract required files from the zip archive @@ -352,7 +352,7 @@ jail_import() { error_exit "Failed to extract files from '${TARGET}' archive." rm -f "${FILE_TRIM}" "${FILE_TRIM}_root" fi - echo -e "${COLOR_GREEN}Receiving zfs data stream...${COLOR_RESET}" + info "Receiving ZFS data stream..." zfs receive -u "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" < "${FILE_TRIM}" zfs set ${ZFS_OPTIONS} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" zfs receive -u "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" < "${FILE_TRIM}_root" @@ -376,7 +376,7 @@ jail_import() { create_zfs_datasets # Extract required files to the new datasets - echo -e "${COLOR_GREEN}Extracting files from '${TARGET}' archive...${COLOR_RESET}" + info "Extracting files from '${TARGET}' archive..." tar --exclude='ezjail/' -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}/${TARGET_TRIM}" tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}/root" if [ "$?" -ne 0 ]; then @@ -391,7 +391,7 @@ jail_import() { workout_components # Extract required files to the new datasets - echo -e "${COLOR_GREEN}Extracting files from '${TARGET}' archive...${COLOR_RESET}" + info "Extracting files from '${TARGET}' archive..." tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components "${CONF_TRIM}" -C "${bastille_jailsdir}/${TARGET_TRIM}" "${JAIL_CONF}" tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components "${DIRS_PLUS}" -C "${bastille_jailsdir}/${TARGET_TRIM}/root" "${JAIL_PATH}" if [ -f "${bastille_jailsdir}/${TARGET_TRIM}/${TARGET_TRIM}" ]; then @@ -410,18 +410,18 @@ jail_import() { else # Import from standard supported archives on UFS systems if [ "${FILE_EXT}" = ".txz" ]; then - echo -e "${COLOR_GREEN}Extracting files from '${TARGET}' archive...${COLOR_RESET}" + info "Extracting files from '${TARGET}' archive..." tar -Jxf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" elif [ "${FILE_EXT}" = ".tar.gz" ]; then # Attempt to import/configure foreign/ezjail container - echo -e "${COLOR_GREEN}Extracting files from '${TARGET}' archive...${COLOR_RESET}" + info "Extracting files from '${TARGET}' archive..." mkdir "${bastille_jailsdir}/${TARGET_TRIM}" tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}/${TARGET_TRIM}" mv "${bastille_jailsdir}/${TARGET_TRIM}/ezjail" "${bastille_jailsdir}/${TARGET_TRIM}/root" generate_config elif [ "${FILE_EXT}" = ".tar" ]; then # Attempt to import/configure foreign/qjail container - echo -e "${COLOR_GREEN}Extracting files from '${TARGET}' archive...${COLOR_RESET}" + info "Extracting files from '${TARGET}' archive..." mkdir -p "${bastille_jailsdir}/${TARGET_TRIM}/root" workout_components tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components "${CONF_TRIM}" -C "${bastille_jailsdir}/${TARGET_TRIM}" "${JAIL_CONF}" @@ -442,7 +442,7 @@ jail_import() { # This is required on foreign imports only update_jailconf update_fstab - echo -e "${COLOR_GREEN}Container '${TARGET_TRIM}' imported successfully.${COLOR_RESET}" + info "Container '${TARGET_TRIM}' imported successfully." exit 0 fi else diff --git a/usr/local/share/bastille/limits.sh b/usr/local/share/bastille/limits.sh index 1d4de5cb..56a659b5 100644 --- a/usr/local/share/bastille/limits.sh +++ b/usr/local/share/bastille/limits.sh @@ -59,16 +59,22 @@ OPTION="${1}" VALUE="${2}" for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" _rctl_rule="jail:${_jail}:${OPTION}:deny=${VALUE}/jail" + _rctl_rule_log="jail:${_jail}:${OPTION}:log=${VALUE}/jail" - ## if entry doesn't exist, add; else show existing entry - if ! grep -qs "${_rctl_rule}" "${bastille_jailsdir}/${_jail}/rctl.conf"; then + # Check whether the entry already exists and, if so, update it. -- cwells + if grep -qs "jail:${_jail}:${OPTION}:deny" "${bastille_jailsdir}/${_jail}/rctl.conf"; then + _escaped_option=$(echo "${OPTION}" | sed 's/\//\\\//g') + _escaped_rctl_rule=$(echo "${_rctl_rule}" | sed 's/\//\\\//g') + sed -i '' -E "s/jail:${_jail}:${_escaped_option}:deny.+/${_escaped_rctl_rule}/" "${bastille_jailsdir}/${_jail}/rctl.conf" + else # Just append the entry. -- cwells echo "${_rctl_rule}" >> "${bastille_jailsdir}/${_jail}/rctl.conf" + echo "${_rctl_rule_log}" >> "${bastille_jailsdir}/${_jail}/rctl.conf" fi echo -e "${OPTION} ${VALUE}" - rctl -a "${_rctl_rule}" + rctl -a "${_rctl_rule}" "${_rctl_rule_log}" echo -e "${COLOR_RESET}" done diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 21173ab7..fc37b1e5 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -60,37 +60,37 @@ _checks=$(echo "${_fstab}" | awk '{print $5" "$6}') ## if any variables are empty, bail out if [ -z "${_hostpath}" ] || [ -z "${_jailpath}" ] || [ -z "${_type}" ] || [ -z "${_perms}" ] || [ -z "${_checks}" ]; then error_notify "FSTAB format not recognized." - echo -e "${COLOR_YELLOW}Format: /host/path jail/path nullfs ro 0 0${COLOR_RESET}" - echo -e "${COLOR_YELLOW}Read: ${_fstab}${COLOR_RESET}" + warn "Format: /host/path jail/path nullfs ro 0 0" + warn "Read: ${_fstab}" exit 1 fi ## if host path doesn't exist or type is not "nullfs" if [ ! -d "${_hostpath}" ] || [ "${_type}" != "nullfs" ]; then error_notify "Detected invalid host path or incorrect mount type in FSTAB." - echo -e "${COLOR_YELLOW}Format: /host/path jail/path nullfs ro 0 0${COLOR_RESET}" - echo -e "${COLOR_YELLOW}Read: ${_fstab}${COLOR_RESET}" + warn "Format: /host/path jail/path nullfs ro 0 0" + warn "Read: ${_fstab}" exit 1 fi ## if mount permissions are not "ro" or "rw" if [ "${_perms}" != "ro" ] && [ "${_perms}" != "rw" ]; then error_notify "Detected invalid mount permissions in FSTAB." - echo -e "${COLOR_YELLOW}Format: /host/path jail/path nullfs ro 0 0${COLOR_RESET}" - echo -e "${COLOR_YELLOW}Read: ${_fstab}${COLOR_RESET}" + warn "Format: /host/path jail/path nullfs ro 0 0" + warn "Read: ${_fstab}" exit 1 fi ## if check & pass are not "0 0 - 1 1"; bail out if [ "${_checks}" != "0 0" ] && [ "${_checks}" != "1 0" ] && [ "${_checks}" != "0 1" ] && [ "${_checks}" != "1 1" ]; then error_notify "Detected invalid fstab options in FSTAB." - echo -e "${COLOR_YELLOW}Format: /host/path jail/path nullfs ro 0 0${COLOR_RESET}" - echo -e "${COLOR_YELLOW}Read: ${_fstab}${COLOR_RESET}" + warn "Format: /host/path jail/path nullfs ro 0 0" + warn "Read: ${_fstab}" exit 1 fi for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" ## aggregate variables into FSTAB entry _jailpath="${bastille_jailsdir}/${_jail}/root/${_jailpath}" diff --git a/usr/local/share/bastille/pkg.sh b/usr/local/share/bastille/pkg.sh index d3f7181c..715b6438 100644 --- a/usr/local/share/bastille/pkg.sh +++ b/usr/local/share/bastille/pkg.sh @@ -46,7 +46,7 @@ if [ $# -lt 1 ]; then fi for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" jexec -l "${_jail}" /usr/sbin/pkg "$@" echo done diff --git a/usr/local/share/bastille/rdr.sh b/usr/local/share/bastille/rdr.sh index 1fe1c63e..be8c62e2 100644 --- a/usr/local/share/bastille/rdr.sh +++ b/usr/local/share/bastille/rdr.sh @@ -58,9 +58,11 @@ if [ -z "${JAIL_NAME}" ]; then fi # Check jail ip4 address valid -JAIL_IP=$(jls -j "${TARGET}" ip4.addr 2>/dev/null) -if [ -z "${JAIL_IP}" -o "${JAIL_IP}" = "-" ]; then - error_exit "Jail IP not found: ${TARGET}" +if [ "$(bastille config $TARGET get vnet)" != 'enabled' ]; then + JAIL_IP=$(jls -j "${TARGET}" ip4.addr 2>/dev/null) + if [ -z "${JAIL_IP}" -o "${JAIL_IP}" = "-" ]; then + error_exit "Jail IP not found: ${TARGET}" + fi fi # Check rdr-anchor is setup in pf.conf diff --git a/usr/local/share/bastille/rename.sh b/usr/local/share/bastille/rename.sh index 14541fb2..1fb73d2a 100644 --- a/usr/local/share/bastille/rename.sh +++ b/usr/local/share/bastille/rename.sh @@ -88,11 +88,11 @@ update_fstab() { change_name() { # Attempt container name change - echo -e "${COLOR_GREEN}Attempting to rename '${TARGET}' to ${NEWNAME}...${COLOR_RESET}" + info "Attempting to rename '${TARGET}' to ${NEWNAME}..." if [ "${bastille_zfs_enable}" = "YES" ]; then if [ -n "${bastille_zfs_zpool}" ] && [ -n "${bastille_zfs_prefix}" ]; then # Check and rename container ZFS dataset accordingly - # Perform additional checks in case of non-zfs existing containers + # Perform additional checks in case of non-ZFS existing containers if zfs list | grep -qw "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}"; then if ! zfs rename -f "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NEWNAME}"; then error_exit "Can't rename '${TARGET}' dataset." @@ -115,7 +115,7 @@ change_name() { error_exit "Can't rename '${TARGET}' dataset." fi else - error_exit "Can't determine the zfs origin path of '${TARGET}'." + error_exit "Can't determine the ZFS origin path of '${TARGET}'." fi else # Just rename the jail directory @@ -131,7 +131,7 @@ change_name() { if [ "$?" -ne 0 ]; then error_exit "An error has occurred while attempting to rename '${TARGET}'." else - echo -e "${COLOR_GREEN}Renamed '${TARGET}' to '${NEWNAME}' successfully.${COLOR_RESET}" + info "Renamed '${TARGET}' to '${NEWNAME}' successfully." fi } diff --git a/usr/local/share/bastille/service.sh b/usr/local/share/bastille/service.sh index b90b881b..9ef37a72 100644 --- a/usr/local/share/bastille/service.sh +++ b/usr/local/share/bastille/service.sh @@ -46,7 +46,7 @@ if [ $# -ne 2 ]; then fi for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" jexec -l "${_jail}" /usr/sbin/service "$@" echo done diff --git a/usr/local/share/bastille/start.sh b/usr/local/share/bastille/start.sh index 47f135a8..66c1fe83 100644 --- a/usr/local/share/bastille/start.sh +++ b/usr/local/share/bastille/start.sh @@ -67,16 +67,26 @@ for _jail in ${JAILS}; do ## test if not running elif [ ! "$(jls name | awk "/^${_jail}$/")" ]; then + # Verify that the configured interface exists. -- cwells + if [ "$(bastille config $_jail get vnet)" != 'enabled' ]; then + _interface=$(bastille config $_jail get interface) + if ! ifconfig | grep "^${_interface}:" >/dev/null; then + error_notify "Error: ${_interface} interface does not exist." + continue + fi + fi + ## warn if matching configured (but not online) ip4.addr, ignore if there's no ip4.addr entry ip=$(grep 'ip4.addr' "${bastille_jailsdir}/${_jail}/jail.conf" | awk '{print $3}' | sed 's/\;//g') if [ -n "${ip}" ]; then if ifconfig | grep -w "${ip}" >/dev/null; then - error_exit "Error: IP address (${ip}) already in use." + error_notify "Error: IP address (${ip}) already in use." + continue fi fi ## start the container - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" jail -f "${bastille_jailsdir}/${_jail}/jail.conf" -c "${_jail}" ## add rctl limits diff --git a/usr/local/share/bastille/stop.sh b/usr/local/share/bastille/stop.sh index 21e84931..bfe67932 100644 --- a/usr/local/share/bastille/stop.sh +++ b/usr/local/share/bastille/stop.sh @@ -55,6 +55,10 @@ for _jail in ${JAILS}; do pfctl -q -t jails -T delete "$(jls -j ${_jail} ip4.addr)" fi fi + + if [ "$(bastille rdr ${_jail} list)" ]; then + bastille rdr ${_jail} clear + fi ## remove rctl limits if [ -s "${bastille_jailsdir}/${_jail}/rctl.conf" ]; then @@ -64,7 +68,7 @@ for _jail in ${JAILS}; do fi ## stop container - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" jail -f "${bastille_jailsdir}/${_jail}/jail.conf" -r "${_jail}" fi echo diff --git a/usr/local/share/bastille/sysrc.sh b/usr/local/share/bastille/sysrc.sh index 2ab807d1..eb368ee3 100644 --- a/usr/local/share/bastille/sysrc.sh +++ b/usr/local/share/bastille/sysrc.sh @@ -46,7 +46,7 @@ if [ $# -lt 1 ]; then fi for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" jexec -l "${_jail}" /usr/sbin/sysrc "$@" echo -e "${COLOR_RESET}" done diff --git a/usr/local/share/bastille/template.sh b/usr/local/share/bastille/template.sh index 8ec25ca8..d43ba95c 100644 --- a/usr/local/share/bastille/template.sh +++ b/usr/local/share/bastille/template.sh @@ -32,7 +32,7 @@ . /usr/local/etc/bastille/bastille.conf bastille_usage() { - error_exit "Usage: bastille template TARGET project/template" + error_exit "Usage: bastille template TARGET|--convert project/template" } post_command_hook() { @@ -97,11 +97,14 @@ get_arg_value() { render() { _file_path="${1}/${2}" if [ -d "${_file_path}" ]; then # Recursively render every file in this directory. -- cwells + echo "Rendering Directory: ${_file_path}" + find "${_file_path}" \( -type d -name .git -prune \) -o -type f find "${_file_path}" \( -type d -name .git -prune \) -o -type f -print0 | $(eval "xargs -0 sed -i '' ${ARG_REPLACEMENTS}") elif [ -f "${_file_path}" ]; then + echo "Rendering File: ${_file_path}" eval "sed -i '' ${ARG_REPLACEMENTS} '${_file_path}'" else - echo -e "${COLOR_YELLOW}Path not found for render: ${2}${COLOR_RESET}" + warn "Path not found for render: ${2}" fi } @@ -116,18 +119,73 @@ if [ $# -lt 1 ]; then bastille_usage fi +## global variables TEMPLATE="${1}" +bastille_template=${bastille_templatesdir}/${TEMPLATE} +if [ -z "${HOOKS}" ]; then + HOOKS='LIMITS INCLUDE PRE FSTAB PF PKG OVERLAY CONFIG SYSRC SERVICE CMD RENDER' +fi + +# Special case conversion of hook-style template files into a Bastillefile. -- cwells +if [ "${TARGET}" = '--convert' ]; then + if [ -d "${TEMPLATE}" ]; then # A relative path was provided. -- cwells + cd "${TEMPLATE}" + elif [ -d "${bastille_template}" ]; then + cd "${bastille_template}" + else + error_exit "Template not found: ${TEMPLATE}" + fi + + echo "Converting template: ${TEMPLATE}" + + HOOKS="ARG ${HOOKS}" + for _hook in ${HOOKS}; do + if [ -s "${_hook}" ]; then + # Default command is the hook name and default args are the line from the file. -- cwells + _cmd="${_hook}" + _args_template='${_line}' + + # Replace old hook names with Bastille command names. -- cwells + case ${_hook} in + CONFIG|OVERLAY) + _cmd='CP' + _args_template='${_line} /' + ;; + FSTAB) + _cmd='MOUNT' ;; + PF) + _cmd='RDR' ;; + PRE) + _cmd='CMD' ;; + esac + + while read _line; do + if [ -z "${_line}" ]; then + continue + fi + eval "_args=\"${_args_template}\"" + echo "${_cmd} ${_args}" >> Bastillefile + done < "${_hook}" + echo '' >> Bastillefile + rm "${_hook}" + fi + done + + info "Template converted: ${TEMPLATE}" + exit 0 +fi case ${TEMPLATE} in http?://github.com/*/*|http?://gitlab.com/*/*) TEMPLATE_DIR=$(echo "${TEMPLATE}" | awk -F / '{ print $4 "/" $5 }') if [ ! -d "${bastille_templatesdir}/${TEMPLATE_DIR}" ]; then - echo -e "${COLOR_GREEN}Bootstrapping ${TEMPLATE}...${COLOR_RESET}" + info "Bootstrapping ${TEMPLATE}..." if ! bastille bootstrap "${TEMPLATE}"; then error_exit "Failed to bootstrap template: ${TEMPLATE}" fi fi TEMPLATE="${TEMPLATE_DIR}" + bastille_template=${bastille_templatesdir}/${TEMPLATE} ;; */*) if [ ! -d "${bastille_templatesdir}/${TEMPLATE}" ]; then @@ -142,10 +200,6 @@ if [ -z "${JAILS}" ]; then error_exit "Container ${TARGET} is not running." fi -if [ -z "${HOOKS}" ]; then - HOOKS='LIMITS INCLUDE PRE FSTAB PF PKG OVERLAY CONFIG SYSRC SERVICE CMD RENDER' -fi - # Check for an --arg-file parameter. -- cwells for _script_arg in "$@"; do case ${_script_arg} in @@ -166,31 +220,38 @@ if [ -n "${ARG_FILE}" ] && [ ! -f "${ARG_FILE}" ]; then error_exit "File not found: ${ARG_FILE}" fi -## global variables -bastille_template=${bastille_templatesdir}/${TEMPLATE} for _jail in ${JAILS}; do + info "[${_jail}]:" + info "Applying template: ${TEMPLATE}..." + ## jail-specific variables. bastille_jail_path=$(jls -j "${_jail}" path) - - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" - echo -e "${COLOR_GREEN}Applying template: ${TEMPLATE}...${COLOR_RESET}" + if [ "$(bastille config $TARGET get vnet)" != 'enabled' ]; then + _jail_ip=$(jls -j "${_jail}" ip4.addr 2>/dev/null) + if [ -z "${_jail_ip}" -o "${_jail_ip}" = "-" ]; then + error_notify "Jail IP not found: ${_jail}" + _jail_ip='' # In case it was -. -- cwells + fi + fi ## TARGET if [ -s "${bastille_template}/TARGET" ]; then if grep -qw "${_jail}" "${bastille_template}/TARGET"; then - echo -e "${COLOR_GREEN}TARGET: !${_jail}.${COLOR_RESET}" + info "TARGET: !${_jail}." echo continue fi if ! grep -Eq "(^|\b)(${_jail}|ALL)($|\b)" "${bastille_template}/TARGET"; then - echo -e "${COLOR_GREEN}TARGET: ?${_jail}.${COLOR_RESET}" + info "TARGET: ?${_jail}." echo continue fi fi + # Build a list of sed commands like this: -e 's/${username}/root/g' -e 's/${domain}/example.com/g' + # Values provided by default (without being defined by the user) are listed here. -- cwells + ARG_REPLACEMENTS="-e 's/\${JAIL_IP}/${_jail_ip}/g' -e 's/\${JAIL_NAME}/${_jail}/g'" # This is parsed outside the HOOKS loop so an ARG file can be used with a Bastillefile. -- cwells - ARG_REPLACEMENTS='' if [ -s "${bastille_template}/ARG" ]; then while read _line; do if [ -z "${_line}" ]; then @@ -199,16 +260,15 @@ for _jail in ${JAILS}; do _arg_name=$(get_arg_name "${_line}") _arg_value=$(get_arg_value "${_line}" "$@") if [ -z "${_arg_value}" ]; then - echo -e "${COLOR_YELLOW}No value provided for arg: ${_arg_name}${COLOR_RESET}" + warn "No value provided for arg: ${_arg_name}" fi - # Build a list of sed commands like this: -e 's/${username}/root/g' -e 's/${domain}/example.com/g' ARG_REPLACEMENTS="${ARG_REPLACEMENTS} -e 's/\${${_arg_name}}/${_arg_value}/g'" done < "${bastille_template}/ARG" fi if [ -s "${bastille_template}/Bastillefile" ]; then # Ignore blank lines and comments. -- cwells - SCRIPT=$(grep -v '^\s*$' "${bastille_template}/Bastillefile" | grep -v '^\s*#') + SCRIPT=$(grep -v '^[[:blank:]]*$' "${bastille_template}/Bastillefile" | grep -v '^[[:blank:]]*#') # Use a newline as the separator. -- cwells IFS=' ' @@ -225,20 +285,22 @@ for _jail in ${JAILS}; do _arg_name=$(get_arg_name "${_args}") _arg_value=$(get_arg_value "${_args}" "$@") if [ -z "${_arg_value}" ]; then - echo -e "${COLOR_YELLOW}No value provided for arg: ${_arg_name}${COLOR_RESET}" + warn "No value provided for arg: ${_arg_name}" fi # Build a list of sed commands like this: -e 's/${username}/root/g' -e 's/${domain}/example.com/g' ARG_REPLACEMENTS="${ARG_REPLACEMENTS} -e 's/\${${_arg_name}}/${_arg_value}/g'" continue ;; cmd) + # Escape single-quotes in the command being executed. -- cwells + _args=$(echo "${_args}" | sed "s/'/'\\\\''/g") # Allow redirection within the jail. -- cwells _args="sh -c '${_args}'" ;; cp|copy) _cmd='cp' # Convert relative "from" path into absolute path inside the template directory. -- cwells - if [ "${_args%${_args#?}}" != '/' ]; then + if [ "${_args%${_args#?}}" != '/' ] && [ "${_args%${_args#??}}" != '"/' ]; then _args="${bastille_template}/${_args}" fi ;; @@ -279,7 +341,7 @@ for _jail in ${JAILS}; do # Override default command/args for some hooks. -- cwells case ${_hook} in CONFIG) - echo -e "${COLOR_YELLOW}CONFIG deprecated; rename to OVERLAY.${COLOR_RESET}" + warn "CONFIG deprecated; rename to OVERLAY." _args_template='${bastille_template}/${_line} /' _cmd='cp' ;; FSTAB) @@ -290,7 +352,7 @@ for _jail in ${JAILS}; do _args_template='${bastille_template}/${_line} /' _cmd='cp' ;; PF) - echo -e "${COLOR_GREEN}NOT YET IMPLEMENTED.${COLOR_RESET}" + info "NOT YET IMPLEMENTED." continue ;; PRE) _cmd='cmd' ;; @@ -300,7 +362,7 @@ for _jail in ${JAILS}; do ;; esac - echo -e "${COLOR_GREEN}[${_jail}]:${_hook} -- START${COLOR_RESET}" + info "[${_jail}]:${_hook} -- START" if [ "${_hook}" = 'CMD' ] || [ "${_hook}" = 'PRE' ]; then bastille cmd "${_jail}" /bin/sh < "${bastille_template}/${_hook}" || exit 1 elif [ "${_hook}" = 'PKG' ]; then @@ -317,11 +379,11 @@ for _jail in ${JAILS}; do bastille "${_cmd}" "${_jail}" ${_args} || exit 1 done < "${bastille_template}/${_hook}" fi - echo -e "${COLOR_GREEN}[${_jail}]:${_hook} -- END${COLOR_RESET}" + info "[${_jail}]:${_hook} -- END" echo fi done - echo -e "${COLOR_GREEN}Template complete.${COLOR_RESET}" + info "Template applied: ${TEMPLATE}" echo done diff --git a/usr/local/share/bastille/templates/default/base/Bastillefile b/usr/local/share/bastille/templates/default/base/Bastillefile new file mode 100644 index 00000000..7418fba6 --- /dev/null +++ b/usr/local/share/bastille/templates/default/base/Bastillefile @@ -0,0 +1,11 @@ +ARG HOST_RESOLV_CONF=/etc/resolv.conf + +CMD touch /etc/rc.conf +SYSRC syslogd_flags="-ss" +SYSRC sendmail_enable="NO" +SYSRC sendmail_submit_enable="NO" +SYSRC sendmail_outbound_enable="NO" +SYSRC sendmail_msp_queue_enable="NO" +SYSRC cron_flags="-J 60" + +CP "${HOST_RESOLV_CONF}" etc/resolv.conf diff --git a/usr/local/share/bastille/templates/default/empty/Bastillefile b/usr/local/share/bastille/templates/default/empty/Bastillefile new file mode 100644 index 00000000..e69de29b diff --git a/usr/local/share/bastille/templates/default/thick/Bastillefile b/usr/local/share/bastille/templates/default/thick/Bastillefile new file mode 100644 index 00000000..37e450e6 --- /dev/null +++ b/usr/local/share/bastille/templates/default/thick/Bastillefile @@ -0,0 +1,4 @@ +ARG BASE_TEMPLATE=default/base +ARG HOST_RESOLV_CONF=/etc/resolv.conf + +INCLUDE ${BASE_TEMPLATE} --arg HOST_RESOLV_CONF="${HOST_RESOLV_CONF}" diff --git a/usr/local/share/bastille/templates/default/thin/Bastillefile b/usr/local/share/bastille/templates/default/thin/Bastillefile new file mode 100644 index 00000000..37e450e6 --- /dev/null +++ b/usr/local/share/bastille/templates/default/thin/Bastillefile @@ -0,0 +1,4 @@ +ARG BASE_TEMPLATE=default/base +ARG HOST_RESOLV_CONF=/etc/resolv.conf + +INCLUDE ${BASE_TEMPLATE} --arg HOST_RESOLV_CONF="${HOST_RESOLV_CONF}" diff --git a/usr/local/share/bastille/templates/default/vnet/Bastillefile b/usr/local/share/bastille/templates/default/vnet/Bastillefile new file mode 100644 index 00000000..92b76fc6 --- /dev/null +++ b/usr/local/share/bastille/templates/default/vnet/Bastillefile @@ -0,0 +1,13 @@ +ARG BASE_TEMPLATE=default/base +ARG HOST_RESOLV_CONF=/etc/resolv.conf + +INCLUDE ${BASE_TEMPLATE} --arg HOST_RESOLV_CONF="${HOST_RESOLV_CONF}" + +ARG EPAIR +ARG GATEWAY +ARG IFCONFIG="SYNCDHCP" + +SYSRC ifconfig_${EPAIR}_name=vnet0 +SYSRC ifconfig_vnet0="${IFCONFIG}" +# GATEWAY will be empty for a DHCP config. -- cwells +CMD if [ -n "${GATEWAY}" ]; then /usr/sbin/sysrc defaultrouter="${GATEWAY}"; fi diff --git a/usr/local/share/bastille/top.sh b/usr/local/share/bastille/top.sh index 5f248653..05e23953 100644 --- a/usr/local/share/bastille/top.sh +++ b/usr/local/share/bastille/top.sh @@ -46,7 +46,7 @@ if [ $# -ne 0 ]; then fi for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" jexec -l "${_jail}" /usr/bin/top echo -e "${COLOR_RESET}" done diff --git a/usr/local/share/bastille/umount.sh b/usr/local/share/bastille/umount.sh index 0b1894d2..518461b0 100644 --- a/usr/local/share/bastille/umount.sh +++ b/usr/local/share/bastille/umount.sh @@ -49,7 +49,7 @@ fi MOUNT_PATH=$1 for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" _jailpath="${bastille_jailsdir}/${_jail}/root/${MOUNT_PATH}" diff --git a/usr/local/share/bastille/update.sh b/usr/local/share/bastille/update.sh index 34e3c641..acb958b2 100644 --- a/usr/local/share/bastille/update.sh +++ b/usr/local/share/bastille/update.sh @@ -32,7 +32,7 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_exit "Usage: bastille update [release|container]" + error_exit "Usage: bastille update [release|container] | [option]" } # Handle special-case commands first. @@ -42,41 +42,72 @@ help|-h|--help) ;; esac -if [ $# -gt 1 ] || [ $# -lt 1 ]; then +if [ $# -gt 2 ] || [ $# -lt 1 ]; then usage fi TARGET="${1}" -shift +OPTION="${2}" + +# Handle options +case "${OPTION}" in + -f|--force) + OPTION="-F" + ;; + *) + OPTION= + ;; +esac + +# Check for unsupported actions +if [ "${TARGET}" = "ALL" ]; then + error_exit "Batch upgrade is unsupported." +fi if freebsd-version | grep -qi HBSD; then error_exit "Not yet supported on HardenedBSD." fi -if [ -d "${bastille_jailsdir}/${TARGET}" ]; then - if ! grep -qw ".bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then - if [ "$(jls name | awk "/^${TARGET}$/")" ]; then - # Update a thick container. - CURRENT_VERSION=$(/usr/sbin/jexec -l "${TARGET}" freebsd-version 2>/dev/null) - if [ -z "${CURRENT_VERSION}" ]; then - error_exit "Can't determine '${TARGET}' version." - else - env PAGER="/bin/cat" freebsd-update --not-running-from-cron -b "${bastille_jailsdir}/${TARGET}/root" \ - fetch install --currently-running "${CURRENT_VERSION}" - fi - else - error_notify "${TARGET} is not running." - error_exit "See 'bastille start ${TARGET}'." - fi +jail_check() { + # Check if the jail is thick and is running + if [ ! "$(jls name | awk "/^${TARGET}$/")" ]; then + error_exit "[${TARGET}]: Not started. See 'bastille start ${TARGET}'." else - error_exit "${TARGET} is not a thick container." + if grep -qw "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then + error_exit "${TARGET} is not a thick container." + fi fi -else +} + +jail_update() { + # Update a thick container + if [ -d "${bastille_jailsdir}/${TARGET}" ]; then + jail_check + CURRENT_VERSION=$(/usr/sbin/jexec -l "${TARGET}" freebsd-version 2>/dev/null) + if [ -z "${CURRENT_VERSION}" ]; then + error_exit "Can't determine '${TARGET}' version." + else + env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_jailsdir}/${TARGET}/root" \ + fetch install --currently-running "${CURRENT_VERSION}" + fi + else + error_exit "${TARGET} not found. See 'bastille bootstrap'." + fi +} + +release_update() { + # Update a release base(affects child containers) if [ -d "${bastille_releasesdir}/${TARGET}" ]; then - # Update container base(affects child containers). - env PAGER="/bin/cat" freebsd-update --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" \ + env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" \ fetch install --currently-running "${TARGET}" else error_exit "${TARGET} not found. See 'bastille bootstrap'." fi +} + +# Check what we should update +if echo "${TARGET}" | grep -q "[0-9]\{2\}.[0-9]-RELEASE"; then + release_update +else + jail_update fi diff --git a/usr/local/share/bastille/upgrade.sh b/usr/local/share/bastille/upgrade.sh index 56b32a01..dbd0ee9b 100644 --- a/usr/local/share/bastille/upgrade.sh +++ b/usr/local/share/bastille/upgrade.sh @@ -74,7 +74,7 @@ jail_check() { if [ ! "$(jls name | awk "/^${TARGET}$/")" ]; then error_exit "[${TARGET}]: Not started. See 'bastille start ${TARGET}'." else - if cat "${bastille_jailsdir}/${TARGET}/fstab" 2>/dev/null | grep -w "${TARGET}" | grep -qw "/.*/.bastille"; then + if grep -qw "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then error_exit "${TARGET} is not a thick container." fi fi diff --git a/usr/local/share/bastille/verify.sh b/usr/local/share/bastille/verify.sh index 13479a50..7239e252 100644 --- a/usr/local/share/bastille/verify.sh +++ b/usr/local/share/bastille/verify.sh @@ -55,22 +55,22 @@ verify_template() { _path=${_template_path}/${_hook} if [ -s "${_path}" ]; then _hook_validate=$((_hook_validate+1)) - echo -e "${COLOR_GREEN}Detected ${_hook} hook.${COLOR_RESET}" + info "Detected ${_hook} hook." ## line count must match newline count if [ $(wc -l "${_path}" | awk '{print $1}') -ne $(grep -c $'\n' "${_path}") ]; then - echo -e "${COLOR_GREEN}[${_hook}]:${COLOR_RESET}" + info "[${_hook}]:" error_notify "${BASTILLE_TEMPLATE}:${_hook} [failed]." error_notify "Line numbers don't match line breaks." echo error_exit "Template validation failed." ## if INCLUDE; recursive verify elif [ ${_hook} = 'INCLUDE' ]; then - echo -e "${COLOR_GREEN}[${_hook}]:${COLOR_RESET}" + info "[${_hook}]:" cat "${_path}" echo while read _include; do - echo -e "${COLOR_GREEN}[${_hook}]:[${_include}]:${COLOR_RESET}" + info "[${_hook}]:[${_include}]:" case ${_include} in http?://github.com/*/*|http?://gitlab.com/*/*) @@ -89,11 +89,11 @@ verify_template() { ## if tree; tree -a bastille_template/_dir elif [ ${_hook} = 'OVERLAY' ]; then - echo -e "${COLOR_GREEN}[${_hook}]:${COLOR_RESET}" + info "[${_hook}]:" cat "${_path}" echo while read _dir; do - echo -e "${COLOR_GREEN}[${_hook}]:[${_dir}]:${COLOR_RESET}" + info "[${_hook}]:[${_dir}]:" if [ -x /usr/local/bin/tree ]; then /usr/local/bin/tree -a "${_template_path}/${_dir}" else @@ -102,7 +102,7 @@ verify_template() { echo done < "${_path}" else - echo -e "${COLOR_GREEN}[${_hook}]:${COLOR_RESET}" + info "[${_hook}]:" cat "${_path}" echo fi @@ -119,7 +119,7 @@ verify_template() { ## if validated; ready to use if [ ${_hook_validate} -gt 0 ]; then - echo -e "${COLOR_GREEN}Template ready to use.${COLOR_RESET}" + info "Template ready to use." fi } diff --git a/usr/local/share/bastille/zfs.sh b/usr/local/share/bastille/zfs.sh index 0f34f328..da4f065d 100644 --- a/usr/local/share/bastille/zfs.sh +++ b/usr/local/share/bastille/zfs.sh @@ -37,7 +37,7 @@ usage() { zfs_snapshot() { for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}"@"${TAG}" echo done @@ -45,7 +45,7 @@ done zfs_set_value() { for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" zfs "${ATTRIBUTE}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}" echo done @@ -53,7 +53,7 @@ done zfs_get_value() { for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" zfs get "${ATTRIBUTE}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}" echo done @@ -61,7 +61,7 @@ done zfs_disk_usage() { for _jail in ${JAILS}; do - echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" + info "[${_jail}]:" zfs list -t all -o name,used,avail,refer,mountpoint,compress,ratio -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}" echo done