Use systemd-nspawn instead of chroot (#74)
All checks were successful
gitea/evobackup/pipeline/head This commit looks good

Reviewed-on: #74
This commit is contained in:
Ludovic Poujol 2024-08-28 17:16:39 +02:00
commit d44be2f567
34 changed files with 466 additions and 257 deletions

14
server/Vagrantfile vendored
View file

@ -24,7 +24,7 @@ mkdir -p /usr/lib/nagios/plugins/
SCRIPT
$deps = <<SCRIPT
DEBIAN_FRONTEND=noninteractive apt-get -yq install openssh-server btrfs-progs rsync lsb-base coreutils sed dash mount openssh-sftp-server libc6 bash-completion duc-nox cryptsetup bats
DEBIAN_FRONTEND=noninteractive apt-get -yq install openssh-server btrfs-progs rsync lsb-base coreutils sed dash mount openssh-sftp-server libc6 bash-completion duc-nox cryptsetup bats systemd-container monitoring-plugins-basic
SCRIPT
$pre_part = <<SCRIPT
@ -44,12 +44,18 @@ mount /dev/vdb /backup
SCRIPT
nodes = [
{ :version => "stretch", :fs => "btrfs" },
{ :version => "stretch", :fs => "ext4" },
# { :version => "stretch", :fs => "btrfs" },
# { :version => "stretch", :fs => "ext4" },
{ :version => "buster", :fs => "btrfs" },
{ :version => "buster", :fs => "ext4" },
{ :version => "bullseye", :fs => "ext4" },
{ :version => "bullseye", :fs => "btrfs" },
{ :version => "bullseye", :fs => "ext4" }
{ :version => "bookworm", :fs => "ext4" },
{ :version => "bookworm", :fs => "btrfs" }
]
nodes.each do |i|

View file

@ -85,7 +85,7 @@ case "${subcommand}" in
exit 1
fi
;;
"init" | "is-on")
"init" | "is-on" | "convert-v2" | "jail-version")
jail_name="${2:-}"
if [ -z "${jail_name}" ]; then
show_help
@ -104,7 +104,7 @@ case "${subcommand}" in
"${LIBDIR}/bkctld-${subcommand}" "${jail_name}" "${option}"
fi
;;
"start" | "stop" | "reload" | "restart" | "sync" | "update" | "remove" | "firewall" | "upgrade-config" | "archive")
"start" | "stop" | "reload" | "restart" | "sync" | "update" | "remove" | "firewall" | "upgrade-config" | "archive" | "log")
jail_name="${2:-}"
if [ "${jail_name}" = "all" ]; then
for jail in $("${LIBDIR}/bkctld-list"); do

View file

@ -24,7 +24,7 @@ test -d "${archive_jail_path}" && error "${jail_name}: archive already exists" 2
if [ "${FORCE}" != "1" ]; then
answer=""
while :; do
printf "> Are you sure you want to archive jail \`%s'? [Y,n,?] " "${jail_name}"
printf "> Are you sure you want to archive jail '%s'? [Y,n,?] " "${jail_name}"
read -r answer
case $answer in
[Yy]|"" )
@ -48,4 +48,7 @@ fi
mkdir -p "$(dirname "${archive_jail_path}")"
mv "${jail_path}" "${archive_jail_path}"
notice "Archive jail \`${jail_name}' : OK"
[ -e "/etc/systemd/nspawn/${jail_name}.nspawn" ] && rm "/etc/systemd/nspawn/${jail_name}.nspawn"
[ -e "/var/lib/machines/${jail_name}" ] && unlink "/var/lib/machines/${jail_name}"
notice "Archive jail '${jail_name}' : OK"

View file

@ -22,7 +22,7 @@ check_jail() {
jail_name=$1
jail_path=$(jail_path "${jail_name}")
canary_absolute_file="${jail_path}/var/backup/${CANARY_RELATIVE_FILE}"
canary_absolute_file="${jail_path}/data/${CANARY_RELATIVE_FILE}"
if [ -f "${canary_absolute_file}" ]; then
if grep --quiet --fixed-string "${date}" "${canary_absolute_file}"; then
@ -51,9 +51,9 @@ done
printf "%s - %s UNK / %s CRIT / %s WARN / %s OK\n\n" "${header}" "${nb_unkn}" "${nb_crit}" "${nb_warn}" "${nb_ok}"
printf "${output}" | grep -E "^UNKNOWN"
printf "${output}" | grep -E "^CRITICAL"
printf "${output}" | grep -E "^WARNING"
printf "${output}" | grep -E "^OK"
echo -n "${output}" | grep -E "^UNKNOWN"
echo -n "${output}" | grep -E "^CRITICAL"
echo -n "${output}" | grep -E "^WARNING"
echo -n "${output}" | grep -E "^OK"
exit "${return}"

View file

@ -25,7 +25,7 @@ for jail_name in $("${LIBDIR}/bkctld-list"); do
jail_config_epoch=$(date --date "$(stat -c %y "${incs_policy_file}")" +"%s")
# read each line in jail configuration
while read line; do
while read -r line; do
## TODO
# deal with empty lines

View file

@ -34,8 +34,8 @@ check_jail() {
unset local_warning
fi
# reset to default values if missing local value
: ${local_critical:=${CRITICAL}}
: ${local_warning:=${WARNING}}
: "${local_critical:=${CRITICAL}}"
: "${local_warning:=${WARNING}}"
if [ "${local_critical}" -gt "0" ] && [ "${date_diff}" -gt "${local_critical}" ]; then
nb_crit=$((nb_crit + 1))
@ -70,9 +70,9 @@ done
printf "%s - %s UNK / %s CRIT / %s WARN / %s OK\n\n" "${header}" "${nb_unkn}" "${nb_crit}" "${nb_warn}" "${nb_ok}"
printf "${output}" | grep -E "^UNKNOWN"
printf "${output}" | grep -E "^CRITICAL"
printf "${output}" | grep -E "^WARNING"
printf "${output}" | grep -E "^OK"
echo -n "${output}" | grep -E "^UNKNOWN"
echo -n "${output}" | grep -E "^CRITICAL"
echo -n "${output}" | grep -E "^WARNING"
echo -n "${output}" | grep -E "^OK"
exit "${return}"

View file

@ -15,15 +15,13 @@ nb_unkn=0
output=""
# Verify backup partition is mounted and writable
findmnt -O rw --mountpoint "${BACKUP_PARTITION}" > /dev/null
if [ "$?" -ne 0 ]; then
if ! findmnt -O rw --mountpoint "${BACKUP_PARTITION}" > /dev/null; then
nb_crit=$((nb_crit + 1))
output="${output}CRITICAL - Backup disk \`/backup' is not mounted (or read-only) !\n"
output="${output}CRITICAL - Backup disk '/backup' is not mounted (or read-only) !\n"
return=2
else
nb_ok=$((nb_ok + 1))
output="${output}OK - Backup disk \`/backup' is mounted and writable.\n"
output="${output}OK - Backup disk '/backup' is mounted and writable.\n"
fi
# Check if the firewall file is sourced
@ -38,14 +36,14 @@ if [ -n "${FIREWALL_RULES}" ] \
if [ -n "${minifirewall_version}" ] && dpkg --compare-versions "${minifirewall_version}" ge "22.03"; then
# Minifirewall 22.03+ includes files automatically
nb_ok=$((nb_ok + 1))
output="${output}OK - Firewall file \`${FIREWALL_RULES}' is present.\n"
output="${output}OK - Firewall file '${FIREWALL_RULES}' is present.\n"
else
if grep -qE "^(\.|source) ${FIREWALL_RULES}" "${minifirewall_config}"; then
nb_ok=$((nb_ok + 1))
output="${output}OK - Firewall file \`${FIREWALL_RULES}' is sourced by \`${minifirewall_config}'.\n"
output="${output}OK - Firewall file '${FIREWALL_RULES}' is sourced by '${minifirewall_config}'.\n"
else
nb_warn=$((nb_warn + 1))
output="${output}WARNING - Firewall file \`${FIREWALL_RULES}' doesn't seem to be sourced by \`${minifirewall_config}'\n"
output="${output}WARNING - Firewall file '${FIREWALL_RULES}' doesn't seem to be sourced by '${minifirewall_config}'\n"
[ "${return}" -le 1 ] && return=1
fi
fi
@ -85,9 +83,9 @@ fi
printf "%s - %s UNK / %s CRIT / %s WARN / %s OK\n\n" "${header}" "${nb_unkn}" "${nb_crit}" "${nb_warn}" "${nb_ok}"
printf "${output}" | grep -E "^UNKNOWN"
printf "${output}" | grep -E "^CRITICAL"
printf "${output}" | grep -E "^WARNING"
printf "${output}" | grep -E "^OK"
echo -n "${output}" | grep -E "^UNKNOWN"
echo -n "${output}" | grep -E "^CRITICAL"
echo -n "${output}" | grep -E "^WARNING"
echo -n "${output}" | grep -E "^OK"
exit "${return}"

25
server/lib/bkctld-convert-v2 Executable file
View file

@ -0,0 +1,25 @@
#!/bin/sh
#
# Description: Convert jail to v2 format
# Usage: convert-v2 <jailname>
#
# shellcheck source=./includes
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
jail_name="${1:?}"
if [ -z "${jail_name}" ]; then
show_help && exit 1
fi
jail_path=$(jail_path "${jail_name}")
test -d "${jail_path}" || error "${jail_name}: jail not found" 2
test "$(get_jail_version "${jail_name}")" -ne 1 && error "${jail_name}: This command only applies to jails in v1 format (currently $(get_jail_version "${jail_name}"))" 3
notice "Converting jail '${jail_name}'"
convert_jail_chroot_to_v2 "${jail_name}"
setup_jail_chroot "${jail_name}"
notice "Converted jail '${jail_name}' : OK"

View file

@ -18,7 +18,7 @@ iptables_input_accept() {
jail_name="${1}"
port="${2}"
ip="${3}"
debug "Accept \`${ip}:${port}' for jail \`${jail_name}'"
debug "Accept '${ip}:${port}' for jail '${jail_name}'"
echo "/sbin/iptables -A INPUT -p tcp --sport 1024: --dport ${port} -s ${ip} -j ACCEPT #${jail_name}"
}
@ -35,7 +35,7 @@ if [ -n "${FIREWALL_RULES}" ]; then
# Restart the firewall
[ -f /etc/init.d/minifirewall ] && /etc/init.d/minifirewall restart >/dev/null
fi
notice "Firewall updated for jail \`${jail_name}'"
notice "Firewall updated for jail '${jail_name}'"
else
notice "Skip jail \`${jail_name}' : FIREWALL_RULES variable is empty."
notice "Skip jail '${jail_name}' : FIREWALL_RULES variable is empty."
fi

View file

@ -46,21 +46,21 @@ create_inc_ext4() {
inc_name=$(date +"%Y-%m-%d-%H")
jails_list=$(jails_list)
jails_total=$(echo $jails_list | wc -w)
jails_total=$(echo "$jails_list" | wc -w)
jails_count=0
for jail_name in ${jails_list}; do
jails_count=$((jails_count+1))
jail_path=$(jail_path "${jail_name}")
inc_path=$(inc_path "${jail_name}" "${inc_name}")
incs_policy_file=$(current_jail_incs_policy_file ${jail_name})
incs_policy_file=$(current_jail_incs_policy_file "${jail_name}")
# If no incs policy is found, we don't create incs
if [ -n "${incs_policy_file}" ]; then
# If inc directory is not present, we proceed with inc creation
if [ ! -d "${inc_path}" ]; then
info "Progress: jail ${jails_count} out of ${jails_total}"
notice "Create inc \`${inc_name}' for jail \`${jail_name}' : start"
notice "Create inc '${inc_name}' for jail '${jail_name}' : start"
if is_btrfs "${jail_path}"; then
create_inc_btrfs "${jail_name}" "${inc_name}"
@ -68,11 +68,11 @@ for jail_name in ${jails_list}; do
create_inc_ext4 "${jail_name}" "${inc_name}"
fi
notice "Create inc \`${inc_name}' for jail \`${jail_name}' : finish"
notice "Create inc '${inc_name}' for jail '${jail_name}' : finish"
else
warning "Skip inc \`${inc_name}' for jail \`${jail_name}' : it already exists."
warning "Skip inc '${inc_name}' for jail '${jail_name}' : it already exists."
fi
else
notice "Skip jail \`${jail_name}' : incs policy is missing"
notice "Skip jail '${jail_name}' : incs policy is missing"
fi
done

View file

@ -38,16 +38,16 @@ unlock_target() {
}
# this directory test must be quoted,beacause of the probable globbing
if [ -d ${target_path} ]; then
if [ -d "${target_path}" ]; then
if [ "${lock_status}" = "on" ]; then
lock_target "${target_path}"
elif [ "${lock_status}" = "off" ]; then
unlock_target "${target_path}"
else
error "Unknown lock status \`${lock_status}'."
error "Unknown lock status '${lock_status}'."
exit 1
fi
else
error "\`${target_path}': no such file or directory."
error "'${target_path}': no such file or directory."
exit 1
fi

View file

@ -14,7 +14,7 @@ fi
jail_path=$(jail_path "${jail_name}")
incs_path=$(incs_path "${jail_name}")
test -d "${jail_path}" && error "Skip jail \`${jail_name}' : it already exists"
test -d "${jail_path}" && error "Skip jail '${jail_name}' : it already exists"
# Create config, jails and incs directories
mkdir --parents "${CONFDIR}" "${JAILDIR}" "${INCDIR}"
@ -34,4 +34,4 @@ mkdir --parents "${incs_path}"
setup_jail_chroot "${jail_name}"
setup_jail_config "${jail_name}"
notice "Create jail \`${jail_name}' : OK"
notice "Create jail '${jail_name}' : OK"

View file

@ -10,20 +10,23 @@ LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
jail_name="${1:?}"
ip="${2:-}"
if [ ! -n "${jail_name}" ]; then
if [ -z "${jail_name}" ]; then
show_help && exit 1
fi
jail_path=$(jail_path "${jail_name}")
jail_rootfs_path=$(jail_rootfs_path "${jail_name}")
test -d "${jail_path}" || error "${jail_name}: jail not found" 2
test -d "${jail_rootfs_path}" || error "${jail_name}: jail rootfs not found" 2
jail_sshd_config="${jail_path}/${SSHD_CONFIG}"
# Ensure we manipulate jails in the current/compatible version format
test "$(get_jail_version "${jail_name}")" -ne "${CURRENT_JAIL_VERSION}" && error "${jail_name}: jail needs to be uptated to version ${CURRENT_JAIL_VERSION} (currently $(get_jail_version "${jail_name}")) - Use bkctld convert-v2 <jail>" 3
jail_sshd_config="${jail_rootfs_path}/${SSHD_CONFIG}"
if [ -z "${ip}" ]; then
# parse IP addresses from AllowUsers directives in sshd config
grep -E "^AllowUsers" "${jail_sshd_config}" \
| grep -E -o "root@[^ ]+" \
| while read allow; do
| while read -r allow; do
echo "${allow}" | cut -d'@' -f2
done
else
@ -31,7 +34,7 @@ else
new_ips="0.0.0.0/0"
else
existing_ips=$("${LIBDIR}/bkctld-ip" "${jail_name}")
new_ips=$(echo ${existing_ips} ${ip} | xargs -n1 | grep -v "0.0.0.0/0" | sort | uniq)
new_ips=$(echo "${existing_ips}" "${ip}" | xargs -n1 | grep -v "0.0.0.0/0" | sort | uniq)
fi
allow_users="AllowUsers"
for new_ip in ${new_ips}; do
@ -40,9 +43,9 @@ else
if grep -q -E "^AllowUsers" "${jail_sshd_config}"; then
sed --follow-symlinks --in-place "s~^AllowUsers .*~${allow_users}~" "${jail_sshd_config}"
else
error "No \`AllowUsers' directive found in \`${jail_sshd_config}'"
error "No 'AllowUsers' directive found in '${jail_sshd_config}'"
fi
notice "Update IP whitelist with \`${ip}' for jail \`${jail_name}' : OK"
notice "Update IP whitelist with '${ip}' for jail '${jail_name}' : OK"
"${LIBDIR}/bkctld-reload" "${jail_name}"
"${LIBDIR}/bkctld-firewall" "${jail_name}"
fi

View file

@ -16,17 +16,9 @@ jail_path=$(jail_path "${jail_name}")
test -d "${jail_path}" || error "${jail_name}: jail not found" 2
jail_pid_file="${jail_path}/${SSHD_PID}"
# Error codes are references in "includes" file
return=100
if [ -f "${jail_pid_file}" ]; then
pid=$(cat "${jail_pid_file}")
ps -p "${pid}" > /dev/null && return=0
fi
if [ "${return}" -gt 0 ]; then
rm -f "${jail_pid_file}"
grep -q "${jail_path}/proc" /proc/mounts && umount --lazy "${jail_path}/proc/"
grep -q "${jail_path}/dev" /proc/mounts && umount --lazy --recursive "${jail_path}/dev"
if systemctl is-active --quiet systemd-nspawn@"${jail_name}"; then
return=0
fi
exit "${return}"

19
server/lib/bkctld-jail-version Executable file
View file

@ -0,0 +1,19 @@
#!/bin/sh
#
# Description: Returns the jail version
# Usage: jail-version <jailname>
#
# shellcheck source=./includes
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
jail_name="${1:?}"
if [ -z "${jail_name}" ]; then
show_help && exit 1
fi
jail_path=$(jail_path "${jail_name}")
test -d "${jail_path}" || error "${jail_name}: jail not found" 2
get_jail_version "${jail_name}"

View file

@ -10,20 +10,23 @@ LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
jail_name="${1:?}"
keyfile="${2:-}"
if [ ! -n "${jail_name}" ]; then
if [ -z "${jail_name}" ]; then
show_help && exit 1
fi
jail_path=$(jail_path "${jail_name}")
jail_rootfs_path=$(jail_rootfs_path "${jail_name}")
test -d "${jail_path}" || error "${jail_name}: jail not found" 2
test -d "${jail_rootfs_path}" || error "${jail_name}: jail rootfs not found" 2
# Ensure we manipulate jails in the current/compatible version format
test "$(get_jail_version "${jail_name}")" -ne "${CURRENT_JAIL_VERSION}" && error "${jail_name}: jail needs to be uptated to version ${CURRENT_JAIL_VERSION} (currently $(get_jail_version "${jail_name}")) - Use bkctld convert-v2 <jail>" 3
if [ -z "${keyfile}" ]; then
if [ -f "${jail_path}/${AUTHORIZED_KEYS}" ]; then
cat "${jail_path}/${AUTHORIZED_KEYS}"
if [ -f "${jail_rootfs_path}/${AUTHORIZED_KEYS}" ]; then
cat "${jail_rootfs_path}/${AUTHORIZED_KEYS}"
fi
else
test -r "${keyfile}" || error "SSH key \`${keyfile}' for jail \`${jail_name}' is missing or is not readable."
cat "${keyfile}" > "${jail_path}/${AUTHORIZED_KEYS}"
chmod 600 "${jail_path}/${AUTHORIZED_KEYS}"
notice "Update SSH key \`${keyfile}' for jail \`${jail_name}' : OK"
test -r "${keyfile}" || error "SSH key '${keyfile}' for jail '${jail_name}' is missing or is not readable."
cat "${keyfile}" > "${jail_rootfs_path}/${AUTHORIZED_KEYS}"
chmod 600 "${jail_rootfs_path}/${AUTHORIZED_KEYS}"
notice "Update SSH key '${keyfile}' for jail '${jail_name}' : OK"
fi

20
server/lib/bkctld-log Executable file
View file

@ -0,0 +1,20 @@
#!/bin/sh
#
# Description: Show jail log (with journalctl)
# Usage: log <jailname>
#
set -eu
# shellcheck source=./includes
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
jail_name="${1:?}"
if [ -z "${jail_name}" ]; then
show_help && exit 1
fi
jail_path=$(jail_path "${jail_name}")
test -d "${jail_path}" || error "${jail_name}: jail not found" 2
journalctl --reverse --unit systemd-nspawn@"${jail_name}"

View file

@ -10,26 +10,26 @@ LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
jail_name="${1:?}"
port="${2:-}"
if [ ! -n "${jail_name}" ]; then
if [ -z "${jail_name}" ]; then
show_help && exit 1
fi
jail_path=$(jail_path "${jail_name}")
jail_rootfs_path=$(jail_rootfs_path "${jail_name}")
test -d "${jail_path}" || error "${jail_name}: jail not found" 2
test -d "${jail_rootfs_path}" || error "${jail_name}: jail not found" 2
jail_sshd_config="${jail_path}/${SSHD_CONFIG}"
jail_sshd_config="${jail_rootfs_path}/${SSHD_CONFIG}"
if [ -z "${port}" ]; then
grep -E "Port [0-9]+" "${jail_sshd_config}"|grep -oE "[0-9]+"
else
if [ "${port}" = "auto" ]; then
port=$(grep -h Port "${JAILDIR}"/*/"${SSHD_CONFIG}" 2>/dev/null | grep -Eo "[0-9]+" | sort -n | tail -1)
port=$(grep -h Port "${JAILDIR}"/*/rootfs/"${SSHD_CONFIG}" 2>/dev/null | grep -Eo "[0-9]+" | sort -n | tail -1)
port=$((port+1))
[ "${port}" -le 1 ] && port=2222
fi
sed --follow-symlinks --in-place "s/^Port .*/Port ${port}/" "${jail_sshd_config}"
notice "Update SSH port \`${port}' for jail \`${jail_name}' : OK"
notice "Update SSH port '${port}' for jail '${jail_name}' : OK"
"${LIBDIR}/bkctld-reload" "${jail_name}"
"${LIBDIR}/bkctld-firewall" "${jail_name}"

View file

@ -17,10 +17,10 @@ test -d "${jail_path}" || error "${jail_name}: jail not found" 2
"${LIBDIR}/bkctld-is-on" "${jail_name}" || exit 0
pid=$(cat "${jail_path}/${SSHD_PID}")
pid=$(get_jail_sshd_pid "${jail_name}")
if kill -HUP "${pid}"; then
notice "Reload jail \`${jail_name}' : OK [${pid}]"
notice "Reload jail '${jail_name}' : OK [${pid}]"
else
error "Reload jail \`${jail_name}' : failed [${pid}]"
error "Reload jail '${jail_name}' : failed [${pid}]"
fi

View file

@ -28,7 +28,7 @@ fi
if [ "${FORCE}" != "1" ]; then
answer=""
while :; do
printf "> Are you sure you want to delete jail \`%s'? [Y,n,?] " "${jail_name}"
printf "> Are you sure you want to delete jail '%s'? [Y,n,?] " "${jail_name}"
read -r answer
case $answer in
[Yy]|"" )
@ -71,11 +71,14 @@ if [ -d "${incs_path}" ]; then
if [ "${inc_inode}" -eq 256 ]; then
${btrfs_bin} subvolume delete "${incs_path}/${inc}" | debug
else
warning "You need to purge \`${incs_path}/${inc}' manually"
warning "You need to purge '${incs_path}/${inc}' manually"
fi
done
rmdir --ignore-fail-on-non-empty "${incs_path}" | debug
fi
[ -e "/etc/systemd/nspawn/${jail_name}.nspawn" ] && rm "/etc/systemd/nspawn/${jail_name}.nspawn"
[ -e "/var/lib/machines/${jail_name}" ] && unlink "/var/lib/machines/${jail_name}"
"${LIBDIR}/bkctld-firewall" "${jail_name}"
notice "Delete jail \`${jail_name}' : OK"
notice "Delete jail '${jail_name}' : OK"

View file

@ -16,6 +16,7 @@ if [ -z "${jail_name}" ] || [ -z "${new_jail_name}" ]; then
fi
jail_path=$(jail_path "${jail_name}")
#jail_rootfs_path=$(jail_rootfs_path "${jail_name}")
incs_path=$(incs_path "${jail_name}")
jail_config_dir=$(jail_config_dir "${jail_name}")
legacy_config_file="${CONFDIR}/${jail_name}"
@ -23,6 +24,7 @@ legacy_config_file="${CONFDIR}/${jail_name}"
test -d "${jail_path}" || error "${jail_name}: jail not found" 2
new_jail_path=$(jail_path "${new_jail_name}")
new_jail_rootfs_path=$(jail_rootfs_path "${new_jail_name}")
new_incs_path=$(incs_path "${new_jail_name}")
new_jail_config_dir=$(jail_config_dir "${new_jail_name}")
new_legacy_config_file="${CONFDIR}/${new_jail_name}"
@ -40,18 +42,28 @@ case "$?" in
;;
*)
unset jail_initial_status
error "Error evaluating jail \`${jail_name}' state. bkctld-is-on exited with \`$?'"
error "Error evaluating jail '${jail_name}' state. bkctld-is-on exited with '$?'"
;;
esac
test "${jail_initial_status}" = "on" && "${LIBDIR}/bkctld-stop" "${jail_name}"
# Rename jail folder
if dry_run; then
echo "[dry-run] rename ${jail_path} to ${new_jail_path}"
else
mv "${jail_path}" "${new_jail_path}"
# Re-create the link in /var/lib/machines/
[ -e "/var/lib/machines/${jail_name}" ] && unlink "/var/lib/machines/${jail_name}"
ln -s "${new_jail_rootfs_path}" "/var/lib/machines/${new_jail_name}"
# Generate new nspawn config
[ -e "/etc/systemd/nspawn/${jail_name}.nspawn" ] && rm "/etc/systemd/nspawn/${jail_name}.nspawn"
generate_jail_nspawn_config "${new_jail_name}"
fi
# Rename incs folder
if [ -d "${incs_path}" ]; then
if dry_run; then
echo "[dry-run] rename ${incs_path} to ${new_incs_path}"
@ -60,6 +72,7 @@ if [ -d "${incs_path}" ]; then
fi
fi
# Rename configs
if [ -d "${jail_config_dir}" ]; then
if dry_run; then
echo "[dry-run] rename ${jail_config_dir} to ${new_jail_config_dir}"
@ -74,10 +87,11 @@ if [ -f "${legacy_config_file}" ]; then
echo "[dry-run] rename ${legacy_config_file} to ${new_legacy_config_file}"
fi
fi
# Reset firewall for new jail name
"${LIBDIR}/bkctld-firewall" "${jail_name}"
"${LIBDIR}/bkctld-firewall" "${new_jail_name}"
test "${jail_initial_status}" = "on" && "${LIBDIR}/bkctld-start" "${new_jail_name}"
notice "Rename jail \`${jail_name}' to \`${new_jail_name}' : OK"
notice "Rename jail '${jail_name}' to '${new_jail_name}' : OK"

View file

@ -20,16 +20,16 @@ kill_or_clean_lockfile() {
# Kill the parent
kill -9 "${pid}"
# Only one bkctld-rm can run in parallel, the latest wins
lockfile_date=$(date --date "@$(stat -c %Y ${lock_file})" +"%Y-%m-%d %H:%M:%S")
warning "Process \`${pid}' (started at ${lockfile_date}) has been killed by \`$$'"
lockfile_date=$(date --date "@$(stat -c %Y "${lock_file}")" +"%Y-%m-%d %H:%M:%S")
warning "Process '${pid}' (started at ${lockfile_date}) has been killed by '$$'"
else
warning "Process not found at PID \`${pid}'. Ignoring lock file \`${lock_file}'."
warning "Process not found at PID '${pid}'. Ignoring lock file '${lock_file}'."
fi
else
warning "Empty lockfile \`${lock_file}'. It should contain a PID."
warning "Empty lockfile '${lock_file}'. It should contain a PID."
fi
# Remove the lock file
rm -f ${lock_file}
rm -f "${lock_file}"
fi
}
incs_to_delete() {
@ -40,13 +40,13 @@ incs_to_delete() {
incs_list_file=$(new_tmp_file "${jail_name}.incs_list")
# loop for each line in jail configuration
for incs_policy_line in $(grep "^\+" ${incs_policy_file}); do
for incs_policy_line in $(grep "^\+" "${incs_policy_file}"); do
# inc date in ISO format
incs_policy_date=$(relative_date ${incs_policy_line})
echo ${incs_policy_date} >> "${incs_policy_keep_file}"
incs_policy_date=$(relative_date "${incs_policy_line}")
echo "${incs_policy_date}" >> "${incs_policy_keep_file}"
done
for inc_name in $(incs_list "${jail_name}"); do
echo "${inc_name}" >> ${incs_list_file}
echo "${inc_name}" >> "${incs_list_file}"
done
# shellcheck disable=SC2046
@ -54,7 +54,7 @@ incs_to_delete() {
rm -f "${incs_policy_keep_file}" "${incs_list_file}"
echo ${incs_to_delete}
echo "${incs_to_delete}"
}
delete_inc_btrfs() {
jail_name=$1
@ -97,10 +97,10 @@ delete_empty_inc() {
for empty_inc in ${empty_incs_list}; do
if dry_run; then
echo "[dry-run] Delete empty \`${empty_inc}'"
echo "[dry-run] Delete empty '${empty_inc}'"
else
rmdir "${empty_inc}"
notice "Delete empty \`${empty_inc}' : OK"
notice "Delete empty '${empty_inc}' : OK"
fi
done
}
@ -115,25 +115,25 @@ new_lock_file "${lock_file}"
# We list jails in "incs" directory, not in "jails" directory
# so we can clean old incs after a jail is archived
jails_list=$(jails_with_incs_list)
jails_total=$(echo $jails_list | wc -w)
jails_total=$(echo "$jails_list" | wc -w)
jails_count=0
for jail_name in ${jails_list}; do
jails_count=$((jails_count+1))
incs_policy_file=$(current_jail_incs_policy_file ${jail_name})
incs_policy_file=$(current_jail_incs_policy_file "${jail_name}")
# If no incs policy is found, we don't remove incs
if [ -n "${incs_policy_file}" ]; then
# shellcheck disable=SC2046
incs_to_delete=$(incs_to_delete "${jail_name}" "${incs_policy_file}")
incs_total=$(echo ${incs_to_delete} | wc -w)
incs_total=$(echo "${incs_to_delete}" | wc -w)
incs_count=0
if [ -n "${incs_to_delete}" ]; then
debug "Incs to be deleted for \`${jail_name}' : $(echo "${incs_to_delete}" | tr '\n', ',' | sed 's/,$//')."
debug "Incs to be deleted for '${jail_name}' : $(echo "${incs_to_delete}" | tr '\n', ',' | sed 's/,$//')."
for inc_name in ${incs_to_delete}; do
incs_count=$((incs_count+1))
info "Progress: jail ${jails_count} out of ${jails_total} - inc ${incs_count} out of ${incs_total}"
notice "Delete inc \`${inc_name}' for jail \`${jail_name}' : start"
notice "Delete inc '${inc_name}' for jail '${jail_name}' : start"
inc_path=$(inc_path "${jail_name}" "${inc_name}")
@ -143,13 +143,13 @@ for jail_name in ${jails_list}; do
delete_inc_ext4 "${jail_name}" "${inc_name}"
fi
notice "Delete inc \`${inc_name}' for jail \`${jail_name}' : finish"
notice "Delete inc '${inc_name}' for jail '${jail_name}' : finish"
done
else
notice "Skip jail \`${jail_name}' : no inc to delete"
notice "Skip jail '${jail_name}' : no inc to delete"
fi
else
notice "Skip jail \`${jail_name}' : incs policy is missing"
notice "Skip jail '${jail_name}' : incs policy is missing"
fi
# Delete empty incs directory for jail
delete_empty_inc "${jail_name}"

View file

@ -17,27 +17,46 @@ test -d "${jail_path}" || error "${jail_name}: jail not found" 2
"${LIBDIR}/bkctld-is-on" "${jail_name}" && exit 0
# Prepare the chroot
mount_jail_fs "${jail_name}"
# Ensure we only start jails in the current/compatible version format
test "$(get_jail_version "${jail_name}")" -ne "${CURRENT_JAIL_VERSION}" && error "${jail_name}: jail needs to be updated to version ${CURRENT_JAIL_VERSION} (currently $(get_jail_version "${jail_name}")) - Use bkctld convert-v2 <jail>" 3
# Start SSH in the chroot
chroot "${jail_path}" /usr/sbin/sshd -E /var/log/authlog || error "Failed to start SSH for jail \`${jail_name}'"
pidfile="${jail_path}/${SSHD_PID}"
# Start the jail
notice "Starting jail '${jail_name}'"
systemctl start systemd-nspawn@"${jail_name}" || error "Failed to start nspawn container for jail '${jail_name}'"
# Wait for SSH to be up
# shellcheck disable=SC2034
for try in $(seq 1 10); do
if [ -f "${pidfile}" ]; then
pid=$(cat "${pidfile}")
break
if systemctl is-active --quiet systemd-nspawn@"${jail_name}"; then
port=$("${LIBDIR}/bkctld-port" "${jail_name}")
success=1
for try in $(seq 1 10); do
# Is the jail still running?
if ! systemctl is-active --quiet systemd-nspawn@"${jail_name}"; then
printf 'x '
break
fi
# Is SSH alive and responding ?
if /usr/lib/nagios/plugins/check_ssh --port="${port}" localhost >/dev/null 2>&1; then
success=0
break
else
printf '.'
sleep 0.3
fi
done
if [ "${success}" -eq 0 ]; then
notice "OK SSH : Started jail '${jail_name}'"
else
pid=""
sleep 0.3
if systemctl is-active --quiet systemd-nspawn@"${jail_name}"; then
error "WARNING SSH : Jail is running, but failed to get response from sshd for jail '${jail_name}' within 3 seconds"
else
error "Failed to to start '${jail_name}' - Jail terminated. Check 'systemctl status systemd-nspawn@${jail_name}'"
fi
fi
done
if [ -n "${pid}" ]; then
notice "Start jail \`${jail_name}' : OK [${pid}]"
else
error "Failed to fetch SSH PID for jail \`${jail_name}' within 3 seconds"
error "Failed to to start '${jail_name}' - Jail terminated. Check 'systemctl status systemd-nspawn@${jail_name}'"
fi

View file

@ -16,7 +16,7 @@ touch "${INDEX_DIR}/.lastrun.duc"
EOF
[ ! -f "${INDEX_DIR}/.lastrun.duc" ] && notice "First run of DUC still in progress ..." && exit 0
[ ! -f ${IDX_FILE} ] && error "Index file doesn't exits !"
[ ! -f "${IDX_FILE}" ] && error "Index file doesn't exits !"
printf "Last update of index file : "
stat --format=%Y "${INDEX_DIR}/.lastrun.duc" | xargs -i -n1 date -R -d "@{}"
@ -33,7 +33,7 @@ trap "rm ${duc_output} ${incs_output} ${stat_output} ${jail_patterns_list}" 0
jails_list | sed -e "s/^\(.*\)$/\\\\b\1\\\\b/" > "${jail_patterns_list}"
grep -f "${jail_patterns_list}" "${duc_output}" | awk '{ print $2 }' | while read jail_name; do
grep -f "${jail_patterns_list}" "${duc_output}" | awk '{ print $2 }' | while read -r jail_name; do
jail_path=$(jail_path "${jail_name}")
stat --format=%Y "${jail_path}/var/log/lastlog" | xargs -i -n1 date -d "@{}" "+%d-%m-%Y" >> "${stat_output}"

View file

@ -8,12 +8,14 @@
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
jail_name="${1:?}"
if [ ! -n "${jail_name}" ]; then
if [ -z "${jail_name}" ]; then
show_help && exit 1
fi
[ -d "${JAILDIR}/${jail_name}" ] || error "${jail_name} : jail is missing.\nUse '$0 status [all]' to get the status of all jails."
incs_policy_file=$(current_jail_incs_policy_file ${jail_name})
test "$(get_jail_version "${jail_name}")" -ne "${CURRENT_JAIL_VERSION}" && error "${jail_name}: jail needs to be updated to version ${CURRENT_JAIL_VERSION} (currently $(get_jail_version "${jail_name}")) - Use bkctld convert-v2 <jail>" 3
incs_policy_file=$(current_jail_incs_policy_file "${jail_name}")
incs_policy="0"
if [ -r "${incs_policy_file}" ]; then
days=$(grep "^\+" "${incs_policy_file}" | grep --count "day")

View file

@ -15,17 +15,13 @@ jail_path=$(jail_path "${jail_name}")
test -d "${jail_path}" || error "${jail_name}: jail not found" 2
# Ensure we manipulate jails in the current/compatible version format
test "$(get_jail_version "${jail_name}")" -ne "${CURRENT_JAIL_VERSION}" && error "${jail_name}: jail needs to be updated to version ${CURRENT_JAIL_VERSION} (currently $(get_jail_version "${jail_name}")) - Use bkctld convert-v2 <jail>" 3
"${LIBDIR}/bkctld-is-on" "${jail_name}" || exit 0
pid=$(cat "${jail_path}/${SSHD_PID}")
pkill --parent "${pid}"
if kill "${pid}"; then
notice "Stop jail \`${jail_name}' : OK [${pid}]"
umount --lazy --recursive "${jail_path}/dev"
umount --lazy "${jail_path}/proc/"
if systemctl stop systemd-nspawn@"${jail_name}"; then
notice "Stopped jail '${jail_name}'"
else
error "Stop jail \`${jail_name}' : failed [${pid}]"
error "Stop jail '${jail_name}' : failed"
fi

View file

@ -16,7 +16,12 @@ jail_config_dir=$(jail_config_dir "${jail_name}")
test -d "${jail_path}" || error "${jail_name}: jail not found" 2
[ -n "${NODE}" ] || error "Sync need config of \$NODE in /etc/default/bkctld !"
[ -n "${NODE}" ] || error "Sync need config for \$NODE variable in /etc/default/bkctld !"
# Ensure the same version of bkctld runs on the other node
node_version=$(ssh "${NODE}" grep "^VERSION=" "${LIBDIR}/includes" | cut -d'=' -f2 | sed 's/"//g')
[ "${VERSION}" = "${node_version}" ] || error "bkctld version on the other server is different than ours (local: ${VERSION} -- node: ${node_version}) - Please ensure bkctld versions are the same and up to date."
ssh "${NODE}" "${LIBDIR}/bkctld-is-on ${jail_name} 2>/dev/null"
# return code 2 is for "missing jail" error
@ -25,8 +30,15 @@ if [ "$?" -eq 2 ]; then
ssh "${NODE}" "${LIBDIR}/bkctld-init ${jail_name}" | debug
fi
# Sync jail structure and configuration on remote server
rsync -a "${jail_path}/" "${NODE}:${jail_path}/" --exclude proc/* --exclude sys/* --exclude dev/* --exclude run --exclude var/backup/*
# Ensure jail version is the same
local_jail_version=$(get_jail_version "${jail_name}")
remote_jail_version=$(ssh "${NODE}" "${LIBDIR}/bkctld-jail-version ${jail_name}")
[ "${local_jail_version}" -eq "${remote_jail_version}" ] || error "remote jail isn't in the same version (local: ${local_jail_version} -- node: ${remote_jail_version}) - Please update it with bkctld convert-v2."
# Sync jail internal config on remote server
rsync -a "${jail_path}/rootfs/etc/" "${NODE}:${jail_path}/rootfs/etc/"
rsync -a "${jail_path}/rootfs/root/" "${NODE}:${jail_path}/rootfs/root/"
# Sync config (new structure)
if [ -d "${jail_config_dir}" ]; then
rsync -a --delete "${jail_config_dir}/" "${NODE}:${jail_config_dir}/"
@ -59,7 +71,7 @@ if "${LIBDIR}/bkctld-is-on" "${jail_name}"; then
ssh "${NODE}" "${LIBDIR}/bkctld-start ${jail_name}" | debug
;;
*)
error "Error evaluating jail \`${jail_name}' state. bkctld-is-on exited with \`$?'"
error "Error evaluating jail '${jail_name}' state. bkctld-is-on exited with '$?'"
;;
esac
else

View file

@ -8,13 +8,16 @@
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
jail_name="${1:?}"
if [ ! -n "${jail_name}" ]; then
if [ -z "${jail_name}" ]; then
show_help && exit 1
fi
jail_path=$(jail_path "${jail_name}")
test -d "${jail_path}" || error "${jail_name}: jail not found" 2
# Ensure we manipulate jails in the current/compatible version format
test "$(get_jail_version "${jail_name}")" -ne "${CURRENT_JAIL_VERSION}" && error "${jail_name}: jail needs to be updated to version ${CURRENT_JAIL_VERSION} (currently $(get_jail_version "${jail_name}")) - Use bkctld convert-v2 <jail>" 3
"${LIBDIR}/bkctld-is-on" "${jail_name}" 2>/dev/null
case "$?" in
0)
@ -25,7 +28,7 @@ case "$?" in
;;
*)
unset jail_initial_status
error "Error evaluating jail \`${jail_name}' state. bkctld-is-on exited with \`$?'"
error "Error evaluating jail '${jail_name}' state. bkctld-is-on exited with '$?'"
;;
esac
@ -35,4 +38,4 @@ setup_jail_chroot "${jail_name}"
test "${jail_initial_status}" = "on" && "${LIBDIR}/bkctld-start" "${jail_name}"
notice "Update jail \`${jail_name}' : OK"
notice "Update jail '${jail_name}' : OK"

View file

@ -8,7 +8,7 @@
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
jail_name="${1:?}"
if [ ! -n "${jail_name}" ]; then
if [ -z "${jail_name}" ]; then
show_help && exit 1
fi
jail_path=$(jail_path "${jail_name}")

View file

@ -6,7 +6,8 @@
[ -f /etc/default/bkctld ] && . /etc/default/bkctld
VERSION="22.11"
VERSION="24.08"
CURRENT_JAIL_VERSION="2"
LIBDIR=${LIBDIR:-/usr/lib/bkctld}
CONFDIR="${CONFDIR:-/etc/evobackup}"
@ -65,17 +66,17 @@ EOF
}
is_quiet() {
test ${QUIET} -eq 1
test "${QUIET}" -eq 1
}
is_verbose() {
test ${VERBOSE} -eq 1
test "${VERBOSE}" -eq 1
}
log_date() {
echo "[$(date +"%Y-%m-%d %H:%M:%S")]"
}
process_name() {
basename $0
basename "$0"
}
debug() {
msg="${1:-$(cat /dev/stdin)}"
@ -119,7 +120,7 @@ error() {
tty -s || echo "${msg}" >&2
logger -t bkctld -p daemon.error "$(process_name) ${msg}"
fi
exit ${rc}
exit "${rc}"
}
dry_run() {
@ -155,6 +156,16 @@ jail_path() {
echo "${JAILDIR}/${jail_name}"
}
jail_rootfs_path() {
jail_name=${1:?}
echo "${JAILDIR}/${jail_name}/rootfs"
}
jail_var_path() {
jail_name=${1:?}
echo "${JAILDIR}/${jail_name}/var"
}
jail_config_dir() {
jail_name=${1:?}
@ -193,6 +204,7 @@ inc_exists() {
inc_path=$(inc_path "${jail_name}" "${inc_pattern}")
# inc_path must not be quoted because it can contain globs
# shellcheck disable=SC2086
ls -d ${inc_path} > /dev/null 2>&1
}
# Returns the list of all incs for a jail
@ -202,7 +214,7 @@ incs_list() {
}
# Return the list of empty incs directories
empty_incs_list() {
find ${INCDIR} -mindepth 1 -maxdepth 1 -type d -empty
find "${INCDIR}" -mindepth 1 -maxdepth 1 -type d -empty
}
current_jail_incs_policy_file() {
jail_name=${1:?}
@ -241,13 +253,13 @@ current_jail_check_policy_file() {
}
# relative_date "+%Y-%m-%d.-2day"
relative_date() {
format=$(echo $1 | cut -d'.' -f1)
time_jump=$(echo $1 | cut -d'.' -f2)
format=$(echo "$1" | cut -d'.' -f1)
time_jump=$(echo "$1" | cut -d'.' -f2)
reference_date=$(date "${format}")
past_date=$(date --date "${reference_date} ${time_jump}" +"%Y-%m-%d")
echo ${past_date}
echo "${past_date}"
}
new_tmp_file() {
name=${1:-}
@ -266,12 +278,12 @@ new_lock_file() {
lock_file=${1:-}
lock_dir=$(dirname "${lock_file}")
mkdir --parents "${lock_dir}" && echo $$ > ${lock_file} || error "Failed to acquire lock file '${lock_file}'"
mkdir --parents "${lock_dir}" && echo $$ > "${lock_file}" || error "Failed to acquire lock file '${lock_file}'"
}
pkg_version() {
# $(command -v ssh) -V 2>&1 | grep -iEo 'OpenSSH_(\S+)' | cut -d '_' -f2
dpkg-query -W -f='${Version}\n' $1 \
dpkg-query -W -f='${Version}\n' "$1" \
| sed 's/[~+-].\+//' \
| sed 's/.\+://' \
| sed 's/p.*//' \
@ -286,6 +298,12 @@ setup_jail_chroot() {
jail_name=${1:?}
jail_path=$(jail_path "${jail_name}")
jail_rootfs_path=$(jail_rootfs_path "${jail_name}")
jail_var_path=$(jail_var_path "${jail_name}")
mkdir --parents "${jail_rootfs_path}"
mkdir --parents "${jail_var_path}"
mkdir --parents "${jail_path}"/data
passwd="${TPLDIR}/passwd"
shadow="${TPLDIR}/shadow"
@ -299,99 +317,123 @@ setup_jail_chroot() {
cd "${jail_path}" || error "${jail_name}: failed to change directory to ${jail_path}."
umask 077
info "1 - Creating the chroot"
info "1 - Creating the jail directories"
echo "${CURRENT_JAIL_VERSION}" > ./version
rm -rf ./bin
rm -rf ./lib
rm -rf ./lib64
rm -rf ./run
rm -rf ./usr
rm -rf ./var/run
# Let's not delete the existing SSH host keys,
rm -rf ./rootfs/usr
rm -rf ./rootfs/bin
rm -rf ./rootfs/lib
rm -rf ./rootfs/lib64
# Let's not delete the existing SSH host keys and server config
# otherwise the clients will have to accept the new keys
mkdir -p ./dev
mkdir -p ./proc
mkdir -p ./usr/bin
mkdir -p ./usr/sbin
mkdir -p ./usr/lib
mkdir -p ./usr/lib/x86_64-linux-gnu
mkdir -p ./usr/lib/openssh
mkdir -p ./usr/lib64
mkdir -p ./etc/ssh
mkdir -p ./rootfs/dev
mkdir -p ./rootfs/proc
mkdir -p ./rootfs/run
mkdir -p ./rootfs/tmp
mkdir -p ./rootfs/data
mkdir -p ./rootfs/usr/bin
mkdir -p ./rootfs/usr/sbin
mkdir -p ./rootfs/usr/lib
mkdir -p ./rootfs/usr/lib/x86_64-linux-gnu
mkdir -p ./rootfs/usr/lib/openssh
mkdir -p ./rootfs/usr/lib64
mkdir -p ./rootfs/etc/ssh
mkdir -p ./var/log
mkdir -p ./run/sshd
# shellcheck disable=SC2174
mkdir -p ./root/.ssh --mode 0700
mkdir -p ./rootfs/root/.ssh --mode 0700
# shellcheck disable=SC2174
mkdir -p ./var/backup --mode 0700
ln -s ./usr/bin ./bin
ln -s ./usr/lib ./lib
ln -s ./usr/lib64 ./lib64
ln -s --target-directory=./var ../run
ln -s ./usr/bin ./rootfs/bin
ln -s ./usr/lib ./rootfs/lib
ln -s ./usr/lib64 ./rootfs/lib64
touch ./rootfs/etc/localtime ./rootfs/etc/resolv.conf
touch ./var/log/lastlog ./var/log/wtmp
touch ./var/log/lastlog ./var/log/wtmp ./run/utmp
info "2 - Copying essential files"
#
if ssh_keygen_with_prefix; then
# Generate SSH host keys if missing in jail
ssh-keygen -A -f "${jail_path}"
ssh-keygen -A -f "${jail_rootfs_path}"
else
# Copy SSH host keys from host if missing in jail
for key in /etc/ssh/*_key; do
cp --no-clobber ${key} ${jail_path}${key};
cp --no-clobber "${key}" "${jail_rootfs_path}"/"${key}";
done
fi
touch "./${AUTHORIZED_KEYS}"
chmod 600 "./${AUTHORIZED_KEYS}"
touch "./rootfs/${AUTHORIZED_KEYS}"
chmod 600 "./rootfs/${AUTHORIZED_KEYS}"
cp "${passwd}" ./etc
cp "${shadow}" ./etc
cp "${group}" ./etc
cp "${sshrc}" ./etc/ssh
cp "${passwd}" ./rootfs/etc
cp "${shadow}" ./rootfs/etc
cp "${group}" ./rootfs/etc
cp "${sshrc}" ./rootfs/etc/ssh
cp /etc/os-release ./rootfs/etc/os-release
sed -i -E 's/^ID=(.*)$/ID=\1-bkctld/g' ./rootfs/etc/os-release
info "3 - Copying binaries"
cp -f /lib/ld-linux.so.2 ./lib 2>/dev/null || cp -f /lib64/ld-linux-x86-64.so.2 ./lib64
cp /lib/x86_64-linux-gnu/libnss* ./lib/x86_64-linux-gnu
cp -f /usr/lib/ld-linux.so.2 ./rootfs/usr/lib 2>/dev/null || cp -f /usr/lib64/ld-linux-x86-64.so.2 ./rootfs/usr/lib64
cp /usr/lib/x86_64-linux-gnu/libnss* ./rootfs/usr/lib/x86_64-linux-gnu
for dbin in \
/bin/sh \
/bin/ls \
/bin/mkdir \
/bin/cat \
/bin/rm \
/bin/sed \
/usr/bin/sh \
/usr/bin/ls \
/usr/bin/mkdir \
/usr/bin/cat \
/usr/bin/rm \
/usr/bin/sed \
/usr/bin/rsync \
/usr/bin/lastlog \
/usr/bin/touch \
/usr/sbin/sshd \
/usr/lib/openssh/sftp-server\
; do
cp -f "${dbin}" "./${dbin}";
cp -f "${dbin}" "./rootfs/${dbin}";
for lib in $(ldd "${dbin}" | grep -Eo "/.*so.[0-9\.]+"); do
cp -p "${lib}" "./${lib}"
cp -p "${lib}" "./rootfs/usr/${lib}"
done
done
info "4 - Add startup script & nspawn config"
cat <<UNLIKELY_EOF >./rootfs/start.sh
#!/bin/sh
mkdir /run/sshd
exec /usr/sbin/sshd -D -e -f /etc/ssh/sshd_config
UNLIKELY_EOF
generate_jail_nspawn_config "${jail_name}"
[ -e "/var/lib/machines/${jail_name}" ] && unlink "/var/lib/machines/${jail_name}"
ln -s "${jail_rootfs_path}" "/var/lib/machines/${jail_name}"
}
setup_jail_config() {
jail_name=${1:?}
jail_path=$(jail_path "${jail_name}")
jail_sshd_config="${jail_path}/${SSHD_CONFIG}"
jail_rootfs_path=$(jail_rootfs_path "${jail_name}")
jail_sshd_config="${jail_rootfs_path}/${SSHD_CONFIG}"
sshd_config_tpl="${TPLDIR}/sshd_config"
test -f "${LOCALTPLDIR}/sshd_config" && sshd_config_tpl="${LOCALTPLDIR}/sshd_config"
info "4 - Copie default sshd_config"
info "5 - Copy default sshd_config"
install -m 0640 "${sshd_config_tpl}" "${jail_sshd_config}"
info "5 - Copie default inc configuration"
info "6 - Copy default inc configuration"
incs_policy_tpl="${TPLDIR}/incs_policy.tpl"
test -f "${LOCALTPLDIR}/incs_policy.tpl" && incs_policy_tpl="${LOCALTPLDIR}/incs_policy.tpl"
jail_incs_policy_file=$(jail_incs_policy_file "${jail_name}")
@ -407,6 +449,64 @@ setup_jail_config() {
"${LIBDIR}/bkctld-port" "${jail_name}" auto
}
generate_jail_nspawn_config(){
jail_name=${1:?}
mkdir --parents /etc/systemd/nspawn/
cat <<UNLIKELY_EOF >/etc/systemd/nspawn/"${jail_name}".nspawn
[Exec]
ProcessTwo=True
Parameters=/bin/sh start.sh
DropCapability=CAP_SYS_ADMIN
NoNewPrivileges=True
SystemCallFilter=~@system-service
PrivateUsers=False
LinkJournal=no
[Files]
ReadOnly=True
Bind=/backup/jails/${jail_name}/var:/var
Bind=/backup/jails/${jail_name}/data:/data
Bind=/backup/jails/${jail_name}/data:/var/backup
[Network]
Private=False
UNLIKELY_EOF
}
convert_jail_chroot_to_v2() {
jail_name=${1:?}
jail_path=$(jail_path "${jail_name}")
jail_rootfs_path=$(jail_rootfs_path "${jail_name}")
jail_var_path=$(jail_var_path "${jail_name}")
cd "${jail_path}" || error "${jail_name}: failed to change directory to ${jail_path}."
umask 077
# Create the new jail rootfs path
mkdir --parents "${jail_rootfs_path}"
# Move config & jail data into their new paths
mv ./etc ./rootfs/etc
mv ./var/backup ./data
# Cleanup old directories
# They will be recreated with the next setup_jail_chroot() call
rm -rf ./bin
rm -rf ./lib
rm -rf ./lib64
rm -rf ./run
rm -rf ./usr
rm -rf ./var/run
# Mark the jail as version 2
echo "2" > ./version
}
is_mounted_inside_jail() {
target=${1:?}
@ -415,39 +515,6 @@ is_mounted_inside_jail() {
grep -q "${target}" /proc/mounts
}
mount_jail_fs() {
jail_name=${1:?}
jail_path=$(jail_path "${jail_name}")
is_mounted_inside_jail "${jail_path}/dev" || mount -nt tmpfs "dev-${jail_name}" "${jail_path}/dev"
[ -e "dev/console" ] || mknod -m 622 "${jail_path}/dev/console" c 5 1
chown root:tty "${jail_path}/dev/console"
[ -e "dev/null" ] || mknod -m 666 "${jail_path}/dev/null" c 1 3
[ -e "dev/zero" ] || mknod -m 666 "${jail_path}/dev/zero" c 1 5
[ -e "dev/ptmx" ] || mknod -m 666 "${jail_path}/dev/ptmx" c 5 2
chown root:tty "${jail_path}/dev/ptmx"
[ -e "dev/tty" ] || mknod -m 666 "${jail_path}/dev/tty" c 5 0
chown root:tty "${jail_path}/dev/tty"
[ -e "dev/random" ] || mknod -m 444 "${jail_path}/dev/random" c 1 8
[ -e "dev/urandom" ] || mknod -m 444 "${jail_path}/dev/urandom" c 1 9
mkdir -p "${jail_path}/dev/pts"
is_mounted_inside_jail "${jail_path}/dev/pts" || mount -t devpts -o gid=4,mode=620 none "${jail_path}/dev/pts"
mkdir -p "${jail_path}/dev/shm"
is_mounted_inside_jail "${jail_path}/dev/shm" || mount -t tmpfs none "${jail_path}/dev/shm"
is_mounted_inside_jail "${jail_path}/proc" || mount -t proc "proc-${jail_name}" "${jail_path}/proc"
ln -fs "${jail_path}/proc/self/fd" "${jail_path}/dev/fd"
ln -fs "${jail_path}/proc/self/fd/0" "${jail_path}/dev/stdin"
ln -fs "${jail_path}/proc/self/fd/1" "${jail_path}/dev/stdout"
ln -fs "${jail_path}/proc/self/fd/2" "${jail_path}/dev/stderr"
ln -fs "${jail_path}/proc/kcore" "${jail_path}/dev/core"
}
read_variable() {
file=${1:?}
var_name=${2:?}
@ -465,3 +532,27 @@ read_numerical_variable() {
grep --extended-regexp --only-matching "${pattern}" "${file}" | tail -1 | cut -d= -f2
}
get_jail_sshd_pid(){
jail_name=${1:?}
## Expected PID hierarchy (ps --forest...)
# 62054 ? Ss 0:00 systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-veth -U --settings=override --machine=test
# 62057 ? Ss 0:00 \_ (sd-stubinit)
# 62059 pts/0 Ss+ 0:00 \_ sshd: /usr/sbin/sshd -D -e -f /etc/ssh/sshd_config [listener] 0 of 10-100 startups
jail_init_pid=$(pgrep -P "$(systemctl show --value --property MainPID systemd-nspawn@"${jail_name}")")
pgrep -P "${jail_init_pid}"
}
get_jail_version(){
jail_name=${1:?}
jail_path=$(jail_path "${jail_name}")
if [ -e "${jail_path}/version" ]; then
cat "${jail_path}/version"
else
echo 1
fi
}

View file

@ -261,7 +261,7 @@ OUT
@test "Check-canary fails if a canary is missing today's entries" {
today="$(date +%Y-%m-%d)"
touch "${JAILPATH}/var/backup/zzz_evobackup_canary"
touch "${JAILPATH}/data/zzz_evobackup_canary"
run /usr/lib/bkctld/bkctld-check-canary "${JAILNAME}"
assert_equal "$status" "2"
@ -269,7 +269,7 @@ OUT
}
@test "Check-canary succeeds if a canary has today's entries" {
echo "$(date "+%FT%T%z") bats-test" >> "${JAILPATH}/var/backup/zzz_evobackup_canary"
echo "$(date "+%FT%T%z") bats-test" >> "${JAILPATH}/data/zzz_evobackup_canary"
run /usr/lib/bkctld/bkctld-check-canary "${JAILNAME}"
assert_success

View file

@ -4,7 +4,7 @@
load test_helper
@test "Without SSH key" {
run cat "${JAILPATH}/root/.ssh/authorized_keys"
run cat "${JAILPATH}/rootfs/root/.ssh/authorized_keys"
assert_equal "$output" ""
}
@ -12,7 +12,7 @@ load test_helper
keyfile=/root/bkctld.key.pub
/usr/lib/bkctld/bkctld-key "${JAILNAME}" "${keyfile}"
# The key should be present in the SSH authorized_keys file
run cat "${JAILPATH}/root/.ssh/authorized_keys"
run cat "${JAILPATH}/rootfs/root/.ssh/authorized_keys"
assert_equal "$output" "$(cat ${keyfile})"
}
@ -26,7 +26,7 @@ load test_helper
@test "No IP restriction" {
# A jail has no IP restriction by default in SSH config
run grep "root@0.0.0.0/0" "${JAILPATH}/etc/ssh/sshd_config"
run grep "root@0.0.0.0/0" "${JAILPATH}/rootfs/etc/ssh/sshd_config"
assert_success
}
@ -34,7 +34,7 @@ load test_helper
# When an IP is added for a jail
/usr/lib/bkctld/bkctld-ip "${JAILNAME}" "10.0.0.1"
# An IP restriction should be present in SSH config
run grep "root@10.0.0.1" "${JAILPATH}/etc/ssh/sshd_config"
run grep "root@10.0.0.1" "${JAILPATH}/rootfs/etc/ssh/sshd_config"
assert_success
}
@ -43,7 +43,7 @@ load test_helper
/usr/lib/bkctld/bkctld-ip "${JAILNAME}" "10.0.0.1"
/usr/lib/bkctld/bkctld-ip "${JAILNAME}" "10.0.0.2"
# The corresponding IP restrictions should be present in SSH config
run grep -E -o "root@10.0.0.[0-9]+" "${JAILPATH}/etc/ssh/sshd_config"
run grep -E -o "root@10.0.0.[0-9]+" "${JAILPATH}/rootfs/etc/ssh/sshd_config"
assert_line "root@10.0.0.1"
assert_line "root@10.0.0.2"
@ -55,13 +55,13 @@ load test_helper
# Remove IP
/usr/lib/bkctld/bkctld-ip "${JAILNAME}" "0.0.0.0/0"
# All IP restrictions should be removed from SSH config
run grep "root@0.0.0.0/0" "${JAILPATH}/etc/ssh/sshd_config"
run grep "root@0.0.0.0/0" "${JAILPATH}/rootfs/etc/ssh/sshd_config"
assert_success
}
@test "Missing AllowUsers" {
# Remove AllowUsers directive in SSH config
sed --follow-symlinks --in-place '/^AllowUsers/d' "${JAILPATH}/etc/ssh/sshd_config"
sed --follow-symlinks --in-place '/^AllowUsers/d' "${JAILPATH}/rootfs/etc/ssh/sshd_config"
# An error should be raised when trying to add an IP restriction
run /usr/lib/bkctld/bkctld-ip "${JAILNAME}" "10.0.0.1"
assert_failure

View file

@ -25,9 +25,14 @@ load test_helper
assert_success