diff --git a/README.md b/README.md index e3d37976..b63ef6d8 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -Bastille: Automated Container Security -====================================== -Bastille is an open-source system for automating deployment and management of -containerized applications on FreeBSD. +Bastille: Automate Container Security +===================================== +[Bastille](https://bastillebsd.org/) is an open-source system for automating +deployment and management of containerized applications on FreeBSD. -Looking for [Bastille Templates](https://gitlab.com/BastilleBSD-Templates)? +Looking for [Bastille Templates](https://gitlab.com/BastilleBSD-Templates/)? Installation @@ -557,9 +557,9 @@ To leverage a template hook, create an UPPERCASE file in the root of the template directory named after the hook you want to execute. eg; ```shell -echo "install zsh vim-console git-lite htop" > /usr/local/bastille/templates/base/PKG -echo "/usr/bin/chsh -s /usr/local/bin/zsh" > /usr/local/bastille/templates/base/CMD -echo "etc\nroot\nusr" > /usr/local/bastille/templates/base/OVERLAY +echo "zsh vim-console git-lite htop" > /usr/local/bastille/templates/username/base/PKG +echo "/usr/bin/chsh -s /usr/local/bin/zsh" > /usr/local/bastille/templates/username/base/CMD +echo "usr" > /usr/local/bastille/templates/username/base/OVERLAY ``` Template hooks are executed in specific order and require specific syntax to diff --git a/usr/local/share/bastille/bootstrap.sh b/usr/local/share/bastille/bootstrap.sh index a9b63fdd..e812cfcb 100644 --- a/usr/local/share/bastille/bootstrap.sh +++ b/usr/local/share/bastille/bootstrap.sh @@ -360,74 +360,21 @@ bootstrap_template() { _template=${bastille_templatesdir}/${_user}/${_repo} ## support for non-git - if [ ! -x /usr/local/bin/git ]; then - echo -e "${COLOR_RED}We're gonna have to use fetch. Strap in.${COLOR_RESET}" - echo -e "${COLOR_RED}Not yet implemented...${COLOR_RESET}" + if [ ! -x $(which git) ]; then + echo -e "${COLOR_RED}Git not found.${COLOR_RESET}" + echo -e "${COLOR_RED}Not yet implemented.${COLOR_RESET}" exit 1 - fi - - ## support for git - if [ -x /usr/local/bin/git ]; then + elif [ -x $(which git) ]; then if [ ! -d "${_template}/.git" ]; then - /usr/local/bin/git clone "${_url}" "${_template}" ||\ + $(which git) clone "${_url}" "${_template}" ||\ echo -e "${COLOR_RED}Clone unsuccessful.${COLOR_RESET}" - echo elif [ -d "${_template}/.git" ]; then - cd ${_template} && - /usr/local/bin/git pull ||\ + cd ${_template} && $(which git) pull ||\ echo -e "${COLOR_RED}Template update unsuccessful.${COLOR_RESET}" - echo fi fi - ## template validation - _hook_validate=0 - for _hook in PRE FSTAB PF PKG SYSRC CMD; do - if [ -s ${_template}/${_hook} ]; then - _hook_validate=$((_hook_validate+1)) - echo -e "${COLOR_GREEN}Detected ${_hook} hook.${COLOR_RESET}" - echo -e "${COLOR_GREEN}[${_hook}]:${COLOR_RESET}" - cat "${_template}/${_hook}" - echo - fi - done - - # template overlay - if [ -s ${_template}/OVERLAY ]; then - _hook_validate=$((_hook_validate+1)) - echo -e "${COLOR_GREEN}Detected OVERLAY hook.${COLOR_RESET}" - while read _dir; do - echo -e "${COLOR_GREEN}[${_dir}]:${COLOR_RESET}" - if [ -x $(which tree) ]; then - tree -a ${_template}/${_dir} - fi - done < ${_template}/OVERLAY - echo - fi - if [ -s ${_template}/CONFIG ]; then - echo -e "${COLOR_GREEN}Detected CONFIG hook.${COLOR_RESET}" - echo -e "${COLOR_YELLOW}CONFIG deprecated; rename to OVERLAY.${COLOR_RESET}" - while read _dir; do - echo -e "${COLOR_GREEN}[${_dir}]:${COLOR_RESET}" - if [ -x $(which tree) ]; then - tree -a ${_template}/${_dir} - fi - done < ${_template}/CONFIG - fi - - ## remove bad templates - if [ ${_hook_validate} -lt 1 ]; then - echo -e "${COLOR_GREEN}Template validation failed.${COLOR_RESET}" - echo -e "${COLOR_GREEN}Deleting template.${COLOR_RESET}" - rm -rf ${_template} - exit 1 - fi - - ## if validated; ready to use - if [ ${_hook_validate} -gt 0 ]; then - echo -e "${COLOR_GREEN}Template ready to use.${COLOR_RESET}" - echo - fi + bastille verify ${_user}/${_repo} } HW_MACHINE=$(sysctl hw.machine | awk '{ print $2 }') @@ -486,8 +433,6 @@ http?://github.com/*/*|http?://gitlab.com/*/*) BASTILLE_TEMPLATE_URL=${1} BASTILLE_TEMPLATE_USER=$(echo "${1}" | awk -F / '{ print $4 }') BASTILLE_TEMPLATE_REPO=$(echo "${1}" | awk -F / '{ print $5 }') - echo -e "${COLOR_GREEN}Template: ${1}${COLOR_RESET}" - echo bootstrap_template ;; network) diff --git a/usr/local/share/bastille/template.sh b/usr/local/share/bastille/template.sh index c5a303a5..76edaba3 100644 --- a/usr/local/share/bastille/template.sh +++ b/usr/local/share/bastille/template.sh @@ -31,7 +31,7 @@ . /usr/local/share/bastille/colors.pre.sh . /usr/local/etc/bastille/bastille.conf -usage() { +bastille_usage() { echo -e "${COLOR_RED}Usage: bastille template TARGET project/template.${COLOR_RESET}" exit 1 } @@ -39,12 +39,12 @@ usage() { # Handle special-case commands first. case "$1" in help|-h|--help) - usage + bastille_usage ;; esac if [ $# -gt 2 ] || [ $# -lt 2 ]; then - usage + bastille_usage fi TARGET="${1}" @@ -60,24 +60,13 @@ fi TEMPLATE="${1}" shift -if [ ! -d "${bastille_templatesdir}"/"${TEMPLATE}" ]; then +if [ ! -d "${bastille_templatesdir}/${TEMPLATE}" ]; then echo -e "${COLOR_RED}${TEMPLATE} not found.${COLOR_RESET}" exit 1 fi ## global variables bastille_template=${bastille_templatesdir}/${TEMPLATE} -bastille_template_TARGET=${bastille_template}/TARGET -bastille_template_INCLUDE=${bastille_template}/INCLUDE -bastille_template_PRE=${bastille_template}/PRE -bastille_template_OVERLAY=${bastille_template}/OVERLAY -bastille_template_FSTAB=${bastille_template}/FSTAB -bastille_template_PF=${bastille_template}/PF -bastille_template_PKG=${bastille_template}/PKG -bastille_template_SYSRC=${bastille_template}/SYSRC -bastille_template_SERVICE=${bastille_template}/SERVICE -bastille_template_CMD=${bastille_template}/CMD - for _jail in ${JAILS}; do ## jail-specific variables. bastille_jail_path=$(jls -j "${_jail}" path) @@ -85,52 +74,86 @@ for _jail in ${JAILS}; do echo -e "${COLOR_GREEN}[${_jail}]:${COLOR_RESET}" ## TARGET - if [ -s "${bastille_template_TARGET}" ]; then - if [ $(grep -w "${_jail}" ${bastille_template_TARGET}) ]; then + if [ -s "${bastille_template}/TARGET" ]; then + if [ $(grep -w "${_jail}" ${bastille_template}/TARGET) ]; then echo -e "${COLOR_GREEN}TARGET: !${_jail}.${COLOR_RESET}" - echo + echo continue fi - if [ ! $(grep -E "(^|\b)(${_jail}|ALL)($|\b)" ${bastille_template_TARGET}) ]; then + if [ ! $(grep -E "(^|\b)(${_jail}|ALL)($|\b)" ${bastille_template}/TARGET) ]; then echo -e "${COLOR_GREEN}TARGET: ?${_jail}.${COLOR_RESET}" - echo + echo continue fi fi ## INCLUDE - if [ -s "${bastille_template_INCLUDE}" ]; then + if [ -s "${bastille_template}/INCLUDE" ]; then echo -e "${COLOR_GREEN}[${_jail}]:INCLUDE -- START${COLOR_RESET}" while read _include; do echo echo -e "${COLOR_GREEN}INCLUDE: ${_include}${COLOR_RESET}" echo -e "${COLOR_GREEN}Bootstrapping ${_include}...${COLOR_RESET}" - bastille bootstrap ${_include} + + case ${_include} in + http?://github.com/*/*|http?://gitlab.com/*/*) + bastille bootstrap ${_include} + ;; + */*) + BASTILLE_TEMPLATE_USER=$(echo "${_include}" | awk -F / '{ print $1 }') + BASTILLE_TEMPLATE_REPO=$(echo "${_include}" | awk -F / '{ print $2 }') + bastille template ${_jail} ${BASTILLE_TEMPLATE_USER}/${BASTILLE_TEMPLATE_REPO} + ;; + *) + echo -e "${COLOR_RED}Template INCLUDE content not recognized.${COLOR_RESET}" + exit 1 + ;; + esac echo echo -e "${COLOR_GREEN}Applying ${_include}...${COLOR_RESET}" BASTILLE_TEMPLATE_PROJECT=$(echo "${_include}" | awk -F / '{ print $4}') BASTILLE_TEMPLATE_REPO=$(echo "${_include}" | awk -F / '{ print $5}') bastille template ${_jail} ${BASTILLE_TEMPLATE_PROJECT}/${BASTILLE_TEMPLATE_REPO} - done < "${bastille_template_INCLUDE}" + done < "${bastille_template}/INCLUDE" echo -e "${COLOR_GREEN}[${_jail}]:INCLUDE -- END${COLOR_RESET}" echo fi ## PRE - if [ -s "${bastille_template_PRE}" ]; then + if [ -s "${bastille_template}/PRE" ]; then echo -e "${COLOR_GREEN}[${_jail}]:PRE -- START${COLOR_RESET}" - jexec -l ${_jail} /bin/sh < "${bastille_template_PRE}" || exit 1 + jexec -l ${_jail} /bin/sh < "${bastille_template}/PRE" || exit 1 echo -e "${COLOR_GREEN}[${_jail}]:PRE -- END${COLOR_RESET}" echo fi + ## FSTAB + if [ -s "${bastille_template}/FSTAB" ]; then + echo -e "${COLOR_GREEN}NOT YET IMPLEMENTED.${COLOR_RESET}" + fi + + ## PF + if [ -s "${bastille_template}/PF" ]; then + echo -e "${COLOR_GREEN}NOT YET IMPLEMENTED.${COLOR_RESET}" + fi + + ## PKG (bootstrap + pkg) + if [ -s "${bastille_template}/PKG" ]; then + echo -e "${COLOR_GREEN}[${_jail}]:PKG -- START${COLOR_RESET}" + jexec -l "${_jail}" env ASSUME_ALWAYS_YES=YES /usr/sbin/pkg bootstrap || exit 1 + jexec -l "${_jail}" env ASSUME_ALWAYS_YES=YES /usr/sbin/pkg install $(cat ${bastille_template}/PKG) || exit 1 + jexec -l "${_jail}" env ASSUME_ALWAYS_YES=YES /usr/sbin/pkg audit -F + echo -e "${COLOR_GREEN}[${_jail}]:PKG -- END${COLOR_RESET}" + echo + fi + ## CONFIG / OVERLAY - if [ -s "${bastille_template_OVERLAY}" ]; then + if [ -s "${bastille_template}/OVERLAY" ]; then echo -e "${COLOR_GREEN}[${_jail}]:OVERLAY -- START${COLOR_RESET}" while read _dir; do cp -av "${bastille_template}/${_dir}" "${bastille_jail_path}" || exit 1 - done < ${bastille_template_OVERLAY} + done < ${bastille_template}/OVERLAY echo -e "${COLOR_GREEN}[${_jail}]:OVERLAY -- END${COLOR_RESET}" echo fi @@ -144,54 +167,30 @@ for _jail in ${JAILS}; do echo fi - ## FSTAB - if [ -s "${bastille_template_FSTAB}" ]; then - bastille_templatefstab=$(cat "${bastille_template_FSTAB}") - echo -e "${COLOR_GREEN}Updating fstab.${COLOR_RESET}" - echo -e "${COLOR_GREEN}NOT YET IMPLEMENTED.${COLOR_RESET}" - fi - - ## PF - if [ -s "${bastille_template_PF}" ]; then - bastille_templatepf=$(cat "${bastille_template_PF}") - echo -e "${COLOR_GREEN}Generating PF profile.${COLOR_RESET}" - echo -e "${COLOR_GREEN}NOT YET IMPLEMENTED.${COLOR_RESET}" - fi - - ## PKG (bootstrap + pkg) - if [ -s "${bastille_template_PKG}" ]; then - echo -e "${COLOR_GREEN}[${_jail}]:PKG -- START${COLOR_RESET}" - jexec -l "${_jail}" env ASSUME_ALWAYS_YES=YES /usr/sbin/pkg bootstrap || exit 1 - jexec -l "${_jail}" env ASSUME_ALWAYS_YES=YES /usr/sbin/pkg audit -F - jexec -l "${_jail}" env ASSUME_ALWAYS_YES=YES /usr/sbin/pkg install $(cat ${bastille_template_PKG}) || exit 1 - echo -e "${COLOR_GREEN}[${_jail}]:PKG -- END${COLOR_RESET}" - echo - fi - ## SYSRC - if [ -s "${bastille_template_SYSRC}" ]; then + if [ -s "${bastille_template}/SYSRC" ]; then echo -e "${COLOR_GREEN}[${_jail}]:SYSRC -- START${COLOR_RESET}" while read _sysrc; do jexec -l ${_jail} /usr/sbin/sysrc "${_sysrc}" || exit 1 - done < "${bastille_template_SYSRC}" + done < "${bastille_template}/SYSRC" echo -e "${COLOR_GREEN}[${_jail}]:SYSRC -- END${COLOR_RESET}" echo fi ## SERVICE - if [ -s "${bastille_template_SERVICE}" ]; then + if [ -s "${bastille_template}/SERVICE" ]; then echo -e "${COLOR_GREEN}[${_jail}]:SERVICE -- START${COLOR_RESET}" while read _service; do jexec -l ${_jail} /usr/sbin/service ${_service} || exit 1 - done < "${bastille_template_SERVICE}" + done < "${bastille_template}/SERVICE" echo -e "${COLOR_GREEN}[${_jail}]:SERVICE -- END${COLOR_RESET}" echo fi ## CMD - if [ -s "${bastille_template_CMD}" ]; then + if [ -s "${bastille_template}/CMD" ]; then echo -e "${COLOR_GREEN}[${_jail}]:CMD -- START${COLOR_RESET}" - jexec -l ${_jail} /bin/sh < "${bastille_template_CMD}" || exit 1 + jexec -l ${_jail} /bin/sh < "${bastille_template}/CMD" || exit 1 echo -e "${COLOR_GREEN}[${_jail}]:CMD -- END${COLOR_RESET}" echo fi diff --git a/usr/local/share/bastille/verify.sh b/usr/local/share/bastille/verify.sh index 7a276887..cbb72617 100644 --- a/usr/local/share/bastille/verify.sh +++ b/usr/local/share/bastille/verify.sh @@ -31,32 +31,130 @@ . /usr/local/share/bastille/colors.pre.sh . /usr/local/etc/bastille/bastille.conf -usage() { - echo -e "${COLOR_RED}Usage: bastille verify release.${COLOR_RESET}" +bastille_usage() { + echo -e "${COLOR_RED}Usage: bastille verify [release|template].${COLOR_RESET}" exit 1 } +verify_release() { + if [ ! -z "$(freebsd-version | grep -i HBSD)" ]; then + echo -e "${COLOR_RED}Not yet supported on HardenedBSD.${COLOR_RESET}" + exit 1 + fi + + if [ -d "${bastille_releasesdir}/${RELEASE}" ]; then + freebsd-update -b "${bastille_releasesdir}/${RELEASE}" --currently-running ${RELEASE} IDS + else + echo -e "${COLOR_RED}${RELEASE} not found. See bootstrap.${COLOR_RESET}" + exit 1 + fi +} + +verify_template() { + _template_path=${bastille_templatesdir}/${BASTILLE_TEMPLATE} + _hook_validate=0 + + for _hook in TARGET INCLUDE PRE OVERLAY FSTAB PF PKG SYSRC SERVICE CMD; do + _path=${_template_path}/${_hook} + if [ -s ${_path} ]; then + _hook_validate=$((_hook_validate+1)) + echo -e "${COLOR_GREEN}Detected ${_hook} hook.${COLOR_RESET}" + + ## 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}" + echo -e "${COLOR_RED}${BASTILLE_TEMPLATE}:${_hook} [failed].${COLOR_RESET}" + echo -e "${COLOR_RED}Line numbers don't match line breaks.${COLOR_RESET}" + echo + echo -e "${COLOR_RED}Template validation failed.${COLOR_RESET}" + exit 1 + + ## if INCLUDE; recursive verify + elif [ ${_hook} = 'INCLUDE' ]; then + echo -e "${COLOR_GREEN}[${_hook}]:${COLOR_RESET}" + cat "${_path}" + echo + while read _include; do + echo -e "${COLOR_GREEN}[${_hook}]:[${_include}]:${COLOR_RESET}" + + case ${_include} in + http?://github.com/*/*|http?://gitlab.com/*/*) + bastille bootstrap ${_include} + ;; + */*) + BASTILLE_TEMPLATE_USER=$(echo "${_include}" | awk -F / '{ print $1 }') + BASTILLE_TEMPLATE_REPO=$(echo "${_include}" | awk -F / '{ print $2 }') + bastille verify ${BASTILLE_TEMPLATE_USER}/${BASTILLE_TEMPLATE_REPO} + ;; + *) + echo -e "${COLOR_RED}Template INCLUDE content not recognized.${COLOR_RESET}" + exit 1 + ;; + esac + done < ${_path} + + ## if tree; tree -a bastille_template/_dir + elif [ ${_hook} = 'OVERLAY' ]; then + echo -e "${COLOR_GREEN}[${_hook}]:${COLOR_RESET}" + cat "${_path}" + echo + while read _dir; do + if [ -x /usr/local/bin/tree ]; then + echo -e "${COLOR_GREEN}[${_hook}]:[${_dir}]:${COLOR_RESET}" + tree -a ${_template_path}/${_dir} + echo + fi + done < ${_path} + else + echo -e "${COLOR_GREEN}[${_hook}]:${COLOR_RESET}" + cat "${_path}" + echo + fi + fi + done + + ## remove bad templates + if [ ${_hook_validate} -lt 1 ]; then + echo -e "${COLOR_RED}No valid template hooks found.${COLOR_RESET}" + echo -e "${COLOR_RED}Template discarded.${COLOR_RESET}" + rm -rf ${bastille_template} + exit 1 + fi + + ## if validated; ready to use + if [ ${_hook_validate} -gt 0 ]; then + echo -e "${COLOR_GREEN}Template ready to use.${COLOR_RESET}" + fi +} + # Handle special-case commands first. case "$1" in help|-h|--help) - usage + bastille_usage ;; esac if [ $# -gt 1 ] || [ $# -lt 1 ]; then - usage + bastille_usage fi -RELEASE=$1 - -if [ ! -z "$(freebsd-version | grep -i HBSD)" ]; then - echo -e "${COLOR_RED}Not yet supported on HardenedBSD.${COLOR_RESET}" - exit 1 -fi - -if [ -d "${bastille_releasesdir}/${RELEASE}" ]; then - freebsd-update -b "${bastille_releasesdir}/${RELEASE}" IDS -else - echo -e "${COLOR_RED}${RELEASE} not found. See bootstrap.${COLOR_RESET}" - exit 1 -fi +case "$1" in +*-RELEASE|*-release|*-RC1|*-rc1|*-RC2|*-rc2) + RELEASE=$1 + verify_release + ;; +*-stable-LAST|*-STABLE-last|*-stable-last|*-STABLE-LAST) + RELEASE=$1 + verify_release + ;; +http?*) + bastille_usage + ;; +*/*) + BASTILLE_TEMPLATE=$1 + verify_template + ;; +*) + bastille_usage + ;; +esac