First chunk of ZFS support in ezjail.

ezjail is now capable of managing jails in seperate ZFS filesystems and to manage basejail and newjail in seperate ZFS filesystems too.

It is possible to mix non-ZFS jails with ZFS jails as well as using ZFS jails with basejail/newjail in a non-ZFS filesystem.

To create a zfs jail you need an existing ZFS pool, ZFS needs to be enabled in /etc/rc.conf and you have to set at least ezjail_jailzfs in ezjail.conf. To let ezjail manage basejail/newjail in ZFS filesystems to, you have to enable ezjail_use_zfs in ezjail.conf.

To use ZFS support in ezjail, you have to use at least FreeBSD 7-STABLE form after the commit of ZFS version 13 (commited Wed May 20 23:34:59 2009 UTC, http://svn.freebsd.org/viewvc/base?view=revision&revision=192498) of FreeBSD 8-CURRENT. Prior versions of ZFS are _not_ supported.

Creating a ZFS based jail is as easy as using 'ezjail-admin create -c zfs <jailname> <jailip>'.

Using zfs send/receive for archiving is not yet implemented.

Converting non-ZFS basejail/newjail setups into ZFS setups is not handled by ezjail, converting non-ZFS jails into ZFS jails is not yet handled by ezjail but will be possible in the future.

WARNING: ZFS is considered to be an experimental feature in FreeBSD. ZFS support in ezjail is work in progress.
This commit is contained in:
cryx 2009-05-23 13:09:53 +00:00
parent ac8696b602
commit 095380a8d0
2 changed files with 118 additions and 18 deletions

View File

@ -39,7 +39,7 @@ case `uname -p` in amd64) ezjail_dirlist="${ezjail_dirlist} usr/lib32"; ezjail_b
# Synopsis messages
ezjail_usage_ezjailadmin="${ezjail_admin} v3.0\nUsage: ${ezjail_admin} [archive|config|console|create|delete|install|list|restore|update] {params}"
ezjail_usage_install="Usage: ${ezjail_admin} install [-mMpPsS] [-h host] [-r release]"
ezjail_usage_create="Usage: ${ezjail_admin} create [-xbi] [-f flavour] [-r jailroot] [-s size] [-c bde|eli] [-C args] [-a archive] jailname jailip"
ezjail_usage_create="Usage: ${ezjail_admin} create [-xbi] [-f flavour] [-r jailroot] [-s size] [-c bde|eli|zfs] [-C args] [-a archive] jailname jailip"
ezjail_usage_delete="Usage: ${ezjail_admin} delete [-w] jailname"
ezjail_usage_update="Usage: ${ezjail_admin} update [-s sourcetree] [-p] (-b|-i|-u|-P)"
ezjail_usage_config="Usage: ${ezjail_admin} config [-r run|norun] [-n newname] [-i attach|detach|fsck] jailname"
@ -200,6 +200,13 @@ ezjail_splitworld() {
# This mkdir is important, since cpio will create intermediate
# directories with permission 0700 which is bad
if [ "${ezjail_use_zfs}" = "YES" ]; then
echo "ZFS: create the basejail"
echo "/sbin/zfs create -p -o mountpoint=${ezjail_jaildir} ${ezjail_zfs_properties} ${ezjail_jailzfs}"
/sbin/zfs create -p -o mountpoint=${ezjail_jaildir} ${ezjail_zfs_properties} ${ezjail_jailzfs}
/sbin/zfs create -p ${ezjail_jailzfs}/basejail
/sbin/zfs snapshot ${ezjail_jailzfs}/basejail@`date -v -7d +"%C%y%m%d_%H:%M:%S"`
fi
mkdir -p "${ezjail_jailbase}/usr"
for dir in ${ezjail_dirlist}; do
find ${dir} | cpio -d -p -v "${ezjail_jailbase}" || exerr "Error: Installation of ${dir} failed."
@ -208,8 +215,15 @@ ezjail_splitworld() {
mkdir basejail
# Try to remove the old template jail
[ -d "${ezjail_jailtemplate}" ] && chflags -R noschg "${ezjail_jailtemplate}" && rm -rf "${ezjail_jailtemplate}"
mv "${ezjail_jailfull}" "${ezjail_jailtemplate}"
if [ "${ezjail_use_zfs}" = "YES" ]; then
echo "ZFS: cleanup old template jail"
[ -d "${ezjail_jailtemplate}" ] && zfs destroy -R ${ezjail_jailzfs}/newjail && rm -rf "${ezjail_jailtemplate}"
cd ${ezjail_jaildir}
zfs rename ${ezjail_jailzfs}/fulljail ${ezjail_jailzfs}/newjail
else
[ -d "${ezjail_jailtemplate}" ] && chflags -R noschg "${ezjail_jailtemplate}" && rm -rf "${ezjail_jailtemplate}"
mv "${ezjail_jailfull}" "${ezjail_jailtemplate}"
fi
# If the default flavour example has not yet been copied, do it now
[ -d "${ezjail_flavours}/default" ] || mkdir -p "${ezjail_flavours}" && cp -p -R "${ezjail_examples}/default" "${ezjail_flavours}"
@ -313,6 +327,20 @@ parse_gbde_attach_args () {
return ${_exit}
}
check_for_zfs () {
. "/etc/rc.conf"
if [ "${ezjail_use_zfs}" = "YES" ] && [ "${zfs_enable}" != "YES" ]; then
echo "You have to enable ZFS in /etc/rc.conf"
exit
fi
_zpoolstatus=`/sbin/zpool list -H -o health ${ezjail_jailzfs%%/*} 2> /dev/null`
if [ ! "${_zpoolstatus}" = "ONLINE" ]; then
echo "Your zpool does not exist or is not online."
exit
fi
}
#############################
# End of function definitions
#
@ -320,6 +348,8 @@ parse_gbde_attach_args () {
# check for command
[ $# -gt 0 ] || exerr ${ezjail_usage_ezjailadmin}
check_for_zfs
case "$1" in
######################## ezjail-admin CREATE ########################
create)
@ -343,12 +373,18 @@ create)
# we need at least a name and an ip for new jail
[ "${ezjail_name}" -a "${ezjail_ip}" -a $# -eq 2 ] || exerr ${ezjail_usage_create}
# show the user the type of image used
echo "TYPE: $ezjail_imagetype"
# check for sanity of settings concerning the image feature
[ -z "${ezjail_imagetype}" -o "${ezjail_exists}" -o "${ezjail_imagesize}" ] || exerr "Error: Image jails need an image size."
if [ "${ezjail_imagetype}" != "zfs" ]; then
[ -z "${ezjail_imagetype}" -o "${ezjail_exists}" -o "${ezjail_imagesize}" ] || exerr "Error: Image jails need an image size."
fi
# check for a sane image type
case ${ezjail_imagetype} in ""|simple|bde|eli) ;; *) exerr ${ezjail_usage_create};; esac
case ${ezjail_imagetype} in ""|simple|bde|eli|zfs) ;; *) exerr ${ezjail_usage_create};; esac
# check for a sane image size and split it up in blocks
if [ "${ezjail_imagesize}" ]; then
@ -422,13 +458,16 @@ create)
# Location of our image file
ezjail_image="${ezjail_image}.img"
# zfs does not use image files
[ "${ezjail_imagetype}" = "zfs" ] && unset ezjail_image
# Prepare crypto jail so that an attacker cannot guess which blocks
# have been written
case ${ezjail_imagetype} in bde|eli) ezjail_sourcedevice="/dev/random";; simple) ezjail_sourcedevice="/dev/zero";; esac
# If NOT exist, create image
if [ -z "${ezjail_exists}" ]; then
# If NOT exist and imagetype not ZFS, create image
if [ -z "${ezjail_exists}" ] && [ ! ${ezjail_imagetype} = "zfs" ]; then
[ -e "${ezjail_image}" ] && exerr "Error: A file exists at ${ezjail_image}.\n Won't overwrite an existing image."
# Now create jail disc image
@ -475,9 +514,18 @@ create)
simple)
ezjail_device=${ezjail_imagedevice}
;;
zfs)
echo "ZFS: create the jail filesystem"
if [ ${ezjail_imagesize} ]; then
ezjail_zfs_jail_properies="-o quota=${ezjail_imagesize} -o compression=lzjb"
fi
[ -d "${ezjail_jaildir}/${ezjail_hostname}" ] && exerr "Error: Could not create jail root mount point ${ezjail_rootdir}"
/sbin/zfs create -p -o mountpoint=${ezjail_rootdir} ${ezjail_zfs_jail_properies} ${ezjail_jailzfs}/${ezjail_hostname}
;;
esac
if [ -z "${ezjail_exists}" ]; then
if [ -z "${ezjail_exists}" ] && [ ! ${ezjail_imagetype} = "zfs" ]; then
# Format memory image
newfs -U "/dev/${ezjail_device}" || detach_images || exerr "Error: Could not newfs /dev/${ezjail_device}."
# Create mount point and mount
@ -500,7 +548,16 @@ create)
[ $? -eq 0 ] || detach_images || exerr "Error: Could not extract archive from ${ezjail_fromarchive}."
elif [ -z "${ezjail_exists}" ]; then
# now take a copy of our template jail
mkdir -p "${ezjail_rootdir}" && cd "${ezjail_jailtemplate}" && find . | cpio -p -v "${ezjail_rootdir}" > /dev/null
if [ "${ezjail_imagetype}" = "zfs" ] && [ "${ezjail_use_zfs}" = "YES" ]; then
# create ZFS filesystem first when using ZFS
/sbin/zfs snapshot ${ezjail_jailzfs}/newjail@_createnewjailtmp
/sbin/zfs send ${ezjail_jailzfs}/newjail@_createnewjailtmp | zfs receive -F ${ezjail_jailzfs}/${ezjail_hostname}
/sbin/zfs destroy ${ezjail_jailzfs}/${ezjail_hostname}@_createnewjailtmp
/sbin/zfs destroy ${ezjail_jailzfs}/newjail@_createnewjailtmp
else
mkdir -p "${ezjail_rootdir}" && cd "${ezjail_jailtemplate}" && find . | cpio -p -v "${ezjail_rootdir}" > /dev/null
fi
[ $? -eq 0 ] || detach_images || exerr "Error: Could not copy template jail."
fi
@ -510,8 +567,9 @@ create)
# if the automount feature is not disabled, this fstab entry for new jail
# will be obeyed
echo -n > /etc/fstab.${ezjail_safename}
[ "${ezjail_imagetype}" ] && \
echo ${ezjail_devicelink} ${ezjail_rootdir} ufs rw 0 0 >> "/etc/fstab.${ezjail_safename}"
if [ "${ezjail_imagetype}" ] && [ ! "${ezjail_imagetype}" = "zfs" ] ; then
echo ${ezjail_devicelink} ${ezjail_rootdir} ufs rw 0 0 >> "/etc/fstab.${ezjail_safename}"
fi
echo ${ezjail_jailbase} ${ezjail_rootdir}/basejail nullfs ro 0 0 >> "/etc/fstab.${ezjail_safename}"
# now, where everything seems to have gone right, create control file in
@ -576,7 +634,7 @@ create)
[ $? -eq 0 ] && echo -e "Warning: Some services already seem to be listening on all IP, (including ${ezjail_ip})\n This may cause some confusion, here they are:\n${ezjail_listener}"
IFS=${TIFS}
[ "${ezjail_imagetype}" ] && echo "Note: To administrate your image jail, attach it using the '${ezjail_admin} config -i attach ${ezjail_hostname}' command."
[ "${ezjail_imagetype}" ] && [ "${ezjail_imagetype}" != "zfs" ] && echo "Note: To administrate your image jail, attach it using the '${ezjail_admin} config -i attach ${ezjail_hostname}' command."
;;
######################## ezjail-admin DELETE ########################
delete)
@ -626,7 +684,15 @@ delete)
# if wiping the jail was requested, remove it
if [ "${ezjail_wipeme}" ]; then
[ "${ezjail_image}" ] && rm -f "${ezjail_image}" "${ezjail_image%.img}.device"
case ${ezjail_imagetype} in
simple|bde|eli)
[ "${ezjail_image}" ] && rm -f "${ezjail_image}" "${ezjail_image%.img}.device"
;;
zfs)
echo "ZFS: delete the jails ZFS"
/sbin/zfs destroy -r ${ezjail_jailzfs}/${ezjail_hostname}
;;
esac
rm -rf "${ezjail_rootdir}"
fi
@ -674,6 +740,10 @@ setup|update)
# Check if some action was requested
[ "${ezjail_installaction}" ] || exerr "Error: No install action has been chosen.\n Please note that ezjails behaviour changed. Rebuilding the world no longer is default.\n Run '${ezjail_admin} update -b' to build and install a world from source or '${ezjail_admin} update -i' to install an already built world."
if [ "${ezjail_use_zfs}" = "YES" ]; then
zfs create -p -o mountpoint=${ezjail_jaildir} ${ezjail_jailzfs}
fi
if [ "${ezjail_installaction}" = "none" ]; then
# check, whether ezjail has been setup correctly. existence of
# ezjail_jailbase is our indicator
@ -683,6 +753,9 @@ setup|update)
# If ran from cron be kind to freebsds update servers and sleep first
[ -z "$TERM" -o "$TERM" = "dumb" ] && sleep $(( ${RANDOM} % 3600 ))
if [ "${ezjail_use_zfs}" = "YES" ]; then
zfs snapshot ${ezjail_jailzfs}/basejail@`date -v -7d +"%C%y%m%d_%H:%M:%S"`
fi
freebsd-update -b ${ezjail_jailbase} fetch install
else
# Bump the user for some of the most common errors
@ -692,8 +765,14 @@ setup|update)
# Normally fulljail should be renamed by past ezjail-admin commands.
# However those may have failed
[ -d "${ezjail_jailfull}" ] && chflags -R noschg "${ezjail_jailfull}" && rm -rf "${ezjail_jailfull}"
mkdir -p "${ezjail_jailfull}" || exerr "Error: Cannot create temporary Jail directory."
if [ "${ezjail_use_zfs}" = "YES" ]; then
echo "ZFS: manage basejail and newjail"
[ -d "${ezjail_jailfull}" ] && /sbin/zfs destroy -R "${ezjail_jailzfs}/fulljail" && rm -rf "${ezjail_jailfull}"
/sbin/zfs create -p "${ezjail_jailzfs}/fulljail" || exerr "Error: Cannot create temporary Jail directory."
else
[ -d "${ezjail_jailfull}" ] && chflags -R noschg "${ezjail_jailfull}" && rm -rf "${ezjail_jailfull}"
mkdir -p "${ezjail_jailfull}" || exerr "Error: Cannot create temporary Jail directory."
fi
# make and setup our world, then split basejail and newjail
cd "${ezjail_sourcetree}" && env DESTDIR="${ezjail_jailfull}" make ${ezjail_installaction} || exerr "Error: The command 'make ${ezjail_installaction}' failed.\n Refer to the error report(s) above."
@ -751,8 +830,14 @@ install)
# Normally fulljail should be renamed by past ezjail-admin commands.
# However those may have failed
[ -d "${ezjail_jailfull}" ] && chflags -R noschg "${ezjail_jailfull}" && rm -rf "${ezjail_jailfull}"
mkdir -p "${ezjail_jailfull}" || exerr "Error: Cannot create temporary jail directory."
if [ "${ezjail_use_zfs}" = "YES" ]; then
echo "ZFS: manage basejail and newjail"
[ -d "${ezjail_jailfull}" ] && /sbin/zfs destroy -R "${ezjail_jailzfs}/fulljail" && rm -rf "${ezjail_jailfull}"
/sbin/zfs create -p "${ezjail_jailzfs}/fulljail" || exerr "Error: Cannot create temporary Jail directory."
else
[ -d "${ezjail_jailfull}" ] && chflags -R noschg "${ezjail_jailfull}" && rm -rf "${ezjail_jailfull}"
mkdir -p "${ezjail_jailfull}" || exerr "Error: Cannot create temporary Jail directory."
fi
DESTDIR=${ezjail_jailfull}
rm -rf "${ezjail_jailtemp}"
@ -1108,6 +1193,12 @@ config)
else
unset ezjail_new_image
fi
if [ "${ezjail_imagetype}" = "zfs" ]; then
# ZFS: using the zfs rename feature to rename the filesystem, remounting is done by ZFS
zfs rename ${ezjail_jailzfs}/${ezjail_hostname} ${ezjail_jailzfs}/${ezjail_new_hostname}
fi
# adjust softlink
if [ -L "${ezjail_softlink}" ]; then
@ -1116,7 +1207,9 @@ config)
fi
# rename rootdir
mv "${ezjail_rootdir}" "${ezjail_new_rootdir}"
if [ ! "${ezjail_imagetype}" = "zfs" ]; then
mv "${ezjail_rootdir}" "${ezjail_new_rootdir}"
fi
# rename fstab
echo -n > "/etc/fstab.${ezjail_new_safename}"

View File

@ -46,3 +46,10 @@
# ezjail_devfs_ruleset="devfsrules_jail"
# ezjail_procfs_enable="YES"
# ezjail_fdescfs_enable="YES"
# Setting this to YES will start to manage the basejail and newjail in ZFS
# ezjail_use_zfs="YES"
# The name of the ZFS ezjail should create jails on, it will be mounted at the ezjail_jaildir
# ezjail_jailzfs="tank/ezjail"
# ADVANCED, be very careful!
# ezjail_zfs_properties="-o compression=lzjb -o atime=off"