Merge branch 'master' into debian
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
commit
a0665db5ca
38
CHANGELOG.md
Normal file
38
CHANGELOG.md
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# Changelog
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Shellcheck directives to have 0 warnings and errors
|
||||||
|
* Ability to override critical/warning thresholds per jail for bkctld-check
|
||||||
|
* Support new location for jail configuration (/etc/evobackup/<jail_name>.d/)
|
||||||
|
* Lock per jail and inc when creating incs
|
||||||
|
* Global lock when removing incs (kill the currently running instance)
|
||||||
|
* Create a blank SSH "authorized_keys" file on jail init
|
||||||
|
* Many new tests with BATS
|
||||||
|
* Check for firewall configuration in bkcld-check
|
||||||
|
* Run the test suite on Buster (ext4/btrfs) in addition of Stretch (ext4/btrfs)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* Extract variables and heper functions to reduce repetition of knowledge
|
||||||
|
* Consistent naming of variables in scripts and functions
|
||||||
|
* Consistent log messages between functions ad commands
|
||||||
|
* Raise errors if required function arguments are missing
|
||||||
|
* Configure locales in Vagrant VM
|
||||||
|
* Split BATS tests file and use helper functions
|
||||||
|
* Improve "lib" detection
|
||||||
|
* Revamp the README
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
### Security
|
68
README.md
68
README.md
|
@ -1,38 +1,44 @@
|
||||||
Bkctld (aka evobackup)
|
Bkctld (aka server-side evobackup)
|
||||||
=========
|
=========
|
||||||
|
|
||||||
Bkctld is a shell script that creates and manages a backup server
|
bkctld helps you manage the receiving side of a backup infrastructure.
|
||||||
which can handle the backups of many other servers (clients). It
|
It is licensed under the AGPLv3.
|
||||||
is licensed under the AGPLv3.
|
|
||||||
|
|
||||||
It uses SSH chroots (called "jails" in the FreeBSD world) to sandbox
|
With bkctld you create and manage "jails". They contain a chrooted and dedicated SSH server, with it's own TCP port and optionnaly it's own set of iptables rules.
|
||||||
every clients backups. Each client will upload it's data every day
|
|
||||||
using rsync in it's chroot (using the root account). Prior backups
|
|
||||||
are stored incrementally outside of the chroot using hard links or
|
|
||||||
BTRFS snapshots. (So they can not be affected by the client).
|
|
||||||
|
|
||||||
Using this method, we can keep a large quantity of backups of each
|
With bkctld you can have hundreds of jails, one for each client to push its data (using Rsync/SFTP). Each client can only see its own data.
|
||||||
client securely and efficiently.
|
|
||||||
|
In addition to the traditional "ext4" filesystem, bkctld also supports the btrfs filesystem and manages subvolumes automatically.
|
||||||
|
|
||||||
|
With bkctld you can create "timestamped" copies of the data, to keep different versions of the same data at different points in time. If the filesystem is btrfs, it creates subvolumes snapshots, otherwise it creates copies with hard-links (for file-level deduplication).
|
||||||
|
|
||||||
|
With btrfs you can have a data retention policy to automatically destroy timestamped copies of your data. For example, keep a copy for the last 5 days and the first day of the last 3 months.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
Backup server
|
Backup server
|
||||||
************
|
************
|
||||||
Server 1 ------ SSH/rsync -------> * tcp/2222 *
|
Client 1 ------ SSH/Rsync -------> * tcp/2222 *
|
||||||
* *
|
************
|
||||||
Server 2 ------ SSH/rsync -------> * tcp/2223 *
|
Client 2 ------ SSH/Rsync -------> * tcp/2223 *
|
||||||
************
|
************
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
This method uses standard tools (ssh, rsync, cp -al, btrfs subvolume)
|
This method uses standard tools (ssh, rsync, cp -al, btrfs subvolume) and has been used for many years by Evolix to backup hundreds of servers, totaling many terabytes of data, each day. bkctld has been tested on Debian Jessie (8), Stretch (9) and Buster (10) and should be compatible with other Debian versions or derived distributions like Ubuntu.
|
||||||
and has been used for many years by Evolix to backup hundreds of
|
|
||||||
servers, totaling many terabytes of data, each day. bkctld has
|
|
||||||
been tested on Debian Jessie and should be compatible with other
|
|
||||||
Debian versions or derived distributions like Ubuntu.
|
|
||||||
|
|
||||||
A large enough volume must be mounted on `/backup`, we recommend
|
A large enough volume must be mounted on `/backup`, we recommend the usage of **BTRFS** so you can use sub-volumes and snapshots.
|
||||||
the usage of **BTRFS** so you can use sub-volumes and snapshots.
|
|
||||||
This volume can also be encrypted with **LUKS**.
|
This volume can also be encrypted with **LUKS**.
|
||||||
|
|
||||||
|
## Security considerations
|
||||||
|
|
||||||
|
The client obviously has access to its uploaded data (in the chroot), but the timestamped copies are outside the chroot, to reduce the risk or complete backup erasure from a compromised client.
|
||||||
|
|
||||||
|
Since the client connects to the backup server with root, it can mess with the jail and destroy the data. But the timestamped copies are out of reach because outside of the chroot.
|
||||||
|
|
||||||
|
It means that **if the client server is compromised**, an attacker can destroy the latest copy of the backed up data, but not the timestamped copies.
|
||||||
|
And **if the backup server is compromised** an attacker has complete access to all the backup data (inside and outside the jails), but they don't have any access to the client.
|
||||||
|
|
||||||
|
This architecture is as secure as SSH, Rsync, chroot and iptables are.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
See the [installation guide](docs/install.md) for instructions.
|
See the [installation guide](docs/install.md) for instructions.
|
||||||
|
@ -47,7 +53,7 @@ vagrant up
|
||||||
|
|
||||||
### Deployment
|
### Deployment
|
||||||
|
|
||||||
Launch rsync-auto in a terminal for automatic synchronization of
|
Run `vagrant rsync-auto` in a terminal for automatic synchronization of
|
||||||
your local code with Vagrant VM :
|
your local code with Vagrant VM :
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
|
@ -57,12 +63,22 @@ vagrant rsync-auto
|
||||||
### Bats
|
### Bats
|
||||||
|
|
||||||
You can run [bats](https://github.com/sstephenson/bats) tests with
|
You can run [bats](https://github.com/sstephenson/bats) tests with
|
||||||
the *test* provision :
|
the *test* provisioner :
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
vagrant provision --provision-with test
|
vagrant provision --provision-with test
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
You can also run the tests from inside the VM
|
||||||
|
|
||||||
|
~~~
|
||||||
|
localhost $ vagrant ssh buster-btrfs
|
||||||
|
vagrant@buster-btrfs $ sudo -i
|
||||||
|
root@buster-btrfs # bats /vagrant/test/*.bats
|
||||||
|
~~~
|
||||||
|
|
||||||
|
You should shellcheck your bats files, but with shellcheck > 0.4.6, because the 0.4.0 version doesn't support bats syntax.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
See [docs/usage.md](docs/usage.md).
|
See [docs/usage.md](docs/usage.md).
|
||||||
|
@ -82,8 +98,8 @@ pandoc -f markdown \
|
||||||
|
|
||||||
#### Client configuration
|
#### Client configuration
|
||||||
|
|
||||||
You can save various systems in the evobackup jails : Linux, BSD,
|
You can backup various systems in the evobackup jails : Linux, BSD,
|
||||||
Windows, MacOSX. The only prerequisite is the rsync command.
|
Windows, macOS. The only need Rsync or an SFTP client.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
rsync -av -e "ssh -p SSH_PORT" /home/ root@SERVER_NAME:/var/backup/home/
|
rsync -av -e "ssh -p SSH_PORT" /home/ root@SERVER_NAME:/var/backup/home/
|
||||||
|
@ -94,7 +110,7 @@ clone the evobackup repository and read the **CLIENT CONFIGURATION**
|
||||||
section of the manual.
|
section of the manual.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
git clone https://forge.evolix.org/evobackup.git
|
git clone https://gitea.evolix.org/evolix/evobackup.git
|
||||||
cd evobackup
|
cd evobackup
|
||||||
man ./docs/bkctld.8
|
man ./docs/bkctld.8
|
||||||
~~~
|
~~~
|
||||||
|
|
11
Vagrantfile
vendored
11
Vagrantfile
vendored
|
@ -28,7 +28,12 @@ DEBIAN_FRONTEND=noninteractive apt-get -yq install openssh-server btrfs-tools rs
|
||||||
SCRIPT
|
SCRIPT
|
||||||
|
|
||||||
$pre_part = <<SCRIPT
|
$pre_part = <<SCRIPT
|
||||||
lsof|awk '/backup/ { print $2 }'| xargs --no-run-if-empty kill -9
|
sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
|
||||||
|
sed -i -e 's/# fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/' /etc/locale.gen && \
|
||||||
|
echo 'LANG="fr_FR.UTF-8"'>/etc/default/locale && \
|
||||||
|
dpkg-reconfigure --frontend=noninteractive locales && \
|
||||||
|
update-locale LANG=fr_FR.UTF-8
|
||||||
|
lsof | awk '/backup/ { print $2 }' | xargs --no-run-if-empty kill -9
|
||||||
grep -q /backup /proc/mounts && umount -R /backup
|
grep -q /backup /proc/mounts && umount -R /backup
|
||||||
exit 0
|
exit 0
|
||||||
SCRIPT
|
SCRIPT
|
||||||
|
@ -40,7 +45,9 @@ SCRIPT
|
||||||
|
|
||||||
nodes = [
|
nodes = [
|
||||||
{ :version => "stretch", :fs => "btrfs" },
|
{ :version => "stretch", :fs => "btrfs" },
|
||||||
{ :version => "stretch", :fs => "ext4" }
|
{ :version => "stretch", :fs => "ext4" },
|
||||||
|
{ :version => "buster", :fs => "btrfs" },
|
||||||
|
{ :version => "buster", :fs => "ext4" }
|
||||||
]
|
]
|
||||||
|
|
||||||
nodes.each do |i|
|
nodes.each do |i|
|
||||||
|
|
|
@ -2,27 +2,28 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2017 Victor Laborie <vlaborie@evolix.fr>
|
# Copyright (c) 2017 Victor Laborie <vlaborie@evolix.fr>
|
||||||
#
|
#
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
function _bkctld()
|
function _bkctld()
|
||||||
{
|
{
|
||||||
local cur prev commands jails keys
|
local cur prev commands jails keys
|
||||||
|
|
||||||
cur=${COMP_WORDS[COMP_CWORD]};
|
cur=${COMP_WORDS[COMP_CWORD]};
|
||||||
prev=${COMP_WORDS[COMP_CWORD-1]};
|
prev=${COMP_WORDS[COMP_CWORD-1]};
|
||||||
commands=$(find /usr/lib/bkctld/ -name "bkctld-*" -exec basename {} \;|sed 's/^bkctld-//')
|
commands=$(find /usr/lib/bkctld/ -name "bkctld-*" -exec basename {} \; | sed 's/^bkctld-//')
|
||||||
|
|
||||||
if [ $COMP_CWORD -eq 1 ]; then
|
if [ $COMP_CWORD -eq 1 ]; then
|
||||||
COMPREPLY=($(compgen -W '${commands}' -- ${cur}))
|
COMPREPLY=($(compgen -W '${commands}' -- ${cur}))
|
||||||
elif [ $COMP_CWORD -eq 2 ]; then
|
elif [ $COMP_CWORD -eq 2 ]; then
|
||||||
[ -f /etc/default/bkctld ] && source /etc/default/bkctld
|
[ -f /etc/default/bkctld ] && source /etc/default/bkctld
|
||||||
[ -z "${JAILDIR}" ] && JAILDIR='/backup/jails'
|
[ -z "${JAILDIR}" ] && JAILDIR='/backup/jails'
|
||||||
jails=$(ls "${JAILDIR}")
|
jails=$(ls "${JAILDIR}")
|
||||||
COMPREPLY=($(compgen -W "${jails}" -- ${cur}))
|
COMPREPLY=($(compgen -W "${jails}" -- ${cur}))
|
||||||
elif [ $COMP_CWORD -eq 3 ]; then
|
elif [ $COMP_CWORD -eq 3 ]; then
|
||||||
keys=$(ls *.pub)
|
keys=$(ls *.pub)
|
||||||
COMPREPLY=($(compgen -W "${keys}" -- ${cur}))
|
COMPREPLY=($(compgen -W "${keys}" -- ${cur}))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
} &&
|
} &&
|
||||||
complete -F _bkctld bkctld
|
complete -F _bkctld bkctld
|
||||||
|
|
52
bkctld
52
bkctld
|
@ -3,8 +3,12 @@
|
||||||
# bkctld is a shell script to create and manage a backup server which will
|
# bkctld is a shell script to create and manage a backup server which will
|
||||||
# handle the backup of many servers (clients).
|
# handle the backup of many servers (clients).
|
||||||
#
|
#
|
||||||
# Author: Victor Laborie <vlaborie@evolix.fr>
|
# Authors: Victor Laborie <vlaborie@evolix.fr>
|
||||||
# Contributor: Benoît Série <bserie@evolix.fr>, Gregory Colpart <reg@evolix.fr>, Romain Dessort <rdessort@evolix.fr>, Tristan Pilat <tpilat@evolix.fr>
|
# Jérémy Lecour <jlecour@evolix.fr>
|
||||||
|
# Benoît Série <bserie@evolix.fr>
|
||||||
|
# Gregory Colpart <reg@evolix.fr>
|
||||||
|
# Romain Dessort <rdessort@evolix.fr>
|
||||||
|
# Tristan Pilat <tpilat@evolix.fr>
|
||||||
# Licence: AGPLv3
|
# Licence: AGPLv3
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -12,12 +16,22 @@ set -u
|
||||||
|
|
||||||
[ "$(id -u)" -ne 0 ] && error "You need to be root to run ${0} !"
|
[ "$(id -u)" -ne 0 ] && error "You need to be root to run ${0} !"
|
||||||
|
|
||||||
[ -d './lib' ] && LIBDIR='lib'
|
basedir=$(dirname "$0")
|
||||||
[ -d '/usr/lib/bkctld' ] && LIBDIR='/usr/lib/bkctld'
|
if [ "${basedir}" = "/usr/local/sbin" ] && [ -d "/usr/local/lib/bkctld" ]; then
|
||||||
. "${LIBDIR}/config"
|
LIBDIR='/usr/local/lib/bkctld'
|
||||||
|
elif [ "${basedir}" = "/usr/sbin" ] && [ -d "/usr/lib/bkctld" ]; then
|
||||||
|
LIBDIR='/usr/lib/bkctld'
|
||||||
|
elif [ -d './lib' ]; then
|
||||||
|
LIBDIR='lib'
|
||||||
|
else
|
||||||
|
error "Failed to find a suitable lib directory for bkctld."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck source=lib/includes
|
||||||
|
. "${LIBDIR}/includes"
|
||||||
|
|
||||||
subcommand="${1:-}"
|
subcommand="${1:-}"
|
||||||
jail="${2:-}"
|
jail_name="${2:-}"
|
||||||
option="${3:-}"
|
option="${3:-}"
|
||||||
|
|
||||||
if [ ! -x "${LIBDIR}/bkctld-${subcommand}" ]; then
|
if [ ! -x "${LIBDIR}/bkctld-${subcommand}" ]; then
|
||||||
|
@ -28,24 +42,24 @@ case "${subcommand}" in
|
||||||
"inc" | "rm" | "check" | "stats" | "help" | "list")
|
"inc" | "rm" | "check" | "stats" | "help" | "list")
|
||||||
"${LIBDIR}/bkctld-${subcommand}"
|
"${LIBDIR}/bkctld-${subcommand}"
|
||||||
;;
|
;;
|
||||||
"init" | "is-on")
|
"init" | "is-on")
|
||||||
"${LIBDIR}/bkctld-${subcommand}" "${jail}"
|
"${LIBDIR}/bkctld-${subcommand}" "${jail_name}"
|
||||||
;;
|
;;
|
||||||
"key" | "port" | "ip")
|
"key" | "port" | "ip")
|
||||||
"${LIBDIR}/bkctld-${subcommand}" "${jail}" "${option}"
|
"${LIBDIR}/bkctld-${subcommand}" "${jail_name}" "${option}"
|
||||||
;;
|
;;
|
||||||
"start" | "stop" | "reload" | "restart" | "sync" | "update" | "remove" | "firewall")
|
"start" | "stop" | "reload" | "restart" | "sync" | "update" | "remove" | "firewall")
|
||||||
if [ "${jail}" = "all" ]; then
|
if [ "${jail_name}" = "all" ]; then
|
||||||
"${LIBDIR}/bkctld-list"|xargs --no-run-if-empty --max-args=1 --max-procs=0 "${LIBDIR}/bkctld-${subcommand}"
|
"${LIBDIR}/bkctld-list" | xargs --no-run-if-empty --max-args=1 --max-procs=0 "${LIBDIR}/bkctld-${subcommand}"
|
||||||
else
|
else
|
||||||
"${LIBDIR}/bkctld-${subcommand}" "${jail}"
|
"${LIBDIR}/bkctld-${subcommand}" "${jail_name}"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
"status")
|
"status")
|
||||||
if [ -z "${jail}" ]; then
|
if [ "${jail_name}" = "all" ] || [ -z "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-list"|xargs --no-run-if-empty --max-args=1 "${LIBDIR}/bkctld-${subcommand}"
|
"${LIBDIR}/bkctld-list" | xargs --no-run-if-empty --max-args=1 "${LIBDIR}/bkctld-${subcommand}"
|
||||||
else
|
else
|
||||||
"${LIBDIR}/bkctld-${subcommand}" "${jail}"
|
"${LIBDIR}/bkctld-${subcommand}" "${jail_name}"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -22,25 +22,34 @@ rc=0
|
||||||
# loop for each configured jail
|
# loop for each configured jail
|
||||||
for file in ${EVOBACKUP_CONFIGS}; do
|
for file in ${EVOBACKUP_CONFIGS}; do
|
||||||
jail_name=$(basename ${file})
|
jail_name=$(basename ${file})
|
||||||
|
|
||||||
# check if jail is present
|
# check if jail is present
|
||||||
if jail_exists ${jail_name}; then
|
if jail_exists ${jail_name}; then
|
||||||
|
today=$(date +"%s")
|
||||||
# get jail last configuration date
|
# get jail last configuration date
|
||||||
jail_config_age=$(date --date "$(stat -c %y ${file})" +"%s")
|
jail_config_age=$(date --date "$(stat -c %y ${file})" +"%s")
|
||||||
|
|
||||||
# loop for each line in jail configuration
|
# loop for each line in jail configuration
|
||||||
for line in $(cat ${file}); do
|
for line in $(cat ${file}); do
|
||||||
# inc date in ISO format
|
# inc date in ISO format
|
||||||
inc_date=$(relative_date ${line})
|
inc_date=$(relative_date ${line})
|
||||||
# inc date in seconds from epoch
|
# inc date in seconds from epoch
|
||||||
inc_age=$(date --date "${inc_date}" +"%s")
|
inc_age=$(date --date "${inc_date}" +"%s")
|
||||||
# check if the configuration changed after the inc date
|
|
||||||
if [ "${jail_config_age}" -lt "${inc_age}" ]; then
|
# skip line if date is inthe future
|
||||||
# Error if inc is not found
|
if [ "${inc_age}" -gt "${today}" ]; then
|
||||||
if ! inc_exists ${jail_name}/${inc_date}*; then
|
|
||||||
echo "ERROR: inc is missing \`${jail_name}/${inc_date}'" >&2
|
|
||||||
rc=1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "INFO: no inc expected for ${inc_date} \`${jail_name}'"
|
echo "INFO: no inc expected for ${inc_date} \`${jail_name}'"
|
||||||
|
else
|
||||||
|
# check if the configuration changed after the inc date
|
||||||
|
if [ "${jail_config_age}" -lt "${inc_age}" ]; then
|
||||||
|
# Error if inc is not found
|
||||||
|
if ! inc_exists ${jail_name}/${inc_date}*; then
|
||||||
|
echo "ERROR: inc is missing \`${jail_name}/${inc_date}'" >&2
|
||||||
|
rc=1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "INFO: no inc expected for ${inc_date} \`${jail_name}'"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Install
|
# Install
|
||||||
|
|
||||||
|
## Install from package
|
||||||
|
|
||||||
A Debian package is available in the Evolix repository
|
A Debian package is available in the Evolix repository
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
|
@ -8,7 +10,27 @@ apt update
|
||||||
apt install bkctld
|
apt install bkctld
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Then edit `/etc//bkctld`
|
Then edit `/etc/default/bkctld`
|
||||||
|
|
||||||
|
## Instal from sources
|
||||||
|
|
||||||
|
Warning: `cp`-ing the files without `-n` or `-i` will replace existing files !
|
||||||
|
|
||||||
|
~~~
|
||||||
|
# git clone https://gitea.evolix.org/evolix/evobackup.git
|
||||||
|
# cd evobackup
|
||||||
|
# cp bkctld /usr/local/sbin/
|
||||||
|
# mkdir -p /usr/local/lib/bkctld
|
||||||
|
# cp lib/* /usr/local/lib/bkctld/
|
||||||
|
# mkdir -p /usr/local/share/bkctld
|
||||||
|
# cp tpl/* /usr/local/share/bkctld/
|
||||||
|
# cp bkctld.service /lib/systemd/system/
|
||||||
|
# mkdir -p /usr/local/share/doc/bkctld
|
||||||
|
# cp zzz_evobackup /usr/local/share/doc/bkctld/
|
||||||
|
# mkdir -p /usr/local/share/bash_completion/
|
||||||
|
# cp bash_completion /usr/local/share/bash_completion/bkctld
|
||||||
|
# cp bkctld.conf /etc/default/bkctld
|
||||||
|
~~~
|
||||||
|
|
||||||
## Chroot dependencies
|
## Chroot dependencies
|
||||||
|
|
||||||
|
@ -30,7 +52,7 @@ apt install \
|
||||||
|
|
||||||
## Client dependencies
|
## Client dependencies
|
||||||
|
|
||||||
The clients only require OpenSSH and rsync.
|
The clients only require OpenSSH and Rsync.
|
||||||
|
|
||||||
### Cron job for incremental backups
|
### Cron job for incremental backups
|
||||||
|
|
||||||
|
@ -44,6 +66,6 @@ Edit the root crontab
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
If you want mutiples backups in a day (1 by hour maximum) you can
|
If you want mutiples backups in a day (1 per hour maximum) you can
|
||||||
run `bkctld inc` multiples times, if you want to keep incremental
|
run `bkctld inc` multiples times, if you want to keep incremental
|
||||||
backups **for ever**, just don't run `bkctld rm`.
|
backups **for ever**, just don't run `bkctld rm`.
|
||||||
|
|
|
@ -155,31 +155,31 @@ the backup server administrator will need:
|
||||||
|
|
||||||
He can then create the jail:
|
He can then create the jail:
|
||||||
|
|
||||||
# bkctld init CLIENT_HOST_NAME
|
# bkctld init <JAIL_NAME>
|
||||||
# bkctld key CLIENT_HOST_NAME /root/CLIENT_HOST_NAME.pub
|
# bkctld key <JAIL_NAME> /root/<JAIL_NAME>.pub
|
||||||
# bkctld ip CLIENT_HOST_NAME CLIENT_IP_ADDRESS
|
# bkctld ip <JAIL_NAME> <IP_OR_CIDR>
|
||||||
# bkctld start CLIENT_HOST_NAME
|
# bkctld start <JAIL_NAME>
|
||||||
# bkctld status CLIENT_HOST_NAME
|
# bkctld status <JAIL_NAME>
|
||||||
|
|
||||||
And override the default
|
And override the default
|
||||||
evobackup-incl(5)
|
evobackup-incl(5)
|
||||||
rules
|
rules
|
||||||
|
|
||||||
# $EDITOR /etc/evobackup/CLIENT_HOST_NAME
|
# $EDITOR /etc/evobackup/<JAIL_NAME>.d/incs_policy
|
||||||
|
|
||||||
To sync itself,
|
To sync itself,
|
||||||
the client server will need to install
|
the client server will need to install
|
||||||
rsync(1).
|
rsync(1).
|
||||||
It can then be run manually:
|
It can then be run manually:
|
||||||
|
|
||||||
# rsync -av -e "ssh -p JAIL_PORT" /home/ root@BACKUP_SERVER:/var/backup/home/
|
# rsync -av -e "ssh -p <JAIL_PORT>" /home/ root@<BACKUP_SERVER>:/var/backup/home/
|
||||||
|
|
||||||
If a more automated setup is required,
|
If a more automated setup is required,
|
||||||
a script can be written in any programming language.
|
a script can be written in any programming language.
|
||||||
In this case,
|
In this case,
|
||||||
it may be useful to validate the backup server's identity before hand.
|
it may be useful to validate the backup server's identity before hand.
|
||||||
|
|
||||||
# ssh -p JAIL_PORT BACKUP_SERVER
|
# ssh -p <JAIL_PORT> root@<BACKUP_SERVER> -t exit
|
||||||
|
|
||||||
A
|
A
|
||||||
bash(1)
|
bash(1)
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
# Usage: check
|
# Usage: check
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
cur_time=$(date "+%s")
|
|
||||||
return=0
|
return=0
|
||||||
nb_crit=0
|
nb_crit=0
|
||||||
nb_warn=0
|
nb_warn=0
|
||||||
|
@ -14,7 +14,10 @@ nb_ok=0
|
||||||
nb_unkn=0
|
nb_unkn=0
|
||||||
output=""
|
output=""
|
||||||
|
|
||||||
|
# Check if the backup disk is properly mounted
|
||||||
|
|
||||||
if [ -b "${BACKUP_DISK}" ]; then
|
if [ -b "${BACKUP_DISK}" ]; then
|
||||||
|
# If backup disk is encrypted, verify that it's open
|
||||||
cryptsetup isLuks "${BACKUP_DISK}"
|
cryptsetup isLuks "${BACKUP_DISK}"
|
||||||
if [ "$?" -eq 0 ]; then
|
if [ "$?" -eq 0 ]; then
|
||||||
if [ ! -b '/dev/mapper/backup' ]; then
|
if [ ! -b '/dev/mapper/backup' ]; then
|
||||||
|
@ -22,35 +25,77 @@ if [ -b "${BACKUP_DISK}" ]; then
|
||||||
echo "cryptsetup luksOpen ${BACKUP_DISK} backup"
|
echo "cryptsetup luksOpen ${BACKUP_DISK} backup"
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
# Change value to real device
|
||||||
BACKUP_DISK='/dev/mapper/backup'
|
BACKUP_DISK='/dev/mapper/backup'
|
||||||
fi
|
fi
|
||||||
grep -qE "^${BACKUP_DISK} " /etc/mtab
|
# Verify that it's mounted and writable
|
||||||
|
findmnt --source ${BACKUP_DISK} -O rw > /dev/null
|
||||||
if [ "$?" -ne 0 ]; then
|
if [ "$?" -ne 0 ]; then
|
||||||
echo "Backup disk ${BACKUP_DISK} is not mounted !\n"
|
echo "Backup disk ${BACKUP_DISK} is not mounted (or read-only) !\n"
|
||||||
echo "mount ${BACKUP_DISK} /backup"
|
echo "mount ${BACKUP_DISK} /backup"
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for jail in $("${LIBDIR}/bkctld-list"); do
|
# Check if the firewall file is sourced
|
||||||
if [ -f "${JAILDIR}/${jail}/var/log/lastlog" ]; then
|
|
||||||
last_conn=$(stat --format=%Y "${JAILDIR}/${jail}/var/log/lastlog")
|
minifirewall_config=/etc/default/minifirewall
|
||||||
date_diff=$(( (cur_time - last_conn) / (60*60) ))
|
|
||||||
if [ "${date_diff}" -gt "${CRITICAL}" ]; then
|
if [ -n "${FIREWALL_RULES}" ] \
|
||||||
nb_crit=$((nb_crit + 1))
|
&& [ -r "${FIREWALL_RULES}" ] \
|
||||||
output="${output}CRITICAL - ${jail} - ${date_diff} hours\n"
|
&& [ -f "${minifirewall_config}" ]; then
|
||||||
[ "${return}" -le 2 ] && return=2
|
if ! grep -qE "^(\.|source) ${FIREWALL_RULES}" "${minifirewall_config}"; then
|
||||||
elif [ "${date_diff}" -gt "${WARNING}" ]; then
|
nb_warn=$((nb_warn + 1))
|
||||||
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 - ${jail} - ${date_diff} hours\n"
|
[ "${return}" -le 1 ] && return=1
|
||||||
[ "${return}" -le 1 ] && return=1
|
fi
|
||||||
else
|
fi
|
||||||
nb_ok=$((nb_ok + 1))
|
|
||||||
output="${output}OK - ${jail} - ${date_diff} hours\n"
|
# Check each jail status
|
||||||
fi
|
|
||||||
|
check_jail() {
|
||||||
|
jail_name=$1
|
||||||
|
|
||||||
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
cur_time=$(date "+%s")
|
||||||
|
last_conn=$(stat --format=%Y "${jail_path}/var/log/lastlog")
|
||||||
|
date_diff=$(( (cur_time - last_conn) / (60*60) ))
|
||||||
|
|
||||||
|
check_policy_file=$(current_jail_check_policy_file "${jail_name}")
|
||||||
|
|
||||||
|
if [ -f "${check_policy_file}" ]; then
|
||||||
|
local_critical=$(read_variable "${check_policy_file}" "CRITICAL")
|
||||||
|
local_warning=$(read_variable "${check_policy_file}" "WARNING")
|
||||||
|
else
|
||||||
|
unset local_critical
|
||||||
|
unset local_warning
|
||||||
|
fi
|
||||||
|
# reset to default values if missing local value
|
||||||
|
: ${local_critical:=${CRITICAL}}
|
||||||
|
: ${local_warning:=${WARNING}}
|
||||||
|
|
||||||
|
if [ "${local_critical}" -gt "0" ] && [ "${date_diff}" -gt "${local_critical}" ]; then
|
||||||
|
nb_crit=$((nb_crit + 1))
|
||||||
|
output="${output}CRITICAL - ${jail_name} - ${date_diff} hours (${local_warning}/${local_critical})\n"
|
||||||
|
[ "${return}" -le 2 ] && return=2
|
||||||
|
elif [ "${local_warning}" -gt "0" ] && [ "${date_diff}" -gt "${local_warning}" ]; then
|
||||||
|
nb_warn=$((nb_warn + 1))
|
||||||
|
output="${output}WARNING - ${jail_name} - ${date_diff} hours (${local_warning}/${local_critical})\n"
|
||||||
|
[ "${return}" -le 1 ] && return=1
|
||||||
|
else
|
||||||
|
nb_ok=$((nb_ok + 1))
|
||||||
|
output="${output}OK - ${jail_name} - ${date_diff} hours (${local_warning}/${local_critical})\n"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
for jail_name in $(jails_list); do
|
||||||
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
|
||||||
|
if [ -f "${jail_path}/var/log/lastlog" ]; then
|
||||||
|
check_jail "${jail_name}"
|
||||||
else
|
else
|
||||||
nb_unkn=$((nb_unkn + 1))
|
nb_unkn=$((nb_unkn + 1))
|
||||||
output="${output}UNKNOWN - ${jail} doesn't have lastlog !\n"
|
output="${output}UNKNOWN - ${jail_name} doesn't have lastlog !\n"
|
||||||
[ "${return}" -le 3 ] && return=3
|
[ "${return}" -le 3 ] && return=3
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -58,11 +103,11 @@ done
|
||||||
[ "${return}" -ge 0 ] && header="OK"
|
[ "${return}" -ge 0 ] && header="OK"
|
||||||
[ "${return}" -ge 1 ] && header="WARNING"
|
[ "${return}" -ge 1 ] && header="WARNING"
|
||||||
[ "${return}" -ge 2 ] && header="CRITICAL"
|
[ "${return}" -ge 2 ] && header="CRITICAL"
|
||||||
[ "${return}" -ge 3 ] && header="UNKNOW"
|
[ "${return}" -ge 3 ] && header="UNKNOWN"
|
||||||
|
|
||||||
printf "%s - %s UNK / %s CRIT / %s WARN / %s OK\n\n" "${header}" "${nb_unkn}" "${nb_crit}" "${nb_warn}" "${nb_ok}"
|
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 "^UNKNOW"
|
printf "${output}" | grep -E "^UNKNOWN"
|
||||||
printf "${output}" | grep -E "^CRITICAL"
|
printf "${output}" | grep -E "^CRITICAL"
|
||||||
printf "${output}" | grep -E "^WARNING"
|
printf "${output}" | grep -E "^WARNING"
|
||||||
printf "${output}" | grep -E "^OK"
|
printf "${output}" | grep -E "^OK"
|
||||||
|
|
|
@ -4,21 +4,37 @@
|
||||||
# Usage: firewall <jailname>|all
|
# Usage: firewall <jailname>|all
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
if [ ! -n "${jail}" ]; then
|
|
||||||
|
if [ -z "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
|
||||||
|
iptables_input_accept() {
|
||||||
|
jail_name="${1}"
|
||||||
|
port="${2}"
|
||||||
|
ip="${3}"
|
||||||
|
|
||||||
|
echo "/sbin/iptables -A INPUT -p tcp --sport 1024: --dport ${port} -s ${ip} -j ACCEPT #${jail_name}"
|
||||||
|
}
|
||||||
|
|
||||||
if [ -n "${FIREWALL_RULES}" ]; then
|
if [ -n "${FIREWALL_RULES}" ]; then
|
||||||
[ -f "${FIREWALL_RULES}" ] && sed -i "/#${jail}$/d" "${FIREWALL_RULES}"
|
# remove existing rules for this jail
|
||||||
if [ -d "${JAILDIR}/${jail}" ]; then
|
[ -f "${FIREWALL_RULES}" ] && sed -i "/#${jail_name}$/d" "${FIREWALL_RULES}"
|
||||||
port=$("${LIBDIR}/bkctld-port" "${jail}")
|
if [ -d "${jail_path}" ]; then
|
||||||
for ip in $("${LIBDIR}/bkctld-ip" "${jail}"); do
|
port=$("${LIBDIR}/bkctld-port" "${jail_name}")
|
||||||
echo "/sbin/iptables -A INPUT -p tcp --sport 1024: --dport ${port} -s ${ip} -j ACCEPT #${jail}" >> "${FIREWALL_RULES}"
|
# Add a rule for each IP
|
||||||
|
for ip in $("${LIBDIR}/bkctld-ip" "${jail_name}"); do
|
||||||
|
iptables_input_accept "${jail_name}" "${port}" "${ip}" >> "${FIREWALL_RULES}"
|
||||||
done
|
done
|
||||||
|
# Restart the firewall
|
||||||
[ -f /etc/init.d/minifirewall ] && /etc/init.d/minifirewall restart >/dev/null
|
[ -f /etc/init.d/minifirewall ] && /etc/init.d/minifirewall restart >/dev/null
|
||||||
fi
|
fi
|
||||||
notice "${jail} : firewall rules updated"
|
notice "${jail_name}: firewall rules have been updated."
|
||||||
|
else
|
||||||
|
warning "${jail_name}: skipping firewall update, FIREWALL_RULES variable is empty."
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
# Usage: help
|
# Usage: help
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Usage: bkctld <subcommand> [options]
|
Usage: bkctld <subcommand> [options]
|
||||||
|
|
106
lib/bkctld-inc
106
lib/bkctld-inc
|
@ -4,34 +4,92 @@
|
||||||
# Usage: inc
|
# Usage: inc
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
date=$(date +"%Y-%m-%d-%H")
|
create_inc_btrfs() {
|
||||||
for jail in $("${LIBDIR}/bkctld-list"); do
|
jail_name=$1
|
||||||
inc="${INCDIR}/${jail}/${date}"
|
inc_name=$2
|
||||||
mkdir -p "${INCDIR}/${jail}"
|
|
||||||
if [ ! -d "${inc}" ]; then
|
jail_path=$(jail_path "${jail_name}")
|
||||||
start=$(date +"%H:%M:%S")
|
inc_path=$(inc_path "${jail_name}" "${inc_name}")
|
||||||
jail_inode=$(stat --format=%i "${JAILDIR}/${jail}")
|
|
||||||
if [ "$jail_inode" -eq 256 ]; then
|
# The lock file prevents from starting a new copy when one is already being done
|
||||||
/bin/btrfs subvolume snapshot -r "${JAILDIR}/${jail}" "${inc}" | debug
|
lock_file="${LOCKDIR}/inc-${jail_name}-${inc_name}.lock"
|
||||||
end=$(date +"%H:%M:%S")
|
if [ -f "${lock_file}" ]; then
|
||||||
notice "${jail} : made ${date} inc [${start}/${end}]"
|
warning "${jail_name}: skipping '${inc_name}', it is already being created."
|
||||||
else
|
else
|
||||||
lock="/run/lock/bkctld/inc-${jail}.lock"
|
(
|
||||||
if [ -f "${lock}" ]; then
|
start=$(current_time)
|
||||||
warning "${jail} : trying to run already running inc"
|
mkdir --parents "${LOCKDIR}" && touch "${lock_file}"
|
||||||
|
# shellcheck disable=SC2064
|
||||||
|
trap "rm -f ${lock_file}" 0
|
||||||
|
|
||||||
|
if dry_run; then
|
||||||
|
echo "[dry-run] btrfs subvolume snapshot of ${jail_path} to ${inc_path}"
|
||||||
else
|
else
|
||||||
(
|
mkdir --parents "$(dirname "${inc_path}")"
|
||||||
mkdir -p /run/lock/bkctld && touch "${lock}"
|
# create a btrfs readonly snapshot from the jail
|
||||||
trap "rm -f ${lock}" 0
|
/bin/btrfs subvolume snapshot -r "${jail_path}" "${inc_path}" | debug
|
||||||
cp -alx "${JAILDIR}/${jail}/" "${inc}"
|
|
||||||
end=$(date +"%H:%M:%S")
|
|
||||||
notice "${jail} : made ${date} inc [${start}/${end}]"
|
|
||||||
)
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
end=$(current_time)
|
||||||
|
notice "${jail_name}: inc '${inc_name}' has been created [${start}/${end}]"
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
create_inc_ext4() {
|
||||||
|
jail_name=$1
|
||||||
|
inc_name=$2
|
||||||
|
|
||||||
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
inc_path=$(inc_path "${jail_name}" "${inc_name}")
|
||||||
|
|
||||||
|
# The lock file prevents from starting a new copy when one is already being done
|
||||||
|
lock_file="${LOCKDIR}/inc-${jail_name}-${inc_name}.lock"
|
||||||
|
if [ -f "${lock_file}" ]; then
|
||||||
|
warning "${jail_name}: skipping '${inc_name}', it is already being created."
|
||||||
|
else
|
||||||
|
(
|
||||||
|
start=$(current_time)
|
||||||
|
mkdir --parents "${LOCKDIR}" && touch "${lock_file}"
|
||||||
|
# shellcheck disable=SC2064
|
||||||
|
trap "rm -f ${lock_file}" 0
|
||||||
|
|
||||||
|
if dry_run; then
|
||||||
|
echo "[dry-run] copy of ${jail_path} to ${inc_path}"
|
||||||
|
else
|
||||||
|
mkdir --parents "$(dirname "${inc_path}")"
|
||||||
|
# create a copy of the jail with hard links
|
||||||
|
cp --archive --link --one-file-system "${jail_path}/" "${inc_path}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
end=$(current_time)
|
||||||
|
notice "${jail_name}: in '${inc_name}' has been created [${start}/${end}]"
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
inc_name=$(date +"%Y-%m-%d-%H")
|
||||||
|
|
||||||
|
for jail_name in $(jails_list); do
|
||||||
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
inc_path=$(inc_path "${jail_name}" "${inc_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 not incs directory is found, we don't create incs
|
||||||
|
if [ ! -d "${inc_path}" ]; then
|
||||||
|
if is_btrfs "${jail_path}"; then
|
||||||
|
create_inc_btrfs "${jail_name}" "${inc_name}"
|
||||||
|
else
|
||||||
|
create_inc_ext4 "${jail_name}" "${inc_name}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warning "${jail_name}: skipping ${inc_name}, it already exists."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
warning "${jail} : trying to made already existant inc"
|
warning "${jail_name}: skipping ${inc_name}, incs policy not found."
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
@ -4,32 +4,28 @@
|
||||||
# Usage: init <jailname>
|
# Usage: init <jailname>
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
if [ ! -n "${jail}" ]; then
|
if [ -z "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] && error "${jail} : trying to create existant jail"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
|
||||||
mkdir -p "${CONFDIR}" "${JAILDIR}"
|
test -d "${jail_path}" && error "${jail_name}: jail already exists."
|
||||||
sshd_config="${TPLDIR}/sshd_config"
|
|
||||||
inctpl="${TPLDIR}/inc.tpl"
|
|
||||||
[ -f "${LOCALTPLDIR}/sshd_config" ] && sshd_config="${LOCALTPLDIR}/sshd_config"
|
|
||||||
[ -f "${LOCALTPLDIR}/inc.tpl" ] && inctpl="${LOCALTPLDIR}/inc.tpl"
|
|
||||||
|
|
||||||
rootdir=$(dirname "${JAILDIR}")
|
# Create config and jails directory
|
||||||
rootdir_inode=$(stat --format=%i "${rootdir}")
|
mkdir --parents "${CONFDIR}" "${JAILDIR}"
|
||||||
jaildir_inode=$(stat --format=%i "${JAILDIR}")
|
|
||||||
if [ "${rootdir_inode}" -eq 256 ] || [ "${jaildir_inode}" -eq 256 ]; then
|
|
||||||
/bin/btrfs subvolume create "${JAILDIR}/${jail}"
|
if is_btrfs "$(dirname "${JAILDIR}")" || is_btrfs "${JAILDIR}"; then
|
||||||
|
/bin/btrfs subvolume create "${jail_path}"
|
||||||
else
|
else
|
||||||
mkdir -p "${JAILDIR}/${jail}"
|
mkdir --parents "${jail_path}"
|
||||||
fi
|
fi
|
||||||
. "${LIBDIR}/mkjail"
|
|
||||||
info "4 - Copie default sshd_config"
|
setup_jail_chroot "${jail_name}"
|
||||||
install -m 0640 "${sshd_config}" "${JAILDIR}/${jail}/${SSHD_CONFIG}"
|
setup_jail_config "${jail_name}"
|
||||||
info "5 - Copie default inc configuration"
|
|
||||||
install -m 0640 "${inctpl}" "${CONFDIR}/${jail}"
|
notice "${jail_name}: jail has been created"
|
||||||
"${LIBDIR}/bkctld-port" "${jail}" auto
|
|
||||||
notice "${jail} : created jail"
|
|
||||||
|
|
|
@ -4,32 +4,45 @@
|
||||||
# Usage: ip <jailname> [<ip>|all]
|
# Usage: ip <jailname> [<ip>|all]
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
ip="${2:-}"
|
ip="${2:-}"
|
||||||
if [ ! -n "${jail}" ]; then
|
|
||||||
|
if [ ! -n "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : inexistant jail'"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
|
||||||
|
test -d "${jail_path}" || error "${jail_name}: jail is missing."
|
||||||
|
|
||||||
|
jail_sshd_config="${jail_path}/${SSHD_CONFIG}"
|
||||||
|
|
||||||
if [ -z "${ip}" ]; then
|
if [ -z "${ip}" ]; then
|
||||||
grep -E "^AllowUsers" "${JAILDIR}/$jail/${SSHD_CONFIG}"|grep -Eo "root@[^ ]+"| while read allow; do
|
# parse IP addresses from AllowUsers directives in sshd config
|
||||||
echo "${allow}"|cut -d'@' -f2
|
grep -E "^AllowUsers" "${jail_sshd_config}" \
|
||||||
|
| grep -E -o "root@[^ ]+" \
|
||||||
|
| while read allow; do
|
||||||
|
echo "${allow}" | cut -d'@' -f2
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
if [ "${ip}" = "all" ] || [ "${ip}" = "0.0.0.0/0" ]; then
|
if [ "${ip}" = "all" ] || [ "${ip}" = "0.0.0.0/0" ]; then
|
||||||
ips="0.0.0.0/0"
|
new_ips="0.0.0.0/0"
|
||||||
else
|
else
|
||||||
ips=$("${LIBDIR}/bkctld-ip" "${jail}")
|
existing_ips=$("${LIBDIR}/bkctld-ip" "${jail_name}")
|
||||||
ips=$(echo "${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
|
fi
|
||||||
allow="AllowUsers"
|
allow_users="AllowUsers"
|
||||||
for ip in $ips; do
|
for ip in ${new_ips}; do
|
||||||
allow="${allow} root@${ip}"
|
allow_users="${allow_users} root@${ip}"
|
||||||
done
|
done
|
||||||
sed -i "s~^AllowUsers .*~${allow}~" "${JAILDIR}/$jail/${SSHD_CONFIG}"
|
if grep -q -E "^AllowUsers" "${jail_sshd_config}"; then
|
||||||
notice "${jail} : update ip => ${ip}"
|
sed -i "s~^AllowUsers .*~${allow_users}~" "${jail_sshd_config}"
|
||||||
"${LIBDIR}/bkctld-reload" "${jail}"
|
else
|
||||||
"${LIBDIR}/bkctld-firewall" "${jail}"
|
error "${jail_name}: No 'AllowUsers' directive found in '${jail_sshd_config}'"
|
||||||
|
fi
|
||||||
|
notice "${jail_name}: IP whitelist updated to ${ip}"
|
||||||
|
"${LIBDIR}/bkctld-reload" "${jail_name}"
|
||||||
|
"${LIBDIR}/bkctld-firewall" "${jail_name}"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -4,23 +4,28 @@
|
||||||
# Usage: is-on <jailname>
|
# Usage: is-on <jailname>
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
if [ ! -n "${jail}" ]; then
|
|
||||||
|
if [ -z "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : trying to check inexistant jail"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
|
||||||
|
test -d "${jail_path}" || error "${jail_name}: jail is missing."
|
||||||
|
|
||||||
|
jail_pid_file="${jail_path}/${SSHD_PID}"
|
||||||
|
|
||||||
jail="${1}"
|
|
||||||
return=1
|
return=1
|
||||||
if [ -f "${JAILDIR}/${jail}/${SSHD_PID}" ]; then
|
if [ -f "${jail_pid_file}" ]; then
|
||||||
pid=$(cat "${JAILDIR}/${jail}/${SSHD_PID}")
|
pid=$(cat "${jail_pid_file}")
|
||||||
ps -p "${pid}" > /dev/null && return=0
|
ps -p "${pid}" > /dev/null && return=0
|
||||||
fi
|
fi
|
||||||
if [ "${return}" -eq 1 ]; then
|
if [ "${return}" -eq 1 ]; then
|
||||||
rm -f "${JAILDIR}/${jail}/${SSHD_PID}"
|
rm -f "${jail_pid_file}"
|
||||||
grep -q "${JAILDIR}/${jail}/proc" /proc/mounts && umount --lazy "${JAILDIR}/${jail}/proc/"
|
grep -q "${jail_path}/proc" /proc/mounts && umount --lazy "${jail_path}/proc/"
|
||||||
grep -q "${JAILDIR}/${jail}/dev" /proc/mounts && umount --lazy --recursive "${JAILDIR}/${jail}/dev"
|
grep -q "${jail_path}/dev" /proc/mounts && umount --lazy --recursive "${jail_path}/dev"
|
||||||
fi
|
fi
|
||||||
exit "${return}"
|
exit "${return}"
|
||||||
|
|
|
@ -4,22 +4,26 @@
|
||||||
# Usage: key <jailname> [<keyfile>]
|
# Usage: key <jailname> [<keyfile>]
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
keyfile="${2:-}"
|
keyfile="${2:-}"
|
||||||
if [ ! -n "${jail}" ]; then
|
|
||||||
|
if [ ! -n "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : inexistant jail'"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
|
||||||
|
test -d "${jail_path}" || error "${jail_name}: jail is missing."
|
||||||
|
|
||||||
if [ -z "${keyfile}" ]; then
|
if [ -z "${keyfile}" ]; then
|
||||||
if [ -f "${JAILDIR}/${jail}/${AUTHORIZED_KEYS}" ]; then
|
if [ -f "${jail_path}/${AUTHORIZED_KEYS}" ]; then
|
||||||
cat "${JAILDIR}/${jail}/${AUTHORIZED_KEYS}"
|
cat "${jail_path}/${AUTHORIZED_KEYS}"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
[ -e "${keyfile}" ] || error "Keyfile ${keyfile} dosen't exist !"
|
test -r "${keyfile}" || error "${jail_name}: SSH key '${keyfile}' is missing or is not readable."
|
||||||
cat "${keyfile}" > "${JAILDIR}/${jail}/${AUTHORIZED_KEYS}"
|
cat "${keyfile}" > "${jail_path}/${AUTHORIZED_KEYS}"
|
||||||
chmod 600 "${JAILDIR}/${jail}/${AUTHORIZED_KEYS}"
|
chmod 600 "${jail_path}/${AUTHORIZED_KEYS}"
|
||||||
notice "${jail} : update key => ${keyfile}"
|
notice "${jail_name}: SSH key has been updated with ${keyfile}"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -6,7 +6,10 @@
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
[ -d "${JAILDIR}" ] || exit 0
|
[ -d "${JAILDIR}" ] || exit 0
|
||||||
|
#TODO: try if this command works the same :
|
||||||
|
# find "${JAILDIR}" -mindepth 1 -maxdepth 1 -type d -printf '%f\n'
|
||||||
find "${JAILDIR}" -mindepth 1 -maxdepth 1 -type d|sed 's!.*/!!'
|
find "${JAILDIR}" -mindepth 1 -maxdepth 1 -type d|sed 's!.*/!!'
|
||||||
|
|
|
@ -4,25 +4,33 @@
|
||||||
# Usage: port <jailname> [<port>|auto]
|
# Usage: port <jailname> [<port>|auto]
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
port="${2:-}"
|
port="${2:-}"
|
||||||
if [ ! -n "${jail}" ]; then
|
|
||||||
|
if [ ! -n "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : inexistant jail'"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
|
||||||
|
test -d "${jail_path}" || error "${jail_name}: jail is missing."
|
||||||
|
|
||||||
|
jail_sshd_config="${jail_path}/${SSHD_CONFIG}"
|
||||||
|
|
||||||
if [ -z "${port}" ]; then
|
if [ -z "${port}" ]; then
|
||||||
grep -E "Port [0-9]+" "${JAILDIR}/${jail}/${SSHD_CONFIG}"|grep -oE "[0-9]+"
|
grep -E "Port [0-9]+" "${jail_sshd_config}"|grep -oE "[0-9]+"
|
||||||
else
|
else
|
||||||
if [ "${port}" = "auto" ]; then
|
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}"/*/"${SSHD_CONFIG}" 2>/dev/null | grep -Eo "[0-9]+" | sort -n | tail -1)
|
||||||
port=$((port+1))
|
port=$((port+1))
|
||||||
[ "${port}" -le 1 ] && port=2222
|
[ "${port}" -le 1 ] && port=2222
|
||||||
fi
|
fi
|
||||||
sed -i "s/^Port .*/Port ${port}/" "${JAILDIR}/$jail/${SSHD_CONFIG}"
|
sed -i "s/^Port .*/Port ${port}/" "${jail_sshd_config}"
|
||||||
notice "${jail} : update port => ${port}"
|
|
||||||
"${LIBDIR}/bkctld-reload" "${jail}"
|
notice "${jail_name}: port has been updated to ${port}"
|
||||||
"${LIBDIR}/bkctld-firewall" "${jail}"
|
|
||||||
|
"${LIBDIR}/bkctld-reload" "${jail_name}"
|
||||||
|
"${LIBDIR}/bkctld-firewall" "${jail_name}"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -4,15 +4,19 @@
|
||||||
# Usage: reload <jailname>|all
|
# Usage: reload <jailname>|all
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
if [ ! -n "${jail}" ]; then
|
if [ -z "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : trying to reload inexistant jail"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
"${LIBDIR}/bkctld-is-on" "${jail}" || exit 0
|
|
||||||
|
|
||||||
pid=$(cat "${JAILDIR}/${jail}/${SSHD_PID}")
|
test -d "${jail_path}" || error "${jail_name}: jail is missing."
|
||||||
|
|
||||||
kill -HUP "${pid}" && notice "${jail} was reloaded [${pid}]"
|
"${LIBDIR}/bkctld-is-on" "${jail_name}" || exit 0
|
||||||
|
|
||||||
|
pid=$(cat "${jail_path}/${SSHD_PID}")
|
||||||
|
|
||||||
|
kill -HUP "${pid}" && notice "${jail_name}: jail has been reloaded [${pid}]"
|
||||||
|
|
|
@ -4,33 +4,39 @@
|
||||||
# Usage: remove <jailname>|all
|
# Usage: remove <jailname>|all
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
if [ ! -n "${jail}" ]; then
|
if [ -z "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : trying to remove inexistant jail"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
"${LIBDIR}/bkctld-is-on" "${jail}" && "${LIBDIR}/bkctld-stop" "${jail}"
|
incs_path=$(incs_path "${jail_name}")
|
||||||
|
|
||||||
rm -f "${CONFDIR}/${jail}"
|
test -d "${jail_path}" || error "${jail_name}: jail is missing."
|
||||||
jail_inode=$(stat --format=%i "${JAILDIR}/${jail}")
|
|
||||||
|
"${LIBDIR}/bkctld-is-on" "${jail_name}" && "${LIBDIR}/bkctld-stop" "${jail_name}"
|
||||||
|
|
||||||
|
rm -f "${CONFDIR}/${jail_name}"
|
||||||
|
jail_inode=$(stat --format=%i "${jail_path}")
|
||||||
if [ "${jail_inode}" -eq 256 ]; then
|
if [ "${jail_inode}" -eq 256 ]; then
|
||||||
/bin/btrfs subvolume delete "${JAILDIR}/${jail}" | debug
|
/bin/btrfs subvolume delete "${jail_path}" | debug
|
||||||
else
|
else
|
||||||
rm -rf "${JAILDIR}/${jail}" | debug
|
rm -rf "${jail_path:?}" | debug
|
||||||
fi
|
fi
|
||||||
if [ -d "${INCDIR}/${jail}" ]; then
|
# TODO: use functions here
|
||||||
incs=$(ls "${INCDIR}/${jail}")
|
if [ -d "${incs_path}" ]; then
|
||||||
|
incs=$(ls "${incs_path}")
|
||||||
for inc in ${incs}; do
|
for inc in ${incs}; do
|
||||||
inc_inode=$(stat --format=%i "${INCDIR}/${jail}/${inc}")
|
inc_inode=$(stat --format=%i "${incs_path}/${inc}")
|
||||||
if [ "${inc_inode}" -eq 256 ]; then
|
if [ "${inc_inode}" -eq 256 ]; then
|
||||||
/bin/btrfs subvolume delete "${INCDIR}/${jail}/${inc}" | debug
|
/bin/btrfs subvolume delete "${incs_path}/${inc}" | debug
|
||||||
else
|
else
|
||||||
warning "You need to purge ${INCDIR}/${jail}/${inc} manually !"
|
warning "You need to purge ${incs_path}/${inc} manually !"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
rmdir --ignore-fail-on-non-empty "${INCDIR}/${jail}" | debug
|
rmdir --ignore-fail-on-non-empty "${incs_path}" | debug
|
||||||
fi
|
fi
|
||||||
"${LIBDIR}/bkctld-firewall" "${jail}"
|
"${LIBDIR}/bkctld-firewall" "${jail_name}"
|
||||||
notice "${jail} : deleted jail"
|
notice "${jail_name}: jail has been deleted."
|
||||||
|
|
|
@ -6,12 +6,16 @@
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
if [ ! -n "${jail}" ]; then
|
if [ -z "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : trying to restart inexistant jail"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
"${LIBDIR}/bkctld-is-on" "${jail}" && "${LIBDIR}/bkctld-stop" "${jail}"
|
|
||||||
"${LIBDIR}/bkctld-start" "${jail}"
|
test -d "${jail_path}" || error "${jail_name}: jail is missing."
|
||||||
|
|
||||||
|
"${LIBDIR}/bkctld-is-on" "${jail_name}" && "${LIBDIR}/bkctld-stop" "${jail_name}"
|
||||||
|
"${LIBDIR}/bkctld-start" "${jail_name}"
|
||||||
|
|
136
lib/bkctld-rm
136
lib/bkctld-rm
|
@ -4,41 +4,109 @@
|
||||||
# Usage: rm
|
# Usage: rm
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
for jail in $("${LIBDIR}/bkctld-list"); do
|
relative_date() {
|
||||||
incs=$(ls "${INCDIR}/${jail}")
|
format=$(echo $1 | cut -d'.' -f1)
|
||||||
if [ -f "${CONFDIR}/${jail}" ]; then
|
time_jump=$(echo $1 | cut -d'.' -f2)
|
||||||
keepfile="$(mktemp)"
|
|
||||||
while read j; do
|
reference_date=$(date "${format}")
|
||||||
date=$( echo "${j}" | cut -d. -f1 )
|
past_date=$(date --date "${reference_date} ${time_jump}" +"%Y-%m-%d")
|
||||||
before=$( echo "${j}" | cut -d. -f2 )
|
|
||||||
date -d "$(date "${date}") ${before}" "+%Y-%m-%d"
|
echo ${past_date}
|
||||||
done < "${CONFDIR}/${jail}" > "${keepfile}"
|
}
|
||||||
for j in $(echo "${incs}" | grep -v -f "${keepfile}"); do
|
|
||||||
start=$(date +"%H:%M:%S")
|
delete_inc_btrfs() {
|
||||||
inc_inode=$(stat --format=%i "${INCDIR}/${jail}/${j}")
|
jail_name=$1
|
||||||
if [ "${inc_inode}" -eq 256 ]; then
|
inc_name=$2
|
||||||
/bin/btrfs subvolume delete "${INCDIR}/${jail}/${j}" | debug
|
|
||||||
end=$(date +"%H:%M:%S")
|
inc_path=$(inc_path "${jail_name}" "${inc_name}")
|
||||||
notice "${jail} : deleted ${j} inc [${start}/${end}]"
|
|
||||||
else
|
start=$(current_time)
|
||||||
lock="/run/lock/bkctld/rm-${jail}.lock"
|
|
||||||
if [ -f "${lock}" ]; then
|
if dry_run; then
|
||||||
warning "${jail} : trying to run already running rm"
|
echo "[dry-run] delete btrfs subvolume ${inc_path}"
|
||||||
else
|
else
|
||||||
(
|
/bin/btrfs subvolume delete "${inc_path}" | debug
|
||||||
empty="/tmp/bkctld-${$}-$(date +%N)"
|
fi
|
||||||
mkdir -p /run/lock/bkctld && touch "${lock}" && mkdir -p "${empty}"
|
|
||||||
trap "rm -f ${lock} && rmdir ${empty}" 0
|
end=$(current_time)
|
||||||
rsync -a --delete "${empty}/" "${INCDIR}/${jail}/${j}/"
|
notice "${jail_name}: inc '${inc_name}' has been deleted [${start}/${end}]"
|
||||||
rmdir "${INCDIR}/${jail}/${j}/"
|
}
|
||||||
end=$(date +"%H:%M:%S")
|
delete_inc_ext4() {
|
||||||
notice "${jail} : deleted ${j} inc [${start}/${end}]"
|
jail_name=$1
|
||||||
)
|
inc_name=$2
|
||||||
fi
|
|
||||||
fi
|
inc_path=$(inc_path "${jail_name}" "${inc_name}")
|
||||||
|
|
||||||
|
lock_file="${LOCKDIR}/rm-global.lock"
|
||||||
|
if [ -f "${lock_file}" ]; then
|
||||||
|
# Get Process ID from the lock file
|
||||||
|
pid=$(cat "${lock_file}")
|
||||||
|
if kill -0 ${pid} 2> /dev/null; then
|
||||||
|
# Kill the children
|
||||||
|
pkill -9 --parent "${pid}"
|
||||||
|
# Kill the parent
|
||||||
|
kill -9 "${pid}"
|
||||||
|
# Remove the lock file
|
||||||
|
rm -f ${lock_file}
|
||||||
|
warning "Process ${pid} has been killed. Only one ${0} can run in parallel, the latest wins."
|
||||||
|
else
|
||||||
|
error "Empty lockfile '${lock_file}'. It should contain a PID."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir --parents "${LOCKDIR}" && echo $$ > ${lock_file} || error "Failed to acquire lock file '${lock_file}'"
|
||||||
|
empty=$(mktemp -d --suffix ".${$}" bkctld.XXXXX)
|
||||||
|
# shellcheck disable=SC2064
|
||||||
|
trap "rm -f ${lock_file}; rmdir ${empty}" 0
|
||||||
|
|
||||||
|
if dry_run; then
|
||||||
|
echo "[dry-run] delete ${inc_path} with rsync from ${empty}"
|
||||||
|
else
|
||||||
|
rsync --archive --delete "${empty}/" "${inc_path}/"
|
||||||
|
rmdir "${inc_path}/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
end=$(current_time)
|
||||||
|
notice "${jail_name}: inc '${inc_name}' has been deleted [${start}/${end}]"
|
||||||
|
}
|
||||||
|
|
||||||
|
for jail_name in $(jails_list); do
|
||||||
|
incs_policy_file=$(current_jail_incs_policy_file ${jail_name})
|
||||||
|
|
||||||
|
# If not incs policy if found, we don't remove incs
|
||||||
|
if [ -n "${incs_policy_file}" ]; then
|
||||||
|
incs_policy_keep_file="$(mktemp)"
|
||||||
|
incs_list_file="$(mktemp)"
|
||||||
|
# shellcheck disable=SC2064
|
||||||
|
trap "rm -f ${incs_policy_keep_file} ${incs_list_file}" 0
|
||||||
|
|
||||||
|
# loop for each line in jail configuration
|
||||||
|
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}"
|
||||||
done
|
done
|
||||||
rm "${keepfile}"
|
for inc_name in $(incs_list "${jail_name}"); do
|
||||||
|
echo "${inc_name}" >> ${incs_list_file}
|
||||||
|
done
|
||||||
|
# shellcheck disable=SC2046
|
||||||
|
incs_to_delete=$(grep -v -f "${incs_policy_keep_file}" "${incs_list_file}")
|
||||||
|
|
||||||
|
if [ -n "${incs_to_delete}" ]; then
|
||||||
|
debug "${jail_name}: incs to be deleted : $(echo "${incs_to_delete}" | tr '\n', ',' | sed 's/,$//')."
|
||||||
|
for inc_name in ${incs_to_delete}; do
|
||||||
|
inc_path=$(inc_path "${jail_name}" "${inc_name}")
|
||||||
|
if is_btrfs "${inc_path}"; then
|
||||||
|
delete_inc_btrfs "${jail_name}" "${inc_name}"
|
||||||
|
else
|
||||||
|
delete_inc_ext4 "${jail_name}" "${inc_name}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
notice "${jail_name}: no inc to be deleted."
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
@ -4,39 +4,40 @@
|
||||||
# Usage: start <jailname>|all
|
# Usage: start <jailname>|all
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
if [ ! -n "${jail}" ]; then
|
if [ -z "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : trying to start inexistant jail"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
"${LIBDIR}/bkctld-is-on" "${jail}" && exit 0
|
|
||||||
|
|
||||||
cd "${JAILDIR}/${jail}"
|
test -d "${jail_path}" || error "${jail_name}: jail is missing."
|
||||||
grep -q "${JAILDIR}/${jail}/proc" /proc/mounts || mount -t proc "proc-${jail}" proc
|
|
||||||
grep -q "${JAILDIR}/${jail}/dev" /proc/mounts || mount -nt tmpfs "dev-${jail}" dev
|
"${LIBDIR}/bkctld-is-on" "${jail_name}" && exit 0
|
||||||
[ -e "dev/console" ] || mknod -m 622 dev/console c 5 1
|
|
||||||
[ -e "dev/null" ] || mknod -m 666 dev/null c 1 3
|
# Prepare the chroot
|
||||||
[ -e "dev/zero" ] || mknod -m 666 dev/zero c 1 5
|
mount_jail_fs "${jail_name}"
|
||||||
[ -e "dev/ptmx" ] || mknod -m 666 dev/ptmx c 5 2
|
|
||||||
[ -e "dev/tty" ] || mknod -m 666 dev/tty c 5 0
|
# Start SSH in the chroot
|
||||||
[ -e "dev/random" ] || mknod -m 444 dev/random c 1 8
|
chroot "${jail_path}" /usr/sbin/sshd -E /var/log/authlog || error "${jail_name}: failed to start SSH."
|
||||||
[ -e "dev/urandom" ] || mknod -m 444 dev/urandom c 1 9
|
pidfile="${jail_path}/${SSHD_PID}"
|
||||||
chown root:tty dev/console dev/ptmx dev/tty
|
|
||||||
ln -fs proc/self/fd dev/fd
|
# Wait for SSH to be up
|
||||||
ln -fs proc/self/fd/0 dev/stdin
|
# shellcheck disable=SC2034
|
||||||
ln -fs proc/self/fd/1 dev/stdout
|
for try in $(seq 1 10); do
|
||||||
ln -fs proc/self/fd/2 dev/stderr
|
if [ -f "${pidfile}" ]; then
|
||||||
ln -fs proc/kcore dev/core
|
pid=$(cat "${pidfile}")
|
||||||
mkdir -p dev/pts
|
break
|
||||||
mkdir -p dev/shm
|
else
|
||||||
grep -q "${JAILDIR}/${jail}/dev/pts" /proc/mounts || mount -t devpts -o gid=4,mode=620 none dev/pts
|
pid=""
|
||||||
grep -q "${JAILDIR}/${jail}/dev/shm" /proc/mounts || mount -t tmpfs none dev/shm
|
sleep 0.3
|
||||||
chroot "${JAILDIR}/${jail}" /usr/sbin/sshd -E /var/log/authlog || error "${jail} : error on starting sshd"
|
fi
|
||||||
pidfile="${JAILDIR}/${jail}/${SSHD_PID}"
|
|
||||||
for try in {1..10}; do
|
|
||||||
[ -f "${pidfile}" ] || sleep 0.3
|
|
||||||
done
|
done
|
||||||
pid=$(cat "${pidfile}")
|
|
||||||
notice "${jail} was started [${pid}]"
|
if [ -n "${pid}" ]; then
|
||||||
|
notice "${jail_name}: jail has been started [${pid}]"
|
||||||
|
else
|
||||||
|
error "${jail_name}: failed to fetch SSH pid within 3 sec."
|
||||||
|
fi
|
||||||
|
|
|
@ -4,31 +4,45 @@
|
||||||
# Usage: stats
|
# Usage: stats
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
mkdir -p "${INDEX_DIR}"
|
mkdir -p "${INDEX_DIR}"
|
||||||
|
|
||||||
lsof "${IDX_FILE}" >/dev/null 2>&1 || nohup sh -s -- <<EOF >/dev/null 2>&1 &
|
lsof "${IDX_FILE}" >/dev/null 2>&1 || nohup sh -s -- <<EOF >/dev/null 2>&1 &
|
||||||
|
|
||||||
ionice -c3 "${DUC}" index -d "${IDX_FILE}" "${JAILDIR}"
|
ionice -c3 "${DUC}" index -d "${IDX_FILE}" "${JAILDIR}"
|
||||||
touch "${INDEX_DIR}/.lastrun.duc"
|
touch "${INDEX_DIR}/.lastrun.duc"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
[ ! -f "${INDEX_DIR}/.lastrun.duc" ] && notice "First run of DUC always in progress ..." && exit 0
|
[ ! -f "${INDEX_DIR}/.lastrun.duc" ] && notice "First run of DUC always in progress ..." && exit 0
|
||||||
[ ! -f ${IDX_FILE} ] && error "Index file do not exits !"
|
[ ! -f ${IDX_FILE} ] && error "Index file do not exits !"
|
||||||
|
|
||||||
printf "Last update of index file : "
|
printf "Last update of index file : "
|
||||||
stat --format=%Y "${INDEX_DIR}/.lastrun.duc" | xargs -i -n1 date -R -d "@{}"
|
stat --format=%Y "${INDEX_DIR}/.lastrun.duc" | xargs -i -n1 date -R -d "@{}"
|
||||||
echo "<jail> <size> <incs> <lastconn>" | awk '{ printf("%- 30s %- 10s %- 10s %- 15s\n", $1, $2, $3, $4); }'
|
echo "<jail> <size> <incs> <lastconn>" | awk '{ printf("%- 30s %- 10s %- 10s %- 15s\n", $1, $2, $3, $4); }'
|
||||||
|
|
||||||
duc_output=$(mktemp)
|
duc_output=$(mktemp)
|
||||||
stat_output=$(mktemp)
|
stat_output=$(mktemp)
|
||||||
incs_output=$(mktemp)
|
incs_output=$(mktemp)
|
||||||
|
|
||||||
|
# shellcheck disable=SC2064
|
||||||
trap "rm ${duc_output} ${incs_output} ${stat_output}" 0
|
trap "rm ${duc_output} ${incs_output} ${stat_output}" 0
|
||||||
|
|
||||||
"${DUC}" ls -d "${IDX_FILE}" "${JAILDIR}" > "${duc_output}"
|
"${DUC}" ls -d "${IDX_FILE}" "${JAILDIR}" > "${duc_output}"
|
||||||
awk '{ print $2 }' "${duc_output}" | while read jail; do
|
|
||||||
stat --format=%Y "/backup/jails/${jail}/var/log/lastlog" | xargs -i -n1 date -d "@{}" "+%d-%m-%Y" >> "${stat_output}"
|
awk '{ print $2 }' "${duc_output}" | while read jail_name; do
|
||||||
inc=0
|
jail_path=$(jail_path "${jail_name}")
|
||||||
if [ -f "${CONFDIR}/${jail}" ]; then
|
stat --format=%Y "${jail_path}/var/log/lastlog" | xargs -i -n1 date -d "@{}" "+%d-%m-%Y" >> "${stat_output}"
|
||||||
day=$(grep -c "day" "${CONFDIR}/${jail}")
|
|
||||||
month=$(grep -c "month" "${CONFDIR}/${jail}")
|
incs_policy_file=$(current_jail_incs_policy_file ${jail_name})
|
||||||
inc="${day}/${month}"
|
incs_policy="0"
|
||||||
|
if [ -r "${incs_policy_file}" ]; then
|
||||||
|
days=$(grep "^\+" "${incs_policy_file}" | grep --count "day")
|
||||||
|
months=$(grep "^\+" "${incs_policy_file}" | grep --count "month")
|
||||||
|
incs_policy="${days}/${months}"
|
||||||
fi
|
fi
|
||||||
echo "${inc}" >> "${incs_output}"
|
echo "${incs_policy}" >> "${incs_output}"
|
||||||
done
|
done
|
||||||
|
|
||||||
paste "${duc_output}" "${incs_output}" "${stat_output}" | awk '{ printf("%- 30s %- 10s %- 10s %- 15s\n", $2, $1, $3, $4); }'
|
paste "${duc_output}" "${incs_output}" "${stat_output}" | awk '{ printf("%- 30s %- 10s %- 10s %- 15s\n", $2, $1, $3, $4); }'
|
||||||
|
|
|
@ -4,22 +4,27 @@
|
||||||
# Usage: status [<jailname>]
|
# Usage: status [<jailname>]
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
if [ ! -n "${jail}" ]; then
|
if [ ! -n "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : inexistant jail ! Use '$0 status' for list all"
|
[ -d "${JAILDIR}/${jail_name}" ] || error "${jail_name} : jail is missing.\nUse '$0 status [all]' to get the status of all jails."
|
||||||
|
|
||||||
inc="0"
|
incs_policy_file=$(current_jail_incs_policy_file ${jail_name})
|
||||||
if [ -f "${CONFDIR}/${jail}" ]; then
|
incs_policy="0"
|
||||||
day=$(grep -c "day" "${CONFDIR}/${jail}")
|
if [ -r "${incs_policy_file}" ]; then
|
||||||
month=$(grep -c "month" "${CONFDIR}/${jail}")
|
days=$(grep "^\+" "${incs_policy_file}" | grep --count "day")
|
||||||
inc="${day}/${month}"
|
months=$(grep "^\+" "${incs_policy_file}" | grep --count "month")
|
||||||
|
incs_policy="${days}/${months}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
status="OFF"
|
status="OFF"
|
||||||
"${LIBDIR}/bkctld-is-on" "${jail}" && status="ON "
|
"${LIBDIR}/bkctld-is-on" "${jail_name}" && status="ON "
|
||||||
port=$("${LIBDIR}/bkctld-port" "${jail}")
|
|
||||||
ip=$("${LIBDIR}/bkctld-ip" "${jail}"|xargs|tr -s ' ' ',')
|
port=$("${LIBDIR}/bkctld-port" "${jail_name}")
|
||||||
echo "${jail} ${status} ${port} ${inc} ${ip}" | awk '{ printf("%- 30s %- 10s %- 10s %- 10s %- 40s\n", $1, $2, $3, $4, $5); }'
|
ip=$("${LIBDIR}/bkctld-ip" "${jail_name}" | xargs | tr -s ' ' ',')
|
||||||
|
|
||||||
|
echo "${jail_name} ${status} ${port} ${incs_policy} ${ip}" | awk '{ printf("%- 30s %- 10s %- 10s %- 10s %- 40s\n", $1, $2, $3, $4, $5); }'
|
||||||
|
|
|
@ -4,19 +4,28 @@
|
||||||
# Usage: stop <jailname>|all
|
# Usage: stop <jailname>|all
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
if [ ! -n "${jail}" ]; then
|
if [ -z "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : trying to stop inexistant jail"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
"${LIBDIR}/bkctld-is-on" "${jail}" || exit 0
|
|
||||||
|
|
||||||
pid=$(cat "${JAILDIR}/${jail}/${SSHD_PID}")
|
test -d "${jail_path}" || error "${jail_name}: jail is missing."
|
||||||
for conn in $(ps --ppid "${pid}" -o pid=); do
|
|
||||||
kill "${conn}"
|
"${LIBDIR}/bkctld-is-on" "${jail_name}" || exit 0
|
||||||
done
|
|
||||||
kill "${pid}" && notice "${jail} was stopped [${pid}]"
|
pid=$(cat "${jail_path}/${SSHD_PID}")
|
||||||
umount --lazy --recursive "${JAILDIR}/${jail}/dev"
|
|
||||||
umount --lazy "${JAILDIR}/${jail}/proc/"
|
pkill --parent "${pid}"
|
||||||
|
|
||||||
|
if kill "${pid}"; then
|
||||||
|
notice "${jail_name}: jail has been stopped [${pid}]"
|
||||||
|
|
||||||
|
umount --lazy --recursive "${jail_path}/dev"
|
||||||
|
umount --lazy "${jail_path}/proc/"
|
||||||
|
else
|
||||||
|
error "${jail_name}: failed to stop jail [${pid}]"
|
||||||
|
fi
|
||||||
|
|
|
@ -4,21 +4,37 @@
|
||||||
# Usage: sync <jailname>|all
|
# Usage: sync <jailname>|all
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
if [ ! -n "${jail}" ]; then
|
if [ -z "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : trying to sync inexistant jail"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
jail_config_dir=$(jail_config_dir "${jail_name}")
|
||||||
|
|
||||||
|
test -d "${jail_path}" || error "${jail_name}: jail is missing."
|
||||||
|
|
||||||
[ -n "${NODE}" ] || error "Sync need config of \$NODE in /etc/default/bkctld !"
|
[ -n "${NODE}" ] || error "Sync need config of \$NODE in /etc/default/bkctld !"
|
||||||
|
|
||||||
jail="${1}"
|
# Init jail on remote server
|
||||||
ssh "${NODE}" "${LIBDIR}/bkctld-init" "${jail}" | debug
|
ssh "${NODE}" "${LIBDIR}/bkctld-init" "${jail_name}" | debug
|
||||||
rsync -a "${JAILDIR}/${jail}/" "${NODE}:${JAILDIR}/${jail}/" --exclude proc/* --exclude sys/* --exclude dev/* --exclude run --exclude var/backup/*
|
|
||||||
rsync -a "${CONFDIR}/${jail}" "${NODE}:${CONFDIR}/${jail}"
|
# Sync Jail structure and configuration on remote server
|
||||||
"${LIBDIR}/bkctld-is-on" "${jail}" && ssh "${NODE}" "${LIBDIR}/bkctld-start" "${jail}" | debug
|
rsync -a "${jail_path}/" "${NODE}:${jail_path}/" --exclude proc/* --exclude sys/* --exclude dev/* --exclude run --exclude var/backup/*
|
||||||
|
# New config directory
|
||||||
|
rsync -a "${jail_config_dir}" "${NODE}:${jail_config_dir}"
|
||||||
|
# Old incs policy config file
|
||||||
|
rsync -a "${CONFDIR}/${jail_name}" "${NODE}:${CONFDIR}/${jail_name}"
|
||||||
|
|
||||||
|
# Sync state on remote server
|
||||||
|
if "${LIBDIR}/bkctld-is-on" "${jail_name}"; then
|
||||||
|
ssh "${NODE}" "${LIBDIR}/bkctld-start" "${jail_name}" | debug
|
||||||
|
else
|
||||||
|
ssh "${NODE}" "${LIBDIR}/bkctld-stop" "${jail_name}" | debug
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -n "${FIREWALL_RULES}" ]; then
|
if [ -n "${FIREWALL_RULES}" ]; then
|
||||||
rsync -a "${FIREWALL_RULES}" "${NODE}:${FIREWALL_RULES}"
|
rsync -a "${FIREWALL_RULES}" "${NODE}:${FIREWALL_RULES}"
|
||||||
ssh "${NODE}" /etc/init.d/minifirewall restart | debug
|
ssh "${NODE}" /etc/init.d/minifirewall restart | debug
|
||||||
|
|
|
@ -4,14 +4,19 @@
|
||||||
# Usage: update <jailname>|all
|
# Usage: update <jailname>|all
|
||||||
#
|
#
|
||||||
|
|
||||||
LIBDIR="$(dirname $0)" && . "${LIBDIR}/config"
|
# shellcheck source=./includes
|
||||||
|
LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes"
|
||||||
|
|
||||||
jail="${1:-}"
|
jail_name="${1:?}"
|
||||||
if [ ! -n "${jail}" ]; then
|
if [ ! -n "${jail_name}" ]; then
|
||||||
"${LIBDIR}/bkctld-help" && exit 1
|
"${LIBDIR}/bkctld-help" && exit 1
|
||||||
fi
|
fi
|
||||||
[ -d "${JAILDIR}/${jail}" ] || error "${jail} : trying to update inexistant jail"
|
jail_path=$(jail_path "${jail_name}")
|
||||||
"${LIBDIR}/bkctld-is-on" "${jail}" && "${LIBDIR}/bkctld-stop" "${jail}"
|
|
||||||
|
|
||||||
. "${LIBDIR}/mkjail"
|
test -d "${jail_path}" || error "${jail_name}: jail is missing."
|
||||||
notice "${jail} : updated jail"
|
|
||||||
|
"${LIBDIR}/bkctld-is-on" "${jail_name}" && "${LIBDIR}/bkctld-stop" "${jail_name}"
|
||||||
|
|
||||||
|
setup_jail_chroot "${jail_name}"
|
||||||
|
|
||||||
|
notice "${jail_name}: jail has been updated."
|
||||||
|
|
64
lib/config
64
lib/config
|
@ -1,64 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Config for bkctld
|
|
||||||
#
|
|
||||||
|
|
||||||
[ -f /etc/default/bkctld ] && . /etc/default/bkctld
|
|
||||||
LIBDIR=${LIBDIR:-/usr/lib/bkctld}
|
|
||||||
CONFDIR="${CONFDIR:-/etc/evobackup}"
|
|
||||||
BACKUP_DISK="${BACKUP_DISK:-}"
|
|
||||||
JAILDIR="${JAILDIR:-/backup/jails}"
|
|
||||||
INCDIR="${INCDIR:-/backup/incs}"
|
|
||||||
TPLDIR="${TPLDIR:-/usr/share/bkctld}"
|
|
||||||
INDEX_DIR="${INDEX_DIR:-/backup/index}"
|
|
||||||
IDX_FILE="${IDX_FILE:-${INDEX_DIR}/bkctld-jails.idx}"
|
|
||||||
LOCALTPLDIR="${LOCALTPLDIR:-/usr/local/share/bkctld}"
|
|
||||||
SSHD_PID="${SSHD_PID:-/run/sshd.pid}"
|
|
||||||
SSHD_CONFIG="${SSHD_CONFIG:-/etc/ssh/sshd_config}"
|
|
||||||
AUTHORIZED_KEYS="${AUTHORIZED_KEYS:-/root/.ssh/authorized_keys}"
|
|
||||||
FIREWALL_RULES="${FIREWALL_RULES:-}"
|
|
||||||
LOGLEVEL="${LOGLEVEL:-6}"
|
|
||||||
CRITICAL="${CRITICAL:-48}"
|
|
||||||
WARNING="${WARNING:-24}"
|
|
||||||
DUC=$(command -v duc-nox||command -v duc)
|
|
||||||
|
|
||||||
debug() {
|
|
||||||
msg="${1:-$(cat /dev/stdin)}"
|
|
||||||
if [ "${LOGLEVEL}" -ge 7 ]; then
|
|
||||||
echo "${msg}"
|
|
||||||
logger -t bkctld -p daemon.debug "${msg}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
info() {
|
|
||||||
msg="${1:-$(cat /dev/stdin)}"
|
|
||||||
if [ "${LOGLEVEL}" -ge 6 ]; then
|
|
||||||
tty -s && echo "${msg}"
|
|
||||||
logger -t bkctld -p daemon.info "${msg}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
notice() {
|
|
||||||
msg="${1:-$(cat /dev/stdin)}"
|
|
||||||
tty -s && echo "${msg}"
|
|
||||||
[ "${LOGLEVEL}" -ge 5 ] && logger -t bkctld -p daemon.notice "${msg}"
|
|
||||||
}
|
|
||||||
|
|
||||||
warning() {
|
|
||||||
msg="${1:-$(cat /dev/stdin)}"
|
|
||||||
tty -s && echo "WARNING : ${msg}" >&2
|
|
||||||
if [ "${LOGLEVEL}" -ge 4 ]; then
|
|
||||||
tty -s || echo "WARNING : ${msg}" >&2
|
|
||||||
logger -t bkctld -p daemon.warning "${msg}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
error() {
|
|
||||||
msg="${1:-$(cat /dev/stdin)}"
|
|
||||||
tty -s && echo "ERROR : ${msg}" >&2
|
|
||||||
if [ "${LOGLEVEL}" -ge 5 ]; then
|
|
||||||
tty -s || echo "ERROR : ${msg}" >&2
|
|
||||||
logger -t bkctld -p daemon.error "${msg}"
|
|
||||||
fi
|
|
||||||
exit 1
|
|
||||||
}
|
|
295
lib/includes
Executable file
295
lib/includes
Executable file
|
@ -0,0 +1,295 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Config for bkctld
|
||||||
|
#
|
||||||
|
|
||||||
|
[ -f /etc/default/bkctld ] && . /etc/default/bkctld
|
||||||
|
LIBDIR=${LIBDIR:-/usr/lib/bkctld}
|
||||||
|
CONFDIR="${CONFDIR:-/etc/evobackup}"
|
||||||
|
BACKUP_DISK="${BACKUP_DISK:-}"
|
||||||
|
JAILDIR="${JAILDIR:-/backup/jails}"
|
||||||
|
INCDIR="${INCDIR:-/backup/incs}"
|
||||||
|
TPLDIR="${TPLDIR:-/usr/share/bkctld}"
|
||||||
|
LOCALTPLDIR="${LOCALTPLDIR:-/usr/local/share/bkctld}"
|
||||||
|
LOCKDIR="${LOCKDIR:-/run/lock/bkctld}"
|
||||||
|
INDEX_DIR="${INDEX_DIR:-/backup/index}"
|
||||||
|
IDX_FILE="${IDX_FILE:-${INDEX_DIR}/bkctld-jails.idx}"
|
||||||
|
SSHD_PID="${SSHD_PID:-/run/sshd.pid}"
|
||||||
|
SSHD_CONFIG="${SSHD_CONFIG:-/etc/ssh/sshd_config}"
|
||||||
|
AUTHORIZED_KEYS="${AUTHORIZED_KEYS:-/root/.ssh/authorized_keys}"
|
||||||
|
FIREWALL_RULES="${FIREWALL_RULES:-}"
|
||||||
|
LOGLEVEL="${LOGLEVEL:-6}"
|
||||||
|
CRITICAL="${CRITICAL:-48}"
|
||||||
|
WARNING="${WARNING:-24}"
|
||||||
|
DUC=$(command -v duc-nox || command -v duc)
|
||||||
|
|
||||||
|
debug() {
|
||||||
|
msg="${1:-$(cat /dev/stdin)}"
|
||||||
|
if [ "${LOGLEVEL}" -ge 7 ]; then
|
||||||
|
echo "${msg}"
|
||||||
|
logger -t bkctld -p daemon.debug "${msg}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
info() {
|
||||||
|
msg="${1:-$(cat /dev/stdin)}"
|
||||||
|
if [ "${LOGLEVEL}" -ge 6 ]; then
|
||||||
|
tty -s && echo "${msg}"
|
||||||
|
logger -t bkctld -p daemon.info "${msg}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
notice() {
|
||||||
|
msg="${1:-$(cat /dev/stdin)}"
|
||||||
|
tty -s && echo "${msg}"
|
||||||
|
[ "${LOGLEVEL}" -ge 5 ] && logger -t bkctld -p daemon.notice "${msg}"
|
||||||
|
}
|
||||||
|
|
||||||
|
warning() {
|
||||||
|
msg="${1:-$(cat /dev/stdin)}"
|
||||||
|
tty -s && echo "WARNING : ${msg}" >&2
|
||||||
|
if [ "${LOGLEVEL}" -ge 4 ]; then
|
||||||
|
tty -s || echo "WARNING : ${msg}" >&2
|
||||||
|
logger -t bkctld -p daemon.warning "${msg}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
msg="${1:-$(cat /dev/stdin)}"
|
||||||
|
tty -s && echo "ERROR : ${msg}" >&2
|
||||||
|
if [ "${LOGLEVEL}" -ge 5 ]; then
|
||||||
|
tty -s || echo "ERROR : ${msg}" >&2
|
||||||
|
logger -t bkctld -p daemon.error "${msg}"
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
dry_run() {
|
||||||
|
test "$DRY_RUN" = "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
current_time() {
|
||||||
|
date +"%H:%M:%S"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns true if the given path is on a btrfs filesystem
|
||||||
|
is_btrfs() {
|
||||||
|
path=$1
|
||||||
|
|
||||||
|
inode=$(stat --format=%i "${path}")
|
||||||
|
|
||||||
|
test $inode -eq 256
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the list of all jails
|
||||||
|
jails_list() {
|
||||||
|
# shellcheck disable=SC2091
|
||||||
|
"${LIBDIR}/bkctld-list"
|
||||||
|
}
|
||||||
|
# Returns the list of all incs for a jail
|
||||||
|
incs_list() {
|
||||||
|
jail_name=${1:?}
|
||||||
|
# shellcheck disable=SC2091
|
||||||
|
ls "$(incs_path "${jail_name}")/"
|
||||||
|
}
|
||||||
|
# Returns the complete path of a jail
|
||||||
|
jail_path() {
|
||||||
|
jail_name=${1:?}
|
||||||
|
|
||||||
|
echo "${JAILDIR}/${jail_name}"
|
||||||
|
}
|
||||||
|
# Returns the path of incs for a jail
|
||||||
|
incs_path() {
|
||||||
|
jail_name=${1:?}
|
||||||
|
|
||||||
|
echo "${INCDIR}/${jail_name}"
|
||||||
|
}
|
||||||
|
# Returns the path of a specific inc for a jail
|
||||||
|
inc_path() {
|
||||||
|
jail_name=${1:?}
|
||||||
|
inc_name=${2:?}
|
||||||
|
|
||||||
|
echo "${INCDIR}/${jail_name}/${inc_name}"
|
||||||
|
}
|
||||||
|
jail_config_dir() {
|
||||||
|
jail_name=${1:?}
|
||||||
|
|
||||||
|
echo "${CONFDIR}/${jail_name}.d"
|
||||||
|
}
|
||||||
|
jail_incs_policy_file() {
|
||||||
|
jail_name=${1:?}
|
||||||
|
|
||||||
|
jail_config_dir=$(jail_config_dir "${jail_name}")
|
||||||
|
|
||||||
|
echo "${jail_config_dir}/incs_policy"
|
||||||
|
}
|
||||||
|
current_jail_incs_policy_file() {
|
||||||
|
jail_name=${1:?}
|
||||||
|
|
||||||
|
new_file="$(jail_incs_policy_file "${jail_name}")"
|
||||||
|
old_file="${CONFDIR}/${jail_name}"
|
||||||
|
|
||||||
|
if [ -f "${new_file}" ]; then
|
||||||
|
echo "${new_file}"
|
||||||
|
elif [ -f "${old_file}" ]; then
|
||||||
|
echo "${old_file}"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
jail_check_policy_file() {
|
||||||
|
jail_name=${1:?}
|
||||||
|
|
||||||
|
jail_config_dir=$(jail_config_dir "${jail_name}")
|
||||||
|
|
||||||
|
echo "${jail_config_dir}/check_policy"
|
||||||
|
}
|
||||||
|
current_jail_check_policy_file() {
|
||||||
|
jail_name=${1:?}
|
||||||
|
|
||||||
|
new_file="$(jail_check_policy_file "${jail_name}")"
|
||||||
|
# old_file="${JAILDIR}/${jail_name}/etc/bkctld-check"
|
||||||
|
|
||||||
|
if [ -f "${new_file}" ]; then
|
||||||
|
echo "${new_file}"
|
||||||
|
# elif [ -f "${old_file}" ]; then
|
||||||
|
# echo "${old_file}"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_jail_chroot() {
|
||||||
|
jail_name=${1:?}
|
||||||
|
|
||||||
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
|
||||||
|
passwd="${TPLDIR}/passwd"
|
||||||
|
shadow="${TPLDIR}/shadow"
|
||||||
|
group="${TPLDIR}/group"
|
||||||
|
sshrc="${TPLDIR}/sshrc"
|
||||||
|
[ -f "${LOCALTPLDIR}/passwd" ] && passwd="${LOCALTPLDIR}/passwd"
|
||||||
|
[ -f "${LOCALTPLDIR}/shadow" ] && shadow="${LOCALTPLDIR}/shadow"
|
||||||
|
[ -f "${LOCALTPLDIR}/group" ] && group="${LOCALTPLDIR}/group"
|
||||||
|
[ -f "${LOCALTPLDIR}/sshrc" ] && group="${LOCALTPLDIR}/sshrc"
|
||||||
|
|
||||||
|
cd "${jail_path}" || error "${jail_name}: failed to change directory to ${jail_path}."
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
info "1 - Creating the chroot"
|
||||||
|
rm -rf ./bin ./lib ./lib64 ./run ./usr ./var/run ./etc/ssh/*key
|
||||||
|
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 ./var/log
|
||||||
|
mkdir -p ./run/sshd
|
||||||
|
# shellcheck disable=SC2174
|
||||||
|
mkdir -p ./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
|
||||||
|
touch ./var/log/lastlog ./var/log/wtmp ./run/utmp
|
||||||
|
|
||||||
|
info "2 - Copying essential files"
|
||||||
|
[ -f /etc/ssh/ssh_host_rsa_key ] && cp /etc/ssh/ssh_host_rsa_key ./etc/ssh
|
||||||
|
[ -f /etc/ssh/ssh_host_ecdsa_key ] && cp /etc/ssh/ssh_host_ecdsa_key ./etc/ssh
|
||||||
|
[ -f /etc/ssh/ssh_host_ed25519_key ] && cp /etc/ssh/ssh_host_ed25519_key ./etc/ssh
|
||||||
|
touch "./${AUTHORIZED_KEYS}"
|
||||||
|
chmod 600 "./${AUTHORIZED_KEYS}"
|
||||||
|
cp "${passwd}" ./etc
|
||||||
|
cp "${shadow}" ./etc
|
||||||
|
cp "${group}" ./etc
|
||||||
|
cp "${sshrc}" ./etc/ssh
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
for dbin in /bin/sh /bin/ls /bin/mkdir /bin/cat /bin/rm /bin/sed /usr/bin/rsync /usr/bin/lastlog /usr/bin/touch /usr/sbin/sshd /usr/lib/openssh/sftp-server; do
|
||||||
|
cp -f "${dbin}" "./${dbin}";
|
||||||
|
for lib in $(ldd "${dbin}" | grep -Eo "/.*so.[0-9\.]+"); do
|
||||||
|
cp -p "${lib}" "./${lib}"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_jail_config() {
|
||||||
|
jail_name=${1:?}
|
||||||
|
|
||||||
|
jail_path=$(jail_path "${jail_name}")
|
||||||
|
jail_sshd_config="${jail_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"
|
||||||
|
install -m 0640 "${sshd_config_tpl}" "${jail_sshd_config}"
|
||||||
|
|
||||||
|
inctpl="${TPLDIR}/inc.tpl"
|
||||||
|
test -f "${LOCALTPLDIR}/inc.tpl" && inctpl="${LOCALTPLDIR}/inc.tpl"
|
||||||
|
|
||||||
|
info "5 - Copie default inc configuration"
|
||||||
|
jail_incs_policy_file=$(jail_incs_policy_file "${jail_name}")
|
||||||
|
mkdir --parents "$(dirname "${jail_incs_policy_file}")"
|
||||||
|
install -m 0640 "${inctpl}" "${jail_incs_policy_file}"
|
||||||
|
"${LIBDIR}/bkctld-port" "${jail_name}" auto
|
||||||
|
}
|
||||||
|
|
||||||
|
is_mounted_inside_jail() {
|
||||||
|
target=${1:?}
|
||||||
|
|
||||||
|
# TODO: try to find why it doesn't work with this findmnt(8) command
|
||||||
|
# findmnt --target "${target}" --tab-file /proc/mounts
|
||||||
|
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:?}
|
||||||
|
|
||||||
|
pattern="^\s*${var_name}=-?[0-9]+"
|
||||||
|
|
||||||
|
grep --extended-regexp --only-matching "${pattern}" "${file}" | cut -d= -f2
|
||||||
|
}
|
44
lib/mkjail
44
lib/mkjail
|
@ -1,44 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
passwd="${TPLDIR}/passwd"
|
|
||||||
shadow="${TPLDIR}/shadow"
|
|
||||||
group="${TPLDIR}/group"
|
|
||||||
sshrc="${TPLDIR}/sshrc"
|
|
||||||
[ -f "${LOCALTPLDIR}/passwd" ] && passwd="${LOCALTPLDIR}/passwd"
|
|
||||||
[ -f "${LOCALTPLDIR}/shadow" ] && shadow="${LOCALTPLDIR}/shadow"
|
|
||||||
[ -f "${LOCALTPLDIR}/group" ] && group="${LOCALTPLDIR}/group"
|
|
||||||
[ -f "${LOCALTPLDIR}/sshrc" ] && group="${LOCALTPLDIR}/sshrc"
|
|
||||||
umask 077
|
|
||||||
|
|
||||||
info "1 - Creating the chroot"
|
|
||||||
cd "${JAILDIR}/${jail}"
|
|
||||||
rm -rf bin lib lib64 run usr var/run etc/ssh/*key
|
|
||||||
mkdir -p dev proc
|
|
||||||
mkdir -p usr/bin usr/sbin usr/lib usr/lib/x86_64-linux-gnu usr/lib/openssh usr/lib64
|
|
||||||
mkdir -p etc/ssh var/log run/sshd
|
|
||||||
mkdir -p root/.ssh var/backup -m 0700
|
|
||||||
ln -s usr/bin bin
|
|
||||||
ln -s usr/lib lib
|
|
||||||
ln -s usr/lib64 lib64
|
|
||||||
ln -st var ../run
|
|
||||||
touch var/log/lastlog var/log/wtmp run/utmp
|
|
||||||
|
|
||||||
info "2 - Copying essential files"
|
|
||||||
[ -f /etc/ssh/ssh_host_rsa_key ] && cp /etc/ssh/ssh_host_rsa_key etc/ssh
|
|
||||||
[ -f /etc/ssh/ssh_host_ecdsa_key ] && cp /etc/ssh/ssh_host_ecdsa_key etc/ssh
|
|
||||||
[ -f /etc/ssh/ssh_host_ed25519_key ] && cp /etc/ssh/ssh_host_ed25519_key etc/ssh
|
|
||||||
cp "${passwd}" etc
|
|
||||||
cp "${shadow}" etc
|
|
||||||
cp "${group}" etc
|
|
||||||
cp "${sshrc}" etc/ssh
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
for dbin in /bin/sh /bin/ls /bin/mkdir /bin/cat /bin/rm /bin/sed /usr/bin/rsync /usr/bin/lastlog /usr/bin/touch /usr/sbin/sshd /usr/lib/openssh/sftp-server; do
|
|
||||||
cp -f "${dbin}" "${JAILDIR}/${jail}/${dbin}";
|
|
||||||
for lib in $(ldd "${dbin}" | grep -Eo "/.*so.[0-9\.]+"); do
|
|
||||||
cp -p "${lib}" "${JAILDIR}/${jail}/${lib}"
|
|
||||||
done
|
|
||||||
done
|
|
167
test/checks.bats
Normal file
167
test/checks.bats
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
#!/usr/bin/env bats
|
||||||
|
# shellcheck disable=SC1089,SC1083,SC2154
|
||||||
|
|
||||||
|
load test_helper
|
||||||
|
|
||||||
|
@test "Check OK for default values" {
|
||||||
|
touch "${JAILPATH}/var/log/lastlog"
|
||||||
|
# With default values (2 days critical, 1 day warning),
|
||||||
|
# a freshly connected jail should be "ok"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "0" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Check WARNING for default values" {
|
||||||
|
lastlog_date=$(date -d -2days --iso-8601=seconds)
|
||||||
|
touch --date="${lastlog_date}" "${JAILPATH}/var/log/lastlog"
|
||||||
|
# With default values (2 days critical, 1 day warning),
|
||||||
|
# a 2 days old jail should be "warning"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "1" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Check CRITICAL for default values" {
|
||||||
|
lastlog_date=$(date -d -3days --iso-8601=seconds)
|
||||||
|
touch --date="${lastlog_date}" "${JAILPATH}/var/log/lastlog"
|
||||||
|
# With default values (2 days critical, 1 day warning),
|
||||||
|
# a 3 days old jail should be "critical"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "2" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Check OK for custom values" {
|
||||||
|
lastlog_date=$(date -d -3days --iso-8601=seconds)
|
||||||
|
touch --date="${lastlog_date}" "${JAILPATH}/var/log/lastlog"
|
||||||
|
|
||||||
|
cat > "/etc/evobackup/${JAILNAME}.d/check_policy" <<OUT
|
||||||
|
CRITICAL=120
|
||||||
|
WARNING=96
|
||||||
|
OUT
|
||||||
|
# With custom values (5 days critical, 4 days warning),
|
||||||
|
# a 3 days old jail should be "ok"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "0" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Check WARNING for custom values" {
|
||||||
|
lastlog_date=$(date -d -3days --iso-8601=seconds)
|
||||||
|
touch --date="${lastlog_date}" "${JAILPATH}/var/log/lastlog"
|
||||||
|
|
||||||
|
cat > "/etc/evobackup/${JAILNAME}.d/check_policy" <<OUT
|
||||||
|
CRITICAL=96
|
||||||
|
WARNING=48
|
||||||
|
OUT
|
||||||
|
# With custom values (4 days critical, 3 days warning),
|
||||||
|
# a 3 days old jail should be "warning"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "1" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Check CRITICAL for custom values" {
|
||||||
|
lastlog_date=$(date -d -10days --iso-8601=seconds)
|
||||||
|
touch --date="${lastlog_date}" "${JAILPATH}/var/log/lastlog"
|
||||||
|
|
||||||
|
cat > "/etc/evobackup/${JAILNAME}.d/check_policy" <<OUT
|
||||||
|
CRITICAL=96
|
||||||
|
WARNING=48
|
||||||
|
OUT
|
||||||
|
# With custom values (4 days critical, 3 days warning),
|
||||||
|
# a 10 days old jail should be "critical"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "2" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Check OK for disabled WARNING" {
|
||||||
|
lastlog_date=$(date -d -2days --iso-8601=seconds)
|
||||||
|
touch --date="${lastlog_date}" "${JAILPATH}/var/log/lastlog"
|
||||||
|
|
||||||
|
cat > "/etc/evobackup/${JAILNAME}.d/check_policy" <<OUT
|
||||||
|
WARNING=0
|
||||||
|
OUT
|
||||||
|
# With custom values (warning disabled, default critical),
|
||||||
|
# a 2 days old jail should still be "ok"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "0" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Check WARNING for disabled CRITICAL" {
|
||||||
|
lastlog_date=$(date -d -3days --iso-8601=seconds)
|
||||||
|
touch --date="${lastlog_date}" "${JAILPATH}/var/log/lastlog"
|
||||||
|
|
||||||
|
cat > "/etc/evobackup/${JAILNAME}.d/check_policy" <<OUT
|
||||||
|
CRITICAL=0
|
||||||
|
OUT
|
||||||
|
# With custom values (critical disabled, default warning),
|
||||||
|
# a 3 days old jail should only be "warning"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "1" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Custom values are parsed with only integers after equal" {
|
||||||
|
lastlog_date=$(date -d -3days --iso-8601=seconds)
|
||||||
|
touch --date="${lastlog_date}" "${JAILPATH}/var/log/lastlog"
|
||||||
|
|
||||||
|
cat > "/etc/evobackup/${JAILNAME}.d/check_policy" <<OUT
|
||||||
|
CRITICAL=0 # foo
|
||||||
|
OUT
|
||||||
|
# With custom values (critical disabled, default warning),
|
||||||
|
# a 3 days old jail should only be "warning"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "1" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Commented custom values are ignored" {
|
||||||
|
lastlog_date=$(date -d -3days --iso-8601=seconds)
|
||||||
|
touch --date="${lastlog_date}" "${JAILPATH}/var/log/lastlog"
|
||||||
|
|
||||||
|
cat > "/etc/evobackup/${JAILNAME}.d/check_policy" <<OUT
|
||||||
|
# CRITICAL=0
|
||||||
|
OUT
|
||||||
|
# With commented custom values (critical disabled),
|
||||||
|
# a 3 days old jail should still be "critical"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "2" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Invalid custom values are ignored" {
|
||||||
|
lastlog_date=$(date -d -3days --iso-8601=seconds)
|
||||||
|
touch --date="${lastlog_date}" "${JAILPATH}/var/log/lastlog"
|
||||||
|
|
||||||
|
cat > "/etc/evobackup/${JAILNAME}.d/check_policy" <<OUT
|
||||||
|
CRITICAL=foo
|
||||||
|
OUT
|
||||||
|
# With commented custom values (critical disabled),
|
||||||
|
# a 3 days old jail should still be "critical"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "2" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Check WARNING if firewall rules are not sourced" {
|
||||||
|
firewall_rules_file="/etc/firewall.rc.jails"
|
||||||
|
set_variable "/etc/default/bkctld" "FIREWALL_RULES" "${firewall_rules_file}"
|
||||||
|
echo "" > "${firewall_rules_file}"
|
||||||
|
|
||||||
|
# Without sourcing
|
||||||
|
echo "" > "/etc/default/minifirewall"
|
||||||
|
# … the check should be "critical"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "1" "$status"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Check OK if firewall rules are sourced" {
|
||||||
|
firewall_rules_file="/etc/firewall.rc.jails"
|
||||||
|
set_variable "/etc/default/bkctld" "FIREWALL_RULES" "${firewall_rules_file}"
|
||||||
|
echo "" > "${firewall_rules_file}"
|
||||||
|
|
||||||
|
# Sourcing file with '.'
|
||||||
|
echo ". ${firewall_rules_file}" > "/etc/default/minifirewall"
|
||||||
|
# … the check should be "critical"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "0" "$status"
|
||||||
|
|
||||||
|
# Sourcing file with 'source'
|
||||||
|
echo "source ${firewall_rules_file}" > "/etc/default/minifirewall"
|
||||||
|
# … the check should be "critical"
|
||||||
|
run /usr/lib/bkctld/bkctld-check
|
||||||
|
assert_equal "0" "$status"
|
||||||
|
}
|
101
test/connectivity.bats
Normal file
101
test/connectivity.bats
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
#!/usr/bin/env bats
|
||||||
|
# shellcheck disable=SC1089,SC1083,SC2154
|
||||||
|
|
||||||
|
load test_helper
|
||||||
|
|
||||||
|
@test "Without SSH key" {
|
||||||
|
run cat "${JAILPATH}/root/.ssh/authorized_keys"
|
||||||
|
assert_equal "$output" ""
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "With SSH key" {
|
||||||
|
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"
|
||||||
|
assert_equal "$output" "$(cat ${keyfile})"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Custom port" {
|
||||||
|
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
||||||
|
/usr/lib/bkctld/bkctld-port "${JAILNAME}" "${PORT}"
|
||||||
|
# A jail should be accessible on the specified SSH port
|
||||||
|
run nc -vz 127.0.0.1 "${PORT}"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@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"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Single IP restriction" {
|
||||||
|
# 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"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Multiple IP restrictions" {
|
||||||
|
# When multiple IP are added for a jail
|
||||||
|
/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"
|
||||||
|
|
||||||
|
assert_line "root@10.0.0.1"
|
||||||
|
assert_line "root@10.0.0.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Removing IP restriction" {
|
||||||
|
# Add an IP
|
||||||
|
/usr/lib/bkctld/bkctld-ip "${JAILNAME}" "10.0.0.1"
|
||||||
|
# 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"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Missing AllowUsers" {
|
||||||
|
# Remove AllowUsers directive in SSH config
|
||||||
|
sed -i '/^AllowUsers/d' "${JAILPATH}/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
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "SSH connectivity" {
|
||||||
|
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
||||||
|
/usr/lib/bkctld/bkctld-port "${JAILNAME}" "${PORT}"
|
||||||
|
/usr/lib/bkctld/bkctld-key "${JAILNAME}" /root/bkctld.key.pub
|
||||||
|
|
||||||
|
ssh_options="-p ${PORT} -i /root/bkctld.key -oStrictHostKeyChecking=no"
|
||||||
|
|
||||||
|
# A started jail should be accessible via SSH
|
||||||
|
run ssh ${ssh_options} root@127.0.0.1 ls
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
/usr/lib/bkctld/bkctld-stop "${JAILNAME}"
|
||||||
|
# A stopped jail should not be accessible via SSH
|
||||||
|
run ssh ${ssh_options} root@127.0.0.1 ls
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Rsync connectivity" {
|
||||||
|
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
||||||
|
/usr/lib/bkctld/bkctld-port "${JAILNAME}" "${PORT}"
|
||||||
|
/usr/lib/bkctld/bkctld-key "${JAILNAME}" /root/bkctld.key.pub
|
||||||
|
|
||||||
|
ssh_options="-p ${PORT} -i /root/bkctld.key -oStrictHostKeyChecking=no"
|
||||||
|
# A started jail should be accessible via Rsync
|
||||||
|
run rsync -a -e "ssh ${ssh_options}" /tmp/ root@127.0.0.1:/var/backup/
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
/usr/lib/bkctld/bkctld-stop "${JAILNAME}"
|
||||||
|
# A stopped jail should not be accessible via Rsync
|
||||||
|
run rsync -a -e "${ssh_options}" /tmp/ root@127.0.0.1:/var/backup/
|
||||||
|
assert_failure
|
||||||
|
}
|
102
test/incs.bats
Normal file
102
test/incs.bats
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
#!/usr/bin/env bats
|
||||||
|
# shellcheck disable=SC1089,SC1083,SC2154
|
||||||
|
|
||||||
|
load test_helper
|
||||||
|
|
||||||
|
|
||||||
|
@test "Inc policy after jail init" {
|
||||||
|
# An incs_policy file should exist
|
||||||
|
run test -e "${CONFDIR}/${JAILNAME}.d/incs_policy"
|
||||||
|
[ "${status}" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Normal inc creation" {
|
||||||
|
/usr/lib/bkctld/bkctld-inc
|
||||||
|
|
||||||
|
if is_btrfs "/backup"; then
|
||||||
|
# On a btrfs filesystem, the inc should be a btrfs volume
|
||||||
|
run is_btrfs "${INCSPATH}/${INC_NAME}"
|
||||||
|
assert_success
|
||||||
|
else
|
||||||
|
# On an ext4 filesystem, the inc should be a regular directory
|
||||||
|
run test -d "${INCSPATH}/${INC_NAME}"
|
||||||
|
assert_success
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Normal inc creation (with old incs policy)" {
|
||||||
|
mv "${CONFDIR}/${JAILNAME}.d/incs_policy" "${CONFDIR}/${JAILNAME}"
|
||||||
|
|
||||||
|
/usr/lib/bkctld/bkctld-inc
|
||||||
|
|
||||||
|
if is_btrfs "/backup"; then
|
||||||
|
# On a btrfs filesystem, the inc should be a btrfs volume
|
||||||
|
run is_btrfs "${INCSPATH}/${INC_NAME}"
|
||||||
|
assert_success
|
||||||
|
else
|
||||||
|
# On an ext4 filesystem, the inc should be a regular directory
|
||||||
|
run test -d "${INCSPATH}/${INC_NAME}"
|
||||||
|
assert_success
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "No inc creation without inc policy" {
|
||||||
|
# Remove inc_policy
|
||||||
|
rm -f "${CONFDIR}/${JAILNAME}.d/incs_policy"
|
||||||
|
# … and old file
|
||||||
|
rm -f "${CONFDIR}/${JAILNAME}"
|
||||||
|
|
||||||
|
/usr/lib/bkctld/bkctld-inc
|
||||||
|
|
||||||
|
run test -d "${INCSPATH}/${INC_NAME}"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "No inc creation with LOCK" {
|
||||||
|
run rm -rf "${INCSPATH}"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
touch "/run/lock/bkctld/inc-${JAILNAME}-${INC_NAME}.lock"
|
||||||
|
|
||||||
|
/usr/lib/bkctld/bkctld-inc
|
||||||
|
|
||||||
|
run test -d "${INCSPATH}/${INC_NAME}"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Recent inc is kept after 'rm'" {
|
||||||
|
# Setup simple incs policy
|
||||||
|
echo "+%Y-%m-%d.-0day" > "${CONFDIR}/${JAILNAME}.d/incs_policy"
|
||||||
|
|
||||||
|
# Prepare an inc older than the policy
|
||||||
|
recent_inc_path="${INCSPATH}/${INC_NAME}"
|
||||||
|
|
||||||
|
# Create the inc, then run 'rm'
|
||||||
|
/usr/lib/bkctld/bkctld-inc
|
||||||
|
/usr/lib/bkctld/bkctld-rm
|
||||||
|
|
||||||
|
# Recent inc should be present
|
||||||
|
run test -d "${recent_inc_path}"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Older inc is removed by 'rm'" {
|
||||||
|
# Setup simple incs policy
|
||||||
|
echo "+%Y-%m-%d.-0day" > "${CONFDIR}/${JAILNAME}.d/incs_policy"
|
||||||
|
|
||||||
|
# Prepare an inc older than the policy
|
||||||
|
recent_inc_path="${INCSPATH}/${INC_NAME}"
|
||||||
|
older_inc_name=$(date -d -1days +"%Y-%m-%d-%H")
|
||||||
|
older_inc_path="${INCSPATH}/${older_inc_name}"
|
||||||
|
|
||||||
|
# Create the inc, rename it to make it older, then run 'rm'
|
||||||
|
/usr/lib/bkctld/bkctld-inc
|
||||||
|
mv "${recent_inc_path}" "${older_inc_path}"
|
||||||
|
/usr/lib/bkctld/bkctld-rm
|
||||||
|
|
||||||
|
# Older inc should be removed
|
||||||
|
run test -d "${older_inc_path}"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: add many tests for incs (creation and removal)
|
142
test/main.bats
142
test/main.bats
|
@ -1,133 +1,69 @@
|
||||||
#!/usr/bin/env bats
|
#!/usr/bin/env bats
|
||||||
|
# shellcheck disable=SC1089,SC1083,SC2154
|
||||||
|
|
||||||
setup() {
|
load test_helper
|
||||||
port=$(awk -v min=2222 -v max=2999 'BEGIN{srand(); print int(min+rand()*(max-min+1))}')
|
|
||||||
date=$(date +"%Y-%m-%d-%H")
|
|
||||||
inode=$(stat --format=%i /backup)
|
|
||||||
rm -f /root/bkctld.key* && ssh-keygen -t rsa -N "" -f /root/bkctld.key -q
|
|
||||||
. /usr/lib/bkctld/config
|
|
||||||
JAILNAME=$(tr -cd '[:alnum:]' < /dev/urandom | fold -w15 | head -n1)
|
|
||||||
}
|
|
||||||
|
|
||||||
teardown() {
|
@test "Filesystem type" {
|
||||||
/usr/lib/bkctld/bkctld-remove "${JAILNAME}" && rm -rf "${INCDIR}/*"
|
if is_btrfs "/backup"; then
|
||||||
}
|
# On a btrfs filesystem, the jail should be a btrfs volume
|
||||||
|
run is_btrfs "${JAILPATH}"
|
||||||
@test "init" {
|
assert_success
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
inode=$(stat --format=%i /backup)
|
|
||||||
if [ "${inode}" -eq 256 ]; then
|
|
||||||
run stat --format=%i "${JAILDIR}/${JAILNAME}"
|
|
||||||
[ "${output}" -eq 256 ]
|
|
||||||
else
|
else
|
||||||
run test -d "${JAILDIR}/${JAILNAME}"
|
# On an ext4 filesystem, the jail should be a regular directory
|
||||||
[ "${status}" -eq 0 ]
|
run test -d "${JAILPATH}"
|
||||||
|
assert_success
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "start" {
|
@test "A jail should be able to be started" {
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
||||||
pid=$(cat "${JAILDIR}/${JAILNAME}/${SSHD_PID}")
|
pid=$(cat "${JAILPATH}/${SSHD_PID}")
|
||||||
|
# A started jail should have an SSH pid file
|
||||||
run ps --pid "${pid}"
|
run ps --pid "${pid}"
|
||||||
[ "${status}" -eq 0 ]
|
assert_success
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "stop" {
|
@test "A jail should be able to be stopped" {
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
||||||
pid=$(cat "${JAILDIR}/${JAILNAME}/${SSHD_PID}")
|
pid=$(cat "${JAILPATH}/${SSHD_PID}")
|
||||||
/usr/lib/bkctld/bkctld-stop "${JAILNAME}"
|
/usr/lib/bkctld/bkctld-stop "${JAILNAME}"
|
||||||
|
# A stopped jail should not have an SSH pid file
|
||||||
run ps --pid "${pid}"
|
run ps --pid "${pid}"
|
||||||
[ "${status}" -ne 0 ]
|
assert_failure
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "reload" {
|
@test "A jail should be able to be reloaded" {
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
||||||
/usr/lib/bkctld/bkctld-reload "${JAILNAME}"
|
/usr/lib/bkctld/bkctld-reload "${JAILNAME}"
|
||||||
run grep "Received SIGHUP; restarting." "${JAILDIR}/${JAILNAME}/var/log/authlog"
|
# A reloaded jail should mention the restart in the authlog
|
||||||
[ "${status}" -eq 0 ]
|
run grep "Received SIGHUP; restarting." "${JAILPATH}/var/log/authlog"
|
||||||
|
assert_success
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "restart" {
|
@test "A jail should be able to be restarted" {
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
||||||
bpid=$(cat "${JAILDIR}/${JAILNAME}/${SSHD_PID}")
|
pid_before=$(cat "${JAILPATH}/${SSHD_PID}")
|
||||||
|
|
||||||
/usr/lib/bkctld/bkctld-restart "${JAILNAME}"
|
/usr/lib/bkctld/bkctld-restart "${JAILNAME}"
|
||||||
apid=$(cat "${JAILDIR}/${JAILNAME}/${SSHD_PID}")
|
pid_after=$(cat "${JAILPATH}/${SSHD_PID}")
|
||||||
[ "${bpid}" -ne "${apid}" ]
|
|
||||||
|
# A restarted jail should have a different pid
|
||||||
|
refute_equal "${pid_before}" "${pid_after}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "status" {
|
@test "Status should return information" {
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
run /usr/lib/bkctld/bkctld-status "${JAILNAME}"
|
run /usr/lib/bkctld/bkctld-status "${JAILNAME}"
|
||||||
[ "${status}" -eq 0 ]
|
assert_success
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "key" {
|
@test "ON/OFF status can be retrived with 'is-on'" {
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
||||||
/usr/lib/bkctld/bkctld-key "${JAILNAME}" /root/bkctld.key.pub
|
# A started jail should report to be ON
|
||||||
run cat "/backup/jails/${JAILNAME}/root/.ssh/authorized_keys"
|
run /usr/lib/bkctld/bkctld-is-on "${JAILNAME}"
|
||||||
[ "${status}" -eq 0 ]
|
assert_success
|
||||||
[ "${output}" = $(cat /root/bkctld.key.pub) ]
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "port" {
|
/usr/lib/bkctld/bkctld-stop "${JAILNAME}"
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
# A stopped jail should not report to be ON
|
||||||
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
run /usr/lib/bkctld/bkctld-is-on "${JAILNAME}"
|
||||||
/usr/lib/bkctld/bkctld-port "${JAILNAME}" "${port}"
|
assert_failure
|
||||||
run nc -vz 127.0.0.1 "${port}"
|
|
||||||
[ "${status}" -eq 0 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "inc" {
|
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
/usr/lib/bkctld/bkctld-inc
|
|
||||||
if [ "${inode}" -eq 256 ]; then
|
|
||||||
run stat --format=%i "${INCDIR}/${JAILNAME}/${date}"
|
|
||||||
[ "${output}" -eq 256 ]
|
|
||||||
else
|
|
||||||
run test -d "${INCDIR}/${JAILNAME}/${date}"
|
|
||||||
[ "${status}" -eq 0 ]
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "ssh" {
|
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
|
||||||
/usr/lib/bkctld/bkctld-port "${JAILNAME}" "${port}"
|
|
||||||
/usr/lib/bkctld/bkctld-key "${JAILNAME}" /root/bkctld.key.pub
|
|
||||||
run ssh -p "${port}" -i /root/bkctld.key -oStrictHostKeyChecking=no root@127.0.0.1 ls
|
|
||||||
[ "$status" -eq 0 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "rsync" {
|
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
/usr/lib/bkctld/bkctld-start "${JAILNAME}"
|
|
||||||
/usr/lib/bkctld/bkctld-port "${JAILNAME}" "${port}"
|
|
||||||
/usr/lib/bkctld/bkctld-key "${JAILNAME}" /root/bkctld.key.pub
|
|
||||||
run rsync -a -e "ssh -p ${port} -i /root/bkctld.key -oStrictHostKeyChecking=no" /tmp/ root@127.0.0.1:/var/backup/
|
|
||||||
[ "$status" -eq 0 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "check-ok" {
|
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
run /usr/lib/bkctld/bkctld-check
|
|
||||||
[ "$status" -eq 0 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "check-warning" {
|
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
touch --date="$(date -d -2days)" "/backup/jails/${JAILNAME}/var/log/lastlog"
|
|
||||||
run /usr/lib/bkctld/bkctld-check
|
|
||||||
[ "$status" -eq 1 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "check-critical" {
|
|
||||||
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
|
||||||
touch --date="$(date -d -3days)" "/backup/jails/${JAILNAME}/var/log/lastlog"
|
|
||||||
run /usr/lib/bkctld/bkctld-check
|
|
||||||
[ "$status" -eq 2 ]
|
|
||||||
}
|
}
|
||||||
|
|
131
test/test_helper.bash
Normal file
131
test/test_helper.bash
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
# shellcheck disable=SC2154 shell=bash
|
||||||
|
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
setup() {
|
||||||
|
. /usr/lib/bkctld/includes
|
||||||
|
|
||||||
|
rm -f /root/bkctld.key*
|
||||||
|
ssh-keygen -t rsa -N "" -f /root/bkctld.key -q
|
||||||
|
|
||||||
|
set_variable "/etc/default/bkctld" "BACKUP_DISK" "/dev/vdb"
|
||||||
|
|
||||||
|
JAILNAME=$(tr -cd '[:alnum:]' < /dev/urandom | fold -w15 | head -n1)
|
||||||
|
JAILPATH="/backup/jails/${JAILNAME}"
|
||||||
|
INCSPATH="/backup/incs/${JAILNAME}"
|
||||||
|
PORT=$(awk -v min=2222 -v max=2999 'BEGIN{srand(); print int(min+rand()*(max-min+1))}')
|
||||||
|
INC_NAME=$(date +"%Y-%m-%d-%H")
|
||||||
|
|
||||||
|
/usr/lib/bkctld/bkctld-init "${JAILNAME}"
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
remove_variable "/etc/default/bkctld" "BACKUP_DISK"
|
||||||
|
/usr/lib/bkctld/bkctld-remove "${JAILNAME}" && rm -rf "${INCSPATH}"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_variable() {
|
||||||
|
file=${1:?}
|
||||||
|
var_name=${2:?}
|
||||||
|
var_value=${3:-}
|
||||||
|
|
||||||
|
if grep -qE "^\s*${var_name}=" "${file}"; then
|
||||||
|
sed -i "s|^\s*${var_name}=.*|${var_name}=${var_value}|" "${file}"
|
||||||
|
else
|
||||||
|
echo "${var_name}=${var_value}" >> "${file}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
remove_variable() {
|
||||||
|
file=${1:?}
|
||||||
|
var_name=${2:?}
|
||||||
|
|
||||||
|
sed -i "s|^\s*${var_name}=.*|d" "${file}"
|
||||||
|
}
|
||||||
|
|
||||||
|
is_btrfs() {
|
||||||
|
path=$1
|
||||||
|
|
||||||
|
inode=$(stat --format=%i "${path}")
|
||||||
|
|
||||||
|
test ${inode} -eq 256
|
||||||
|
}
|
||||||
|
|
||||||
|
flunk() {
|
||||||
|
{ if [ "$#" -eq 0 ]; then cat -
|
||||||
|
else echo "$@"
|
||||||
|
fi
|
||||||
|
} >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_success() {
|
||||||
|
if [ "$status" -ne 0 ]; then
|
||||||
|
flunk "command failed with exit status $status"
|
||||||
|
elif [ "$#" -gt 0 ]; then
|
||||||
|
assert_output "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_failure() {
|
||||||
|
if [ "$status" -eq 0 ]; then
|
||||||
|
flunk "expected failed exit status"
|
||||||
|
elif [ "$#" -gt 0 ]; then
|
||||||
|
assert_output "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal() {
|
||||||
|
if [ "$1" != "$2" ]; then
|
||||||
|
{ echo "expected: $1"
|
||||||
|
echo "actual: $2"
|
||||||
|
} | flunk
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
refute_equal() {
|
||||||
|
if [ "$1" = "$2" ]; then
|
||||||
|
echo "expected $1 to not be equal to $2" | flunk
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_output() {
|
||||||
|
local expected
|
||||||
|
if [ $# -eq 0 ]; then expected="$(cat -)"
|
||||||
|
else expected="$1"
|
||||||
|
fi
|
||||||
|
assert_equal "$expected" "$output"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_line() {
|
||||||
|
if [ "$1" -ge 0 ] 2>/dev/null; then
|
||||||
|
assert_equal "$2" "${lines[$1]}"
|
||||||
|
else
|
||||||
|
local line
|
||||||
|
for line in "${lines[@]}"; do
|
||||||
|
if [ "$line" = "$1" ]; then return 0; fi
|
||||||
|
done
|
||||||
|
flunk "expected line \`$1'"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
refute_line() {
|
||||||
|
if [ "$1" -ge 0 ] 2>/dev/null; then
|
||||||
|
local num_lines="${#lines[@]}"
|
||||||
|
if [ "$1" -lt "$num_lines" ]; then
|
||||||
|
flunk "output has $num_lines lines"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
local line
|
||||||
|
for line in "${lines[@]}"; do
|
||||||
|
if [ "$line" = "$1" ]; then
|
||||||
|
flunk "expected to not find line \`$line'"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# shellcheck disable=SC2145
|
||||||
|
assert() {
|
||||||
|
if ! "$@"; then
|
||||||
|
flunk "failed: $@"
|
||||||
|
fi
|
||||||
|
}
|
|
@ -15,6 +15,9 @@
|
||||||
#
|
#
|
||||||
# /!\ DON'T FORGET TO SET "MAIL" and "SERVERS" VARIABLES
|
# /!\ DON'T FORGET TO SET "MAIL" and "SERVERS" VARIABLES
|
||||||
|
|
||||||
|
# Fail on unassigned variables
|
||||||
|
set -u
|
||||||
|
|
||||||
##### Configuration ###################################################
|
##### Configuration ###################################################
|
||||||
|
|
||||||
# email adress for notifications
|
# email adress for notifications
|
||||||
|
@ -95,7 +98,10 @@ pick_server() {
|
||||||
new_error="No more server available"
|
new_error="No more server available"
|
||||||
SERVERS_SSH_ERRORS=$(printf "%s\n%s" "${SERVERS_SSH_ERRORS}" "${new_error}" | sed -e '/^$/d')
|
SERVERS_SSH_ERRORS=$(printf "%s\n%s" "${SERVERS_SSH_ERRORS}" "${new_error}" | sed -e '/^$/d')
|
||||||
|
|
||||||
|
# Log errors to stderr
|
||||||
printf "%s\n" "${SERVERS_SSH_ERRORS}" >&2
|
printf "%s\n" "${SERVERS_SSH_ERRORS}" >&2
|
||||||
|
# Log errors to logfile
|
||||||
|
printf "%s\n" "${SERVERS_SSH_ERRORS}" >> $LOGFILE
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -154,6 +160,10 @@ if [ "${LOCAL_TASKS}" = "1" ]; then
|
||||||
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 -Q --opt --events --hex-blob --skip-comments \
|
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 -Q --opt --events --hex-blob --skip-comments \
|
||||||
# --fields-enclosed-by='\"' --fields-terminated-by=',' -T /home/mysqldump/$i $i; done
|
# --fields-enclosed-by='\"' --fields-terminated-by=',' -T /home/mysqldump/$i $i; done
|
||||||
|
|
||||||
|
## Dump all grants (requires 'percona-toolkit' package)
|
||||||
|
# mkdir -p -m 700 /home/mysqldump/
|
||||||
|
# pt-show-grants --flush --no-header > /home/mysqldump/all_grants.sql
|
||||||
|
|
||||||
## example with SQL dump (schema only, no data) for each databases
|
## example with SQL dump (schema only, no data) for each databases
|
||||||
# mkdir -p -m 700 /home/mysqldump/
|
# mkdir -p -m 700 /home/mysqldump/
|
||||||
# for i in $(mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 -e 'show databases' -s --skip-column-names \
|
# for i in $(mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 -e 'show databases' -s --skip-column-names \
|
||||||
|
@ -300,7 +310,7 @@ if [ "${LOCAL_TASKS}" = "1" ]; then
|
||||||
pkg_info -m > ${LOCAL_BACKUP_DIR}/packages
|
pkg_info -m > ${LOCAL_BACKUP_DIR}/packages
|
||||||
|
|
||||||
## Dump MBR / table partitions
|
## Dump MBR / table partitions
|
||||||
##disklabel sd0 > ${LOCAL_BACKUP_DIR}/partitions
|
disklabel sd0 > ${LOCAL_BACKUP_DIR}/partitions
|
||||||
|
|
||||||
## Dump pf infos
|
## Dump pf infos
|
||||||
pfctl -sa > ${LOCAL_BACKUP_DIR}/pfctl-sa.txt
|
pfctl -sa > ${LOCAL_BACKUP_DIR}/pfctl-sa.txt
|
||||||
|
@ -343,7 +353,7 @@ SSH_PORT=$(echo "${server}" | cut -d':' -f2)
|
||||||
HOSTNAME=$(hostname)
|
HOSTNAME=$(hostname)
|
||||||
|
|
||||||
if [ "${SYSTEM}" = "linux" ]; then
|
if [ "${SYSTEM}" = "linux" ]; then
|
||||||
rep="/bin /boot /lib /opt /sbin /usr"
|
rep="/bin /boot /lib /opt /sbin /usr /srv"
|
||||||
else
|
else
|
||||||
rep="/bsd /bin /sbin /usr"
|
rep="/bsd /bin /sbin /usr"
|
||||||
fi
|
fi
|
||||||
|
@ -391,7 +401,6 @@ if [ "${SYNC_TASKS}" = "1" ]; then
|
||||||
/root \
|
/root \
|
||||||
/var \
|
/var \
|
||||||
/home \
|
/home \
|
||||||
/srv \
|
|
||||||
-e "${RSH_COMMAND}" \
|
-e "${RSH_COMMAND}" \
|
||||||
"root@${SSH_SERVER}:/var/backup/" \
|
"root@${SSH_SERVER}:/var/backup/" \
|
||||||
| tail -30 >> $LOGFILE
|
| tail -30 >> $LOGFILE
|
||||||
|
|
Loading…
Reference in a new issue