Merge branch 'dev' into main

This commit is contained in:
Thomas von Dein
2020-12-04 20:35:11 +01:00
2 changed files with 774 additions and 149 deletions

339
README.md
View File

@@ -5,17 +5,156 @@ used to build, update, manage and run jails in a versioned environment.
Every jail consists of layers of directories mounted on top of each Every jail consists of layers of directories mounted on top of each
other using nullfs mounts. Some of them can be shared among jails, other using nullfs mounts. Some of them can be shared among jails,
some are versioned. some are versioned. By using shared and versioned layers of mounts it
is easy to update jails in a new version while the current version is
still running, you can switch back to an older version of a jail.
Most of the layers are mounted read-only for security reasons.
Let's take a look at the layers of a typical running jail built with `jaildk`:
```
1 /jail/base/12.1-RELEASE-p10 /jail/run/db read-only
2 /dev/md12 /jail/run/db/tmp
3 devfs /jail/run/db/dev
4 /jail/log/db-20201026 /jail/run/db/var/log
5 /jail/appl/db-20201026 /jail/run/db/usr/local read-only
6 /jail/etc/db/etc-20201026 /jail/run/db/etc read-only
7 /jail/etc/db/local-etc-20201026 /jail/run/db/usr/local/etc read-only
8 /jail/etc/db/cron-20201026 /jail/run/db/var/cron
9 /jail/home/db/root-20201026 /jail/run/db/root
10 /jail/data/db/mysql-20201026 /jail/run/db/usr/local/data/mysql
11 /backup/db /jail/run/db/var/backups
|
+--- root of the jail
```
As can be easily deduced this is a database jail with the following layers:
1. **base layer**: This is basically the same as a FreeBSD base, which
contains all biinaries, libraries and other files required to boot
up a FreeBSD system. Our base doesn't contain a kernel by default,
but you could add one, required if you want to use the ports
collection and compile `lsof` yourself.<br/>
This particular base is based on 12.1-RELEASE-p10, that is, I
created it while I had this release installed and running on the
host system.
2. **tmp layer**: Just a ramdisk for `/tmp`, the size can be tuned.
3. **dev layer**: Contains /dev/null and friends, required by every jail.
4. **log layer**: Here we have our first versioned layer for
`/var/log`. Notice how all other layers are using the same version,
this is done by purpose (but can be changed if you like). The
version is a jail variable (see below) which is being used for all
layers.
5. **application layer**: As you know if you're using FreeBSD, any
additional software, wether installed from a port or as package,
will be installed to `/usr/local`. In our case it contains the
mysql server software, bash and a couple of supporting
utilities. It is being mounted read-only, so no new software can be
installed in the running jail. This might sound annoying at first,
because you can't just install stuff inside the jail anytime you
like. But it forces you to work more disciplined. Once a jail has
been completely built you can be sure, all components match with
each other. Read below how to install or update software in a jail.
6. **/etc layer**: this just contains the normal etc, it is basically
a stripped copy of the host `/etc`. We do not use it at all inside
a jail, but it's required nontheless. There are some exceptions
however, like `/etc/resolv.conf`.
7. **/usr/local/etc layer**: This is the place we configure all
aspects of the jail, all configs reside here (like in our case the
mysql config). It is also being mounted read-only, just like
the etc layer.
8. **cron layer**: A writable mount for the crontabs of users inside
the jail. That way one can modify crontabs with `crontab
-e`. However, if you don't want or need this, just remove the layer
and add cronjobs to `/etc/crontab`.
9. **/root layer**: most of the administrative work inside a jail must
be done as the root user and it would be a pity not to have a
writable history. So, `/root` is mounted writable to add more
comfort.
10. **a data layer**: A versioned data layer which contains the binary
data of our mysql server. This is very jail specific and you have
to add such layers yourself. Variants of such a layer include the
document root of a webserver or the repositories of a git server.
11. **backup layer**: Another custom layer, here we've mounted a
global backup directory of our host which contains all backups.
All layers are configured in a `mount.conf` file specific for each
jail. The one for this jail looks like this:
```
base/$base $name nullfs ro
md $name/tmp mfs rw,nosuid,async 500m 1777
dev $name/dev devfs
log/$name-$version $name/var/log nullfs rw
appl/db-$version $name/usr/local nullfs ro
etc/$name/etc-$version $name/etc nullfs ro
etc/$name/local-etc-$version $name/usr/local/etc nullfs ro
etc/$name/cron-$version $name/var/cron nullfs rw
home/$name/root-$version $name/root nullfs rw
data/$name/mysql-$version $name/usr/local/data/mysql nullfs rw
/backup/db $name/var/backups nullfs rw
```
Now, as you can see, we're using variables here. Those are defined in
the `jail.conf` (not to be confused with `/etc/jail.conf` on the
host!):
```
name=db
version=20201026
base=12.1-RELEASE-p10
```
You might wonder how the other aspects of a jail are configured like
ip addresses, routing, jail parameters, sysctls etc. Well, that's
beyond the purpose of `jaildk`. You just use the standard FreeBSD
mechanism for these things, that is `/ect/rc.conf`, `/etc/jail.conf`,
`service jail ...`, `jexec`, etc. However, `jaildk` provides some
handy wrappers to make live easier.
For an overview of the provided commands, here's the usage screen:
```
Usage: /usr/local/bin/jaildk <command> <mode-args>
Building Jails:
base -b <name> [-w] - build a new base
build <jail> <mode> [-b <base>] [-v <version>] - install a build chroot of a jail
create - create a new jail from a template
clone -s <src> -d <dst> [-o <v>] [-n <v>] - clone an existing jail or jail version
fetch - fetch current port collection
Installing Jails:
install <jail> <mode> [-r function] - install a jail (prepare mounts, devfs etc)
uninstall <jail> [-w] - uninstall a jail
remove <jail> - remove a jail or a jail version
reinstall <jail> - stop, remove, install and start a jail
Maintaining Jails:
start <jail> - start a jail
stop <jail> - stop a jail
restart <jail> - restart a jail
status [<jail>] - display a jail's status
rc <jail> <mode> [-r <rc.d script>] - execute an rc-script inside a jail
Managing Jails:
login <jail> [<user>] - login into a jail
blogin <jail> - chroot into a build jail
Transferring Jails:
freeze <jail> [-a -b -v <version>] - freeze (build an image of) a jail
thaw <image> - thaw (install) an image of a jail
Getting help:
help <command> - request help on <command>
```
## Installation ## Installation
Execute the following command: Download the file `jaildk` or clone this repository to your FreeBSD server and execute the following command:
``` ```
./jaildk setup <directory> ./jaildk setup <directory>
``` ```
This will create the directory structure required for the tool install This will create the directory structure required for the tool itself,
the tool itself, create a template jail and build a base directory. create a template jail and build a base directory.
## Basic usage ## Basic usage
@@ -37,7 +176,7 @@ Create the file `/etc/jail.conf` with the following innitial contents:
sysvshm = "new"; sysvshm = "new";
host.hostname = $name; host.hostname = $name;
path = "/jail/run/$name"; path = "/jail/run/$name";
exec.prestart = "/jail/bin/jaildk install $name all start"; exec.prestart = "/jail/bin/jaildk install $name start";
exec.clean = "true"; exec.clean = "true";
} }
@@ -52,12 +191,12 @@ Refer to [jail(8)](https://www.freebsd.org/cgi/man.cgi?query=jail&sektion=8) for
Next add the following lines to your `/etc/rc.conf`: Next add the following lines to your `/etc/rc.conf`:
``` ```
ifconfig_em0_alias0="inet 144.76.67.168/32" ifconfig_em0_alias0="inet 172.16.1.1/32"
jail_enable="YES" jail_enable="YES"
``` ```
You may need to replace the interface name `em0` with the one in use on your system. You may need to replace the interface name `em0` with the one in use on your system.
You might need to restart the interface to apply the alias: `/etc/rc.d/netif restart`.
### Create the jail ### Create the jail
``` ```
@@ -135,7 +274,7 @@ A normal base directory cannot be used with the ports collection
because jaildk removes libraries and binaries for security reasons because jaildk removes libraries and binaries for security reasons
from normal bases. To create a build base, execute: from normal bases. To create a build base, execute:
`jaildk base 12-RELEASE-build rw` `jaildk base -b 12-RELEASE-build -w`
Next, add the following entry to the configuration of you jail. To Next, add the following entry to the configuration of you jail. To
stay with our example, edit `/jail/etc/myjail/jail.conf` and add: stay with our example, edit `/jail/etc/myjail/jail.conf` and add:
@@ -197,7 +336,7 @@ fcgiwrap is running as pid 37682.
### Login into the running jail for administration ### Login into the running jail for administration
``` ```
# jaildk jlogin myjail # jaildk login myjail
``` ```
You can use this to login into a database or execute commands inside the jail. You can use this to login into a database or execute commands inside the jail.
@@ -209,22 +348,22 @@ The very first thing to do is to update the host system using `freebsd-update`.
Next create a new base version: Next create a new base version:
``` ```
jaildk base `uname -r` jaildk base -b `uname -r`
``` ```
Now you can create clone of your jail with a new version: Now you can create clone of your jail with a new version:
``` ```
jaildk clone myjail myjail 20201106 20210422 jaildk clone -s myjail -d myjail -o 20201106 -n 20210422
``` ```
Mount the build chroot for the new version: Mount the build chroot for the new version:
``` ```
jaildk build myjail start `uname -r` 20210422 jaildk build myjail start -b `uname -r` -v 20210422
``` ```
And finally chroot into the new jail and update it: And finally chroot into the new jail and update it:
``` ```
blogin myjail jaildk blogin myjail
pkg update pkg update
... ...
``` ```
@@ -233,6 +372,178 @@ The last step is to remove the current running jail, change the version in `etc/
If there's anything wrong you can always go back to the previous version using the above steps. If there's anything wrong you can always go back to the previous version using the above steps.
## Advanced Features
Jaildk also offers some advanced features like automatically setting
up and deleting ipfw rules or freezing and thawing a jail (to make it
easily portable).
### Using the IPFW
To use the IPFW on your host you first have to enable ipfw in your
hosts rc.conf `firewall_enable="YES"`. You probably want to set the
default firewalling-type there aswell, check out the
[FreeBSD handbook](https://www.freebsd.org/doc/handbook/firewalls-ipfw.html)
for further information.
Once enabled you also need to start ipfw by executing the rc script:
`/etc/rc.d/ipfw start`.
Be aware that inter-jail communication is transfered via the loopback
interface (normally lo0) for which there is a high priority allow any
to any rule by default:
`allow ip from any to any via lo`
In order to control the inter-jail communication you have to delete
this rule first.
If an ipfw.conf exists for a jail (e.g. /jail/etc/myjail/ipfw.conf)
the rules inside that config file are added when starting, and deleted
when stopping the jail. E.g. allowing HTTP/HTTPS traffic for that
jail (webserver):
`allow tcp from any to $ip setup keep-state`
As demonstrated in the previous rule `$ip` is reserved and
automatically replaced with the jails own ip (as reported by
`jls`). The same applies to the ipv6 address which will be available
as variable `$ip6`. Also, all variables in the jails `jail.conf` can
be used.
In order to make these ipfw rules available on boot, you need to add
the following line to `/etc/jail.conf` in the section of the jail
which uses custom ipfw rules:
`exec.prestart = "/jail/bin/jaildk ipfw $name"`
Be aware, that the ipfw module will only be executed if the jail is
running so that we can properly determine the ip addresses of the
running jail. **Note**: this might change in the future.
### Using pf
Beside ipfw, Free supports
[pf](https://www.freebsd.org/doc/de_DE.ISO8859-1/books/handbook/firewalls-pf.html)
as well. You can use pf with `jaildk`. Unlike the ipfw module (see
above) it is a normal `install` module. That is it can be installed or
reloaded before the jail is running (i.e. like the mount module).
In order to use `pf` with a jail, enable and configure it according to
the FreeBSD handbook linked above. It is recommended to include
general block, scrup, state rules, communication to and fro localhost
etc and just leave everything which is related to your jail.
Just so that you know how such a global `/etc/pf.conf` file might look
like, here's a simple one:
```shell
# variables
ext = "em0"
me = "your ipv4 address here"
me5 = "your ipv6 address here/64"
loginports = "{ 22, 5222, 443 }"
icmp_types = "echoreq"
# tables. look at the contents of a table:
# pfctl -t bad_hosts -T show
# remove an entry from a table:
# pfctl -t bad_hosts -T delete $ip
table <bad_hosts> persist
# default policy
set block-policy drop
# optimize according to rfc's
set optimization aggressive
# normalisation
scrub in all
antispoof for $ext
# allow localhost
pass quick on $local
# additional default block rules w/ logging. to view the log:
# tcpdump -n -e -ttt -r /var/log/pflog
# to view live log:
# tcpdump -n -e -ttt -i pflog0
block in log on $ext
block in log on $ext inet6
# whoever makes it into those tables: you loose
block quick from <bad_hosts>
# allow outgoing established sessions
pass out keep state
pass out inet6 keep state
# allow troubleshooting
pass in on $ext inet proto icmp all icmp-type $icmp_types keep state
pass in on $ext inet proto udp from any to any port 33433 >< 33626 keep state
# allow all icmpv6
pass in quick inet6 proto icmp6 all keep state
# allow login but punish offenders
block quick from <bad*hosts>
pass in quick on $ext inet proto tcp from any to $me port $loginports \
flags S/SAFR keep state \
(max-src-conn-rate 10/60, \
overload <bad*hosts> flush global) label ServicesTCP
pass in quick on $ext inet6 proto tcp from any to $me6 port $loginports \
flags S/SAFR keep state \
(max-src-conn-rate 10/60, \
overload <bad_hosts> flush global) label ServicesTCP
```
Install the ruleset with `service pf start`.
Now that everything is prepared you can create a `/jail/etc/myjail/pf.conf` file for your
jail. Here's an example I use for a webserver jail, which includes a
git server:
```shell
ip = "jail ip4 addr"
ip6 = "jail ip6 addr"
loginports = "{ 22 }"
prodports = "{ 80, 443 }"
ext = "em0"
# dynamic block list
table <blocked>
# restrict foreigners
block quick from <blocked>
pass in quick on $ext inet proto tcp from any to $ip port $loginports \
flags S/SAFR keep state \
(max-src-conn-rate 10/60, \
overload <blocked> flush global) label ServicesTCP
# allow production traffic v4
pass in quick on $ext proto tcp from any to $ip port $prodports keep state
# allow production traffic v6
pass in quick inet6 proto tcp from any to $ip6 port $prodports keep state
```
That's it already. Now install the jail as usual. You can also install
the pf ruleset for the jail separately:
`jaildk install myjail start -r pf`
To take look at the rules, execute:
`jaildk install myjail status -r pf`
You can of course manipulate the ruleset manually. `jaildk` installs
rulesets into a jail specific anchor using the following naming
scheme: `/jail/<jail name>`. So, for example to view the rules, execute:
`pfctl -a /jail/myjail -s rules`
Manipulate a jail specific table:
`pfctl -a /jail/myjail -t blocked -T show`
## Getting help ## Getting help
@@ -251,6 +562,8 @@ This software is licensed under the BSD license.
T.v.Dein <tom AT vondein DOT org> T.v.Dein <tom AT vondein DOT org>
F.Sass (Culsu)
## Project homepage ## Project homepage
https://github.com/TLINDEN/jaildk https://github.com/TLINDEN/jaildk

582
jaildk Normal file → Executable file
View File

@@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
version=1.07 version=1.09
usage_jaildk() { usage_jaildk() {
beg=`tput -T ${TERM:-cons25} md` beg=`tput -T ${TERM:-cons25} md`
@@ -11,39 +11,52 @@ This is jaildk version $version, a jail management toolkit.
Usage: $0 <command> <mode-args> Usage: $0 <command> <mode-args>
${beg}Building Jails:${end} ${beg}Building Jails:${end}
base - build a new base base -b <name> [-w] - build a new base
build - install a build chroot of a jail build <jail> <mode> [-b <base>] [-v <version>] - install a build chroot of a jail
create - create a new jail from a template create - create a new jail from a template
clone - clone an existing jail or jail version clone -s <src> -d <dst> [-o <v>] [-n <v>] - clone an existing jail or jail version
fetch - fetch current port collection fetch - fetch current port collection
${beg}Installing Jails:${end} ${beg}Installing Jails:${end}
install - install a jail (prepare mounts, devfs etc) install <jail> <mode> [-r function] - install a jail (prepare mounts, devfs etc)
uninstall - uninstall a jail uninstall <jail> [-w] - uninstall a jail
remove - remove a jail or a jail version remove <jail> - remove a jail or a jail version
reinstall - stop, remove, install and start a jail reinstall <jail> - stop, remove, install and start a jail
${beg}Maintaining Jails:${end} ${beg}Maintaining Jails:${end}
start - start a jail start <jail> - start a jail
stop - stop a jail stop <jail> - stop a jail
restart - restart a jail restart <jail> - restart a jail
status - display a jail's status status [<jail>] - display a jail's status
rc - execute an rc-script inside a jail rc <jail> <mode> [-r <rc.d script>] - execute an rc-script inside a jail
ipfw <jail> <mode> - add or remove ipfw rules
${beg}Managing Jails:${end} ${beg}Managing Jails:${end}
login - login into a jail (also available as separate command) login <jail> [<user>] - login into a jail
blogin - chroot into a build jail (dito) blogin <jail> - chroot into a build jail
${beg}Transferring Jails:${end} ${beg}Transferring Jails:${end}
freeze - freeze (build an image of) a jail freeze <jail> [-a -b -v <version>] - freeze (build an image of) a jail
thaw - thaw (install) an image of a jail somewhere else thaw <image> - thaw (install) an image of a jail
Run the <command> without arguments to get usage help about the command. ${beg}Getting help:${end}
help <command> - request help on <command>
EOF EOF
) )
echo "$usage" echo "$usage"
exit 1 exit 1
}
usage_help() {
command=$1
usage="usage_${command}"
if ! type "$usage" > /dev/null 2>&1; then
die "Unknown command $command!"
else
$usage
fi
} }
ex() { ex() {
@@ -67,6 +80,11 @@ bold() {
echo -n "$BOLD_OFF" echo -n "$BOLD_OFF"
} }
fin() {
echo "$*" >&2
exit
}
die() { die() {
bold "$*" >&2 bold "$*" >&2
exit 1 exit 1
@@ -101,28 +119,100 @@ die_if_not_exist() {
fi fi
} }
parse_jail_conf() {
#
# just in case we want or have to fetch variables out of
# /etc/jail.conf, this is the way to go. Call it like this:
#
# ip=`parse_jail_conf $jail ip4.addr`
#
# Output may be empty, so check before using. Multiple variables
# of the same type (like multiple ip addresses) will be returned
# comma separated.
jail=$1
search=$2
JAIL=''
list=''
# fetch 20 lines after "^$jail {", ignore comments
egrep -A20 "^$jail" jail.conf | egrep -v "^ *#" | \
# turn each line into an evaluable shell expression \
sed -e 's/ *{//g' -e 's/}//g' -e 's/ *= */=/g' -e 's/;$//' | \
# ignore empty lines \
egrep -v '^$' | while read LINE; do
if echo "$LINE" | egrep -q "="; then
case $JAIL in
$jail)
var=`echo "$LINE" | cut -d= -f1`
opt=`echo "$LINE" | cut -d= -f2 | sed -e 's/^"//' -e 's/"$//'`
case $var in
$search)
if test -z "$list"; then
list="$opt"
else
list="$list,$opt"
fi
;;
esac
;;
*)
echo $list
return
;;
esac
else
case $LINE in
\*) JAIL=any;;
*) JAIL="$LINE";;
esac
fi
done
}
usage_build() {
fin "Usage: $0 build <jail> [<start|stop|status>] [-b <base>] [-v <version>]
Mount <jail> to $j/build read-writable for maintenance. Options:
-b <base> Use specified <base>. default: use configured base.
-v <version> Mount <version> of <jail>.
<mode> One of start, stop or status. default: start."
}
jaildk_build() { jaildk_build() {
jail=$1 jail=$1
mode=$2 mode=$2
base=$3 shift
version=$4 shift
load-jail-config $jail base=''
version=''
while getopts "b:v:" arg; do
case $arg in
b) base=${OPTARG};;
v) version=${OPTARG};;
*) usage_build;;
esac
done
if test -z "$mode"; then if test -z "$mode"; then
echo "Usage: $0 build <jail name> <start|stop|status> [<base>] [<version>]" mode=start
exit 1
fi fi
die_if_not_exist $jail $version
load-jail-config $jail
if test -n "$buildbase"; then if test -n "$buildbase"; then
base="$buildbase" base="$buildbase"
elif test -z "$base"; then elif test -z "$base"; then
# not configured, use default: latest # nothing configured, use default: latest
base=`ls $j/base | tail -1` base=`ls $j/base | tail -1`
fi fi
# install the jail to build/ # install the jail to build/
jaildk_install $jail all $mode rw $base $version jaildk_install $jail $mode -r all -w -b $base -v $version
case $mode in case $mode in
start) start)
@@ -133,12 +223,40 @@ jaildk_build() {
esac esac
} }
jaildk_rc_pf() {
jail=$1
mode=$2
conf=$j/etc/$jail/pf.conf
# FIXME: maybe we use parse_jail_conf() to fetch ip addresses,
# generate a config file containing pf macros, which the user
# needs to include in the jails pf.conf? On the other hand,
# there's not that much duplication in the config. So, maybe not.
if test -f $conf; then
case $mode in
start)
bold "Installing PF rules for jail $jail:"
pfctl -a /jail/$jail -f $conf -v
;;
status)
bold "PF rules for jail $jail:"
pfctl -a /jail/$jail -s rules -v
;;
stop)
bold "Removing PF rules for jail $jail:"
pfctl -a /jail/$jail -f $conf -v -F all
;;
esac
fi
}
jaildk_rc_mtree() { jaildk_rc_mtree() {
jail=$1 jail=$1
mode=$2 mode=$2
base=$3 base=$3
version=$4 version=$4
rw=$5 rw=$5
rcscript=mtree
if [ $mode = "start" ]; then if [ $mode = "start" ]; then
if test -n "$rw"; then if test -n "$rw"; then
@@ -342,46 +460,57 @@ jaildk_rc_mount() {
done done
} }
jaildk_install_usage() {
err "Usage: $0 install <jail> [[<rc.d-script>] <start|stop|restart|status>]"
err "If <rc.d-script> is 'all' every script will be executed in rc-order." usage_install() {
err "If <rc.d-script> is not specified, just execute all scripts with <start>." fin "Usage: $0 install <jail> [<mode>] [-r rc-function]
err "Available rc.d-scripts: $RCSCRIPTS_START" Install <jail> according to its config. Options:
exit 1 <mode> Mode can either be start, stop or status. default: start
-r <function> Only execute function with <mode> parameter. default: all.
Available rc.d-scripts: $RCSCRIPTS_START"
} }
jaildk_install() { jaildk_install() {
jail=$1 jail=$1
rcd=$2 mode=$2
mode=$3 shift
shift
rcd=''
# used by jaildk_build() only # options -b -w -v are undocumented, used by jaildk_build() only
rw=$4 rw=''
base=$5 base=''
version=$6 version=''
while getopts "r:b:v:w" arg; do
case $arg in
w) rw=1;;
b) base=${OPTARG};;
v) version=${OPTARG};;
r) rcd=${OPTARG};;
*) usage_install;;
esac
done
if test -z "$jail"; then if test -z "$jail"; then
jaildk_install_usage usage_install
fi
if test -z "$rcd"; then
# default just install all
mode=start
rcd=all
else
case $rcd in
start|stop|restart|status)
# shift args
mode=$rcd
rcd=all
;;
esac
fi fi
if test -z "$mode"; then if test -z "$mode"; then
jaildk_install_usage mode=start
fi fi
if test -z "$rcd"; then
# default just install everything
rcd=all
fi
case $mode in
start|stop|restart|status) :;;
*) usage_install;;
esac
die_if_not_exist $jail die_if_not_exist $jail
if test "$rcd" = "all"; then if test "$rcd" = "all"; then
@@ -410,14 +539,27 @@ jaildk_install() {
done done
} }
usage_uninstall() {
fin "Usage: $0 uninstall <jail> [-w]
Uninstall <jail>. Options:
-w Uninstall writable build chroot."
}
jaildk_uninstall() { jaildk_uninstall() {
# wrapper around _install # wrapper around _install
jail=$1 jail=$1
rw=$2 shift
rw=''
while getopts "w" arg; do
case $arg in
w) rw=1;;
*) usage_uninstall;;
esac
done
if test -z "$jail"; then if test -z "$jail"; then
err "Usage: $0 uninstall <jail> [<remove build>]" usage_uninstall
exit 1
fi fi
die_if_not_exist $jail die_if_not_exist $jail
@@ -426,18 +568,34 @@ jaildk_uninstall() {
die "Jail $jail($version) is still running, stop it before removing!" die "Jail $jail($version) is still running, stop it before removing!"
fi fi
jaildk_install $jail all stop $rw jaildk_install $jail stop -r all -w
}
usage_base() {
fin "Usage: $0 base -b <basename|basedir> [-w]
Build a base directory from bsd install media. Options:
-b <name> <name> can be the name of a base (e.g. 12.2-RELEASE)
or a directory where it shall be created
-w Create a writable base, including compiler and other
build stuff. Use this if you want to use the ports
collection."
} }
jaildk_base() { jaildk_base() {
base=$1 base=""
rw=$2 rw=""
while getopts "b:w" arg; do
case $arg in
w) rw=1;;
b) base=${OPTARG};;
*) usage_base;;
esac
done
if test -z "$base"; then if test -z "$base"; then
err "Usage: $0 base <basename|basedir> [<rw>]" usage_base
err "If the <rw> has been set, the base will not cleaned up"
err "and will contain compilers and other build stuff. Use"
err "this if you want to use the ports collection."
fi fi
removelist="tests removelist="tests
@@ -515,7 +673,7 @@ var/tmp"
exit 1 exit 1
else else
ex mkdir -p $basedir ex mkdir -p $basedir
bsdinstall jail $basedir bsdinstall jail $basedir || exit 1
if test -z "$rw"; then if test -z "$rw"; then
# run base # run base
@@ -565,21 +723,40 @@ clone() {
fi fi
} }
usage_clone() {
fin "Usage: $0 clone -s <jail> -d <jail> [-o <version>] [-n <version>]
-s <jail> Source jail to clone from
-d <jail> Destionation jail to create from source
-o <version> Old version
-n <version> New version
Hints:
- if no source version has been given, tha latest version will be used.
- if no new version has been given, source version will be used.
- if source and new jail are the same, both versions must be given
and a new version of the same jail will be created (update)"
}
jaildk_clone() { jaildk_clone() {
src=$1 src=''
new=$2 new=''
srcversion=$3 srcversion=''
newversion=$4 newversion=''
update="" update=''
while getopts "s:d:o:n:" arg; do
case $arg in
o) srcversion=${OPTARG};;
n) newversion=${OPTARG};;
s) src=${OPTARG};;
d) new=${OPTARG};;
*) usage_clone;;
esac
done
if test -z "$new"; then if test -z "$new"; then
echo "Usage: $0 clone <source jail> <new jail> [<source version> [<new version>]]" usage_clone
echo "Hints:"
echo "- if no source version has been given, tha latest version will be used."
echo "- if no new version has been given, source version will be used."
echo "- if source and new jail are the same, both versions must be given"
echo " and a new version of the same jail will be created (update)"
exit 1
fi fi
if test "$src" = "$new"; then if test "$src" = "$new"; then
@@ -620,7 +797,7 @@ jaildk_clone() {
clone $j/data/$src/www $j/data/$new/www clone $j/data/$src/www $j/data/$new/www
clone $j/data/$src/spool $j/data/$new/spool clone $j/data/$src/spool $j/data/$new/spool
ex cp -pRp $j/etc/$src/mount.conf $j/etc/$src/ports.conf $j/etc/$src/mtree.conf $j/etc/$new/ ex cp -pRp $j/etc/$src/mount.conf $j/etc/$src/ports.conf $j/etc/$src/mtree.conf $j/etc/$src/ipfw.conf $j/etc/$new/
echo "Creating $j/etc/$src/jail.conf" echo "Creating $j/etc/$src/jail.conf"
cat $j/etc/$src/jail.conf | egrep -v "^(name|version)=" > $j/etc/$new/jail.conf cat $j/etc/$src/jail.conf | egrep -v "^(name|version)=" > $j/etc/$new/jail.conf
@@ -656,17 +833,26 @@ jaildk_clone() {
echo echo
else else
. $j/etc/$src/jail.conf . $j/etc/$src/jail.conf
jail=$new
bold "To mount the build chroot of the new jail, execute:" bold "To mount the build chroot of the new jail, execute:"
echo "jaildk build $new start $base $newversion" echo "jaildk build $new start $base $newversion"
fi fi
} }
usage_create() {
fin "Usage: $0 create <jail>
Create a new jail from template."
}
jaildk_create() { jaildk_create() {
jail=$1 jail=$1
# $jail gets overwritten in jaildk_clone or some subcall to .template :-( ...
newjail=$jail
src=.template src=.template
if test -z "$jail"; then if test -z "$jail"; then
die "Usage: $0 create <jail>" usage_create
fi fi
. $j/etc/$src/jail.conf . $j/etc/$src/jail.conf
@@ -675,7 +861,14 @@ jaildk_create() {
mkdir -p $j/etc/$jail mkdir -p $j/etc/$jail
jaildk_clone $src $jail $srcversion $newversion jaildk_clone -s $src -d $jail -o $srcversion -n $newversion
# some perl magic to extract the hostname (if any) from /etc/jail.conf - and write it into the jails rc.conf
jailhostname=$(cat /etc/jail.conf | tr -d '\t\r\n ' | perl -ne '$_ =~ /.*'"$newjail"'(\{(?:\{.*\}|[^{])*\})|\w+/; print $1;' | grep -oE 'hostname=[^;]+' | cut -d= -f2)
if [ -n "$jailhostname" ]; then
echo "new name: $jailhostname"
echo "in path $j/etc/$jail/local-etc-$newversion/rc.conf"
sed -iE 's/^hostname.*$/hostname="'"$jailhostname"'"/' $j/etc/$newjail/local-etc-$newversion/rc.conf
fi
} }
remove() { remove() {
@@ -688,12 +881,25 @@ remove() {
fi fi
} }
usage_remove() {
fin "Usage: $0 remove <jail> [-v <version>]
Remove <jail> from disk."
}
jaildk_remove() { jaildk_remove() {
jail=$1 jail=$1
version=$2 shift
version=''
while getopts "v:" arg; do
case $arg in
v) version=${OPTARG};;
*) usage_remove;;
esac
done
if test -z "$jail"; then if test -z "$jail"; then
die "Usage: $0 remove <jail> [<version>]" usage_remove
fi fi
if jls | egrep -q "${jail}"; then if jls | egrep -q "${jail}"; then
@@ -726,19 +932,37 @@ jaildk_remove() {
} }
jaildk_jail_usage() { jaildk_jail_usage() {
die "Usage: $0 <start|stop|restart|status> <jail> | status" fin "Usage: $0 <start|stop|restart|status> <jail> | status"
}
usage_start() {
fin "Usage $0 start <jail>
Start <jail>."
}
usage_stop() {
fin "Usage $0 stop <jail>
Stop <jail>."
}
usage_restart() {
fin "Usage $0 restart <jail>
Restart <jail>."
}
usage_status() {
fin "Usage $0 status [<jail>]
Show status of <jail>. Without <jail>, show status of all jails."
} }
jaildk_jail() { jaildk_jail() {
mode=$1
jail=$2 jail=$2
mode=$1
if test -z "$mode"; then if test -z "$jail"; then
jaildk_jail_usage usage_$mode
fi elif test -z "$jail" -a $mode = "status"; then
if test -z "$jail" -a $mode = "status"; then
bold "Running jails:" bold "Running jails:"
bold " JID IP Address Hostname Path" bold " JID IP Address Hostname Path"
jls | grep -v JID jls | grep -v JID
@@ -754,8 +978,6 @@ jaildk_jail() {
jls | grep -v JID | awk '{print $3}' | while read J; do jls | grep -v JID | awk '{print $3}' | while read J; do
jaildk_rc $J status jaildk_rc $J status
done done
elif test -z "$jail"; then
jaildk_jail_usage
else else
bold "Jail $jail $mode:" bold "Jail $jail $mode:"
case $mode in case $mode in
@@ -765,6 +987,7 @@ jaildk_jail() {
;; ;;
*) *)
service jail $mode $jail service jail $mode $jail
jaildk_ipfw $jail $mode
;; ;;
esac esac
fi fi
@@ -783,35 +1006,33 @@ get_rc_scripts() {
done done
} }
jaildk_rc_usage() { usage_rc() {
err "Usage: $0 rc <jail> {<rc-script> [<mode>] | <mode>}" fin "Usage: $0 rc <jail> [<mode>] [-r <rc.d script]
err "If <rc-script> is all, execute <mode> for every rc script" Execute an rc.d script inside <jail> with parameter <mode>. Options:
err "<mode> must be a parameter of <rc-script>" -r <rc.d script> Execute <rc.d script>. default: execute all enabled scripts."
err "if only <mode> has been given, execute all scripts"
exit 1
} }
jaildk_rc() { jaildk_rc() {
jail=$1 jail=$1
rc=$2 mode=$1
mode=$3 shift
shift
rc=''
while getopts "r:" arg; do
case $arg in
r) rcd=${OPTARG};;
*) usage_rc;;
esac
done
if test -z "$rc"; then if test -z "$rc"; then
jaildk_rc_usage rc='all'
fi fi
if test -z "$mode"; then if test -z "$jail" -o -z "$mode"; then
# shift args usage_rc
case $rc in
start|stop|restart|status)
# shift args
mode=$rc
rc=all
;;
*)
jaildk_rc_usage
;;
esac
fi fi
if ! jls | egrep -q "${jail}"; then if ! jls | egrep -q "${jail}"; then
@@ -840,6 +1061,14 @@ jaildk_rc() {
fi fi
} }
usage_blogin() {
err "Usage: $file <jail>
Chroot into a build jail.
Mounted build chroot's:"
mount|egrep "base.*build" | awk '{print $3}' | cut -d/ -f 4
exit 1
}
jaildk_blogin() { jaildk_blogin() {
jail=$1 jail=$1
@@ -851,10 +1080,7 @@ jaildk_blogin() {
else else
file="$0" file="$0"
fi fi
echo "Usage: $file <jail-name|jail-domain|jail-ip> [<user>]" usage_blogin
echo "mounted build jails:"
mount|egrep "base.*build" | awk '{print $3}' | cut -d/ -f 4
exit
fi fi
chroot="$j/build/$jail" chroot="$j/build/$jail"
@@ -878,6 +1104,16 @@ jaildk_blogin() {
env - HOME=$home TERM=$term SHELL=$shell PATH=$path chroot $chroot $shell env - HOME=$home TERM=$term SHELL=$shell PATH=$path chroot $chroot $shell
} }
usage_login() {
err "Usage: $file <jail-name|jail-domain|jail-ip> [<user>]
Login into a jail by name, ip or domain. If <user> has not been
specified, login as root.
Available jails:"
jls
exit 1
}
jaildk_login() { jaildk_login() {
jail=$1 jail=$1
user=$2 user=$2
@@ -891,10 +1127,7 @@ jaildk_login() {
else else
file="$0" file="$0"
fi fi
echo "Usage: $file <jail-name|jail-domain|jail-ip> [<user>]" usage_login
echo "available jails:"
jls
exit
fi fi
jid="" jid=""
@@ -932,10 +1165,19 @@ jaildk_login() {
env - JAIL=$jail HOME=$home TERM=$term SHELL=$shell PATH=$path $jexec -U $user $jid $shell env - JAIL=$jail HOME=$home TERM=$term SHELL=$shell PATH=$path $jexec -U $user $jid $shell
} }
usage_reinstall() {
fin "Usage: $0 reinstall <jail>
Stop, uninstall, install and start <jail>.
"
}
jaildk_reinstall() { jaildk_reinstall() {
jail=$1 jail=$1
if test -z "$jail"; then
usage_reinstall
fi
die_if_not_exist $jail die_if_not_exist $jail
if jls | egrep -q "${jail}"; then if jls | egrep -q "${jail}"; then
@@ -960,7 +1202,7 @@ jaildk_setup() {
j=$1 j=$1
if test -z "$j"; then if test -z "$j"; then
die "Usage: $0 setup <base dir for jail environment>" fin "Usage: $0 setup <base dir for jail environment>"
fi fi
bold "preparing directories" bold "preparing directories"
@@ -1005,8 +1247,10 @@ home/$name/root-$version $name/root nullfs rw' >
bold "creating template config $j/etc/.template/ports.conf" bold "creating template config $j/etc/.template/ports.conf"
(echo bash; echo ca_root_nss) > $j/etc/.template/ports.conf (echo bash; echo ca_root_nss) > $j/etc/.template/ports.conf
bold "creating template config $j/etc/.template/ipfw.conf"
touch $j/etc/.template/ipfw.conf
bold "creating template config $j/etc/.template/mtree.conf" bold "creating template config $j/etc/.template/mtree.conf"
# touch $j/etc/.template/mtree.conf
echo '/set type=dir uid=0 gid=0 mode=01777 echo '/set type=dir uid=0 gid=0 mode=01777
. type=dir mode=0755 . type=dir mode=0755
tmp tmp
@@ -1063,7 +1307,7 @@ endif
read yesno read yesno
case $yesno in case $yesno in
y|Y|yes|YES) y|Y|yes|YES)
jaildk_base $j/base/$os jaildk_base -b $j/base/$os
;; ;;
esac esac
} }
@@ -1092,7 +1336,7 @@ jaildk_fetch_ports() {
ex rm -rf $j/ports/tmp/ports* ex rm -rf $j/ports/tmp/ports*
} }
freeze_usage() { usage_freeze() {
echo "Usage: $0 freeze <jail> [options] echo "Usage: $0 freeze <jail> [options]
Options: Options:
-v <version> freeze <version> of <jail> -v <version> freeze <version> of <jail>
@@ -1123,12 +1367,12 @@ jaildk_freeze() {
a) ADDAPPL=1;; a) ADDAPPL=1;;
b) ADDBASE=1;; b) ADDBASE=1;;
v) VERSION=${OPTARG};; v) VERSION=${OPTARG};;
*) freeze_usage;; *) usage_freeze;;
esac esac
done done
if test -z "$jail"; then if test -z "$jail"; then
freeze_usage usage_freeze
fi fi
die_if_not_exist $jail "Jail to freeze" $VERSION die_if_not_exist $jail "Jail to freeze" $VERSION
@@ -1231,9 +1475,12 @@ thaw_tarball() {
ex rm -f $srcdir/$tarball ex rm -f $srcdir/$tarball
} }
usage_thaw() {
fin "Usage: $0 thaw <image>"
}
jaildk_thaw() { jaildk_thaw() {
image=$1 image=$1
J=$2 # just for testing
if test -n "$J"; then if test -n "$J"; then
j=$J j=$J
@@ -1243,8 +1490,7 @@ jaildk_thaw() {
version=$(echo $image | cut -d\- -f3 | cut -d\. -f1) version=$(echo $image | cut -d\- -f3 | cut -d\. -f1)
if ! test -n "$version" -o -n "$jail"; then if ! test -n "$version" -o -n "$jail"; then
err "Usage: $0 thaw <image>" usage_thaw
die "Image filename pattern: <host>-<jail>-<version>.tgz"
fi fi
if test -d $j/etc/$jail/etc-$version; then if test -d $j/etc/$jail/etc-$version; then
@@ -1301,6 +1547,69 @@ jaildk_thaw() {
bold "Done. Thawed jail $jail $version from $image." bold "Done. Thawed jail $jail $version from $image."
} }
usage_ipfw() {
echo "Usage: $0 ipfw <jail> <mode>
[Un]install ipfw rules. <mode> can be start or stop.
The jail needs to have a ipfw.conf file, containing
ipfw rules. You can use variables like \$ip and \$ip6
and you need to omit the 'ipfw add' of the command."
exit 1
}
jaildk_ipfw() {
jail=$1
mode=$2
if test -z "$mode"; then
usage_ipfw
fi
if test -f "$j/etc/$jail/ipfw.conf"; then
echo
bold "Managing IPFW Rules..."
case $mode in
start)
jaildk_ipfw_delete $jail "y"
jaildk_ipfw_add $jail
;;
stop)
jaildk_ipfw_delete $jail
;;
esac
bold "... done"
echo
fi
}
jaildk_ipfw_add() {
jail=$1
# support jail variables as well
load-jail-config $jail
# Getting current jails IP..
ip=`jls -n -j $jail ip4.addr | cut -d= -f2`
if test -z "$ip"; then
die "Jail $jail doesn't have an ipv4 address!"
fi
ip6=`jls -n -j $jail ip6.addr | cut -d= -f2` # optional, no checks
# Adding rules
egrep "^[a-z]" $j/etc/$jail/ipfw.conf | while read LINE; do
rule=$(eval echo "ipfw add $LINE // $jail")
echo $rule
$rule
done
}
jaildk_ipfw_delete() {
jail=$1
noout=$2
# Deleting rules
ipfw show | grep -E "// $jail\$" | while read rule; do [ -z "$2" ] && bold "Deleting rule $rule"; sh -c "ipfw delete $(echo $rule| awk '{print $1}')"; done
}
########################## ##########################
# #
@@ -1310,8 +1619,8 @@ jaildk_thaw() {
JAILDIR=/jail JAILDIR=/jail
# install modules # install modules
RCSCRIPTS_START="jaildk_rc_mount jaildk_rc_rcoff jaildk_rc_ports jaildk_rc_mtree" RCSCRIPTS_START="jaildk_rc_mount jaildk_rc_rcoff jaildk_rc_ports jaildk_rc_mtree jaildk_rc_pf"
RCSCRIPTS_STOP="jaildk_rc_rcoff jaildk_rc_mount jaildk_rc_ports" RCSCRIPTS_STOP="jaildk_rc_pf jaildk_rc_rcoff jaildk_rc_mount jaildk_rc_ports"
# globals # globals
j=$JAILDIR j=$JAILDIR
@@ -1328,9 +1637,12 @@ case $runner in
start|stop|status|restart) start|stop|status|restart)
jaildk_jail $runner $* jaildk_jail $runner $*
;; ;;
setup|reinstall|install|uninstall|build|blogin|login|clone|create|remove|rc|base|fetch|freeze|thaw) setup|reinstall|install|uninstall|build|blogin|login|clone|create|remove|rc|base|fetch|freeze|thaw|ipfw)
jaildk_$runner $* jaildk_$runner $*
;; ;;
help)
usage_help $*
;;
*) *)
usage_jaildk $* usage_jaildk $*
;; ;;