diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ee48c45e..c56df890 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,6 @@ name: Bastille_Testing -on: +on: pull_request: branches: - master @@ -29,7 +29,3 @@ jobs: cd bastille make install rocinante template tests/masterTest - - - - diff --git a/COMPARE.md b/COMPARE.md deleted file mode 100644 index 1be6a618..00000000 --- a/COMPARE.md +++ /dev/null @@ -1,31 +0,0 @@ -# Bastille Compared to Other Jail Managers - -| Feature | BastilleBSD | Appjail | pot | ezjail | iocage | -|------------------------------------------|----------------------------------------|----------------------------------------------------------|--------------------|---------------------|-----------------------------------------| -| OCI Compliant | No | Yes | No | No | No | -| Writen In | Bourne Shell | Bourne Shell, C | Bourne Shell, Rust | Bourne Shell | Bourne Shell, Python | -| Dependencies | None | C | Rust | None | Python | -| Jail Types | clone, copy, thin, thick, empty, linux | clone, copy, tiny, thin, thick, empty, linux+debootstrap | thick | basejail | clone, basejail, template, empty, thick | -| Jail dependency | Yes | Yes | Yes | No | Yes | -| Import/Export | Yes | Yes | Yes | Yes | Yes | -| Boot Order Priorities | Yes | Yes | No | Yes using `rcorder` | Yes | -| Linux containers | Yes | Yes | No | No | Yes | -| Automation | Templates | Makejail, Initscripts, Images | Flavours, Images | Flavours | Plugins | -| Cloning | Yes | No | No | No | No | -| Package Management | Yes | No | No | No | No | -| ZFS Support | Yes | Yes | Yes | No | Yes | -| Volume management | Basic | Yes | Basic | No | Basic | -| VNET Support | Yes | Yes | Yes | No | Yes | -| IPv6 Support | Yes | Yes | Yes | Yes | Yes | -| Dual Network Stack | Yes | Yes | Yes | No | No | -| Netgraph | Yes | Yes | No | No | No | -| Dynamic Firewall | Yes | Yes | Yes | No | No | -| Dynamic DEVFS Ruleset Management | No | Yes | No | No | No | -| Resource Control | Yes | Yes | CPU and Memory | No | Legacy Only | -| CPU Sets | Yes | Yes | Yes | Yes | Yes | -| Parallel Startup | Yes | Yes (Healthcheckers, jails & NAT) | No | No | No | -| Multi-Target Commands | Yes | No | No | No | No | -| Log Management | Basic (console logs) | Yes | No | No | No | -| Copy Files Between Jails | Yes | No | No | No | No | -| Automated Jail Migration Between Servers | Yes | No | No | No | No | -| Top/Htop Support | Yes | No | No | No | No | diff --git a/Makefile b/Makefile index 05e21278..e45ab625 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ +BASTILLE_BRANCH=$$(git branch --show-current) BASTILLE_VERSION=$$(git rev-parse --short HEAD) +BASTILLE_DEV_VERSION="${BASTILLE_BRANCH}-${BASTILLE_VERSION}" .PHONY: all all: @@ -8,9 +10,10 @@ install: @echo "Installing Bastille" @echo @echo "Updating Bastille version to match git revision." - @echo "BASTILLE_VERSION: ${BASTILLE_VERSION}" - @sed -i.orig "s/BASTILLE_VERSION=.*/BASTILLE_VERSION=${BASTILLE_VERSION}/" usr/local/bin/bastille + @echo "BASTILLE_VERSION: ${BASTILLE_DEV_VERSION}" + @sed -i '' "s|BASTILLE_VERSION=.*|BASTILLE_VERSION=${BASTILLE_DEV_VERSION}|" usr/local/bin/bastille @cp -Rv usr / + @gzip -f -n /usr/local/share/man/man8/bastille.8 @echo @echo "This method is for testing & development." @echo "Please report any issues to https://github.com/BastilleBSD/bastille/issues" @@ -24,7 +27,7 @@ uninstall: @rm -rvf /usr/local/share/bastille @echo @echo "removing man page" - @rm -rvf /usr/local/share/man/man8/bastille.8.gz + @rm -rvf /usr/local/share/man/man8/bastille* @echo @echo "removing configuration file" @rm -rvf /usr/local/etc/bastille/bastille.conf.sample diff --git a/README.md b/README.md index 6d10f6e4..c122a839 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,33 @@ -Bastille 1.0.x -======== -[Bastille](https://bastillebsd.org/) is an open-source system for automating +

+ +

+ +---- + + +Table of Contents +================= + +* [Table of Contents](#table-of-contents) +* [Bastille](#bastille) + * [Installation](#installation) + * [Usage](#usage) + * [Getting Started](#getting-started) + * [Documentation](#documentation) + * [Comparing](#comparing) + * [Breaking Changes](#breaking-changes) + * [Support](#support) + + +# Bastille + +Bastille is an open-source system for automating deployment and management of containerized applications on FreeBSD. -Check the [Bastille Documentation](https://bastille.readthedocs.io/en/latest/) +[Official BastilleBSD Website](https://bastillebsd.org) +## Installation -Potencially breaking changes in 1.0 ⚠️ -======================================== -Please read the [1.0 release announcement](https://github.com/BastilleBSD/bastille/releases/tag/1.0.20250714) -first if you are upgrading from 0.14.x - - -Bastille Compared to Other Jail Managers ----------------------------------------- - -See the [comparison table.](COMPARE.md) - - -Installation -============ Bastille is available for installation from the official FreeBSD ports tree. **pkg** @@ -29,7 +37,7 @@ pkg install bastille **ports** ```shell -portsnap fetch auto +git clone https://git.freebsd.org/ports.git /usr/ports make -C /usr/ports/sysutils/bastille install clean ``` @@ -45,10 +53,12 @@ make install sysrc bastille_enable=YES ``` -Upgrading from a previous version ---------------------------------- -When upgrading from a previous version of bastille (e.g. 0.10.20230714 to -0.10.20231013) you will need to update your bastille.conf +### Upgrading + +When upgrading from a previous version of bastille (e.g. 0.10.20230714 to +1.1.3.251130) you will need to update your bastille.conf + +Be sure to read the [Breaking Changes](#breaking-changes) below. ```shell cd /usr/local/etc/bastille @@ -58,145 +68,78 @@ diff -u bastille.conf bastille.conf.sample Merge the lines that are present in the new bastille.conf.sample into your bastille.conf -Basic Usage ------------ -```shell -Bastille is an open-source system for automating deployment and management of -containerized applications on FreeBSD. +## Usage -Usage: - bastille [options(s)] command [option(s)] TARGET [args] +See [Usage](https://bastille.readthedocs.io/en/latest/chapters/usage.html) -Available Commands: - bootstrap Bootstrap a release for jail base. - clone Clone an existing jail. - cmd Execute arbitrary command(s) in targeted jail(s). - config Get, set or remove a config value for the targeted jail(s). - console Console into a jail. - convert Convert thin jail to thick jai. Convert jail to custom release base. - cp cp(1) files from host to targeted jail(s). - create Create a jail. - destroy Destroy a jail or release. - edit Edit jail configuration files (advanced). - export Export a jail. - help Help about any command. - htop Interactive process viewer (requires htop). - import Import a jail. - jcp cp(1) files from a jail to jail(s). - limits Apply resources limits to targeted jail(s). See rctl(8) and cpuset(1). - list List jails, releases, templates and more... - migrate Migrate targeted jail(s) to a remote system. - mount Mount a volume inside targeted jail(s). - network Add or remove interfaces from targeted jail(s). - pkg Manipulate binary packages within targeted jail(s). See pkg(8). - rcp cp(1) files from a jail to host. - rdr Redirect host port to jail port. - rename Rename a jail. - restart Restart a running jail. - service Manage services within targeted jail(s). - setup Attempt to auto-configure network, firewall, storage and more... - start Start a stopped jail. - stop Stop a running jail. - sysrc Safely edit rc files within targeted jail(s). - tags Add or remove tags to targeted jail(s). - template Apply file templates to targeted jail(s). - top Display and update information about the top(1) cpu processes. - umount Unmount a volume from targeted jail(s). - update Update jail base -pX release. - upgrade Upgrade jail release to X.Y-RELEASE. - verify Compare release against a "known good" index. - zfs Manage (get|set) ZFS attributes on targeted container(s). +## Getting Started -Use "bastille -v|--version" for version information. -Use "bastille command -h|--help" for more information about a command. -Use "bastille -c|--config config.conf command" to specify a non-default config file. -Use "bastille -p|--parallel VALUE command" to run bastille in parallel mode. +See [Getting Started](https://bastille.readthedocs.io/en/latest/chapters/getting-started.html) -``` +## Documentation -## 1.0.x -This document outlines the basic usage of the Bastille container management -framework. This release is still considered beta. +See [Documentation](https://bastille.readthedocs.io/en/latest/) -Setup Requirements -================== -Bastille can now (attempt) to configure the networking, firewall and storage -automatically. This feature is new since version 0.10.20231013. +## Comparing -**bastille setup** +See [Comparing](https://bastille.readthedocs.io/en/latest/chapters/comparing.html) -```shell -ishmael ~ # bastille setup -h -Usage: bastille setup [-p|pf|firewall] [-l|loopback] [-s|shared] [-z|zfs|storage] [-v|vnet] [-b|bridge] -``` +## Breaking Changes -On fresh installations it is likely safe to run `bastille setup` with no -arguments. This will configure the firewall, the loopback interface and attempt -to determine ZFS vs UFS storage. +### Version 1.x -If you have an existing firewall, or customized network design, you may want to -run individual options; eg `bastille setup zfs` or `bastille setup vnet`. +Up until version 1.0.20250714, Bastille has handled epairs for -V jails +using the jib script included in FreeBSD installs. However, for -B jails, +Bastille statically assigned an epair to each jail. This means you can only +run one type (-V or -B) of VNET jails on a given system. -Note: The `bastille setup` command can configure and enable PF but it does not -automatically reload the firewall. You will still need to manually `service pf -start`. At that point you'll likely be disconnected if configuring a remote -host. Simply reconnect the ssh session and continue. +Starting with version 1.0.20250714, we are now handling all epairs +dynamically, allowing the use of both types of VNET jails without issue. We +have also selected a naming scheme that will allow for consistency across +these jail types. The naming scheme is as follows: -This step only needs to be done once in order to prepare the host. +`e0a_jailname` and `e0b_jailname` are the default epair interfaces for every +jail. The `e0a` side is on the host, while the `e0b` is in the jail. This will +allow better management when trying to figure out which jail a given epair is +linked to. Due to a limitations in how long an interface name can be, Bastille +will name any epairs whose jail names exceed the maximum length, to +`e0b_bastille1` and `e0b_bastille1` with the `1` incrementing by 1 for +each new epair. So, mylongjailname will be `e0a_bastille2` and `e0b_bastille2`. -Example (create, start, console) -================================ -This example creates, starts and consoles into the container. +If you decide to add an interface using the network sub-command, they will +be named `e1a_jailname` and `e1b_jailname` respectively. The number included +in the prefix `eXa_` will increment by 1 for each interface you add. -```shell -ishmael ~ # bastille create alcatraz 14.0-RELEASE 10.17.89.10/24 -``` +### Mandatory -```shell -ishmael ~ # bastille start alcatraz -[alcatraz]: -alcatraz: created -``` +We have tried our best to auto-convert each jails jail.conf and rc.conf +to the new syntax (this happens when the jail is stopped). It isn't a huge +change (only a handful of lines), but if you do have an issue please open a +bug report. -```shell -ishmael ~ # bastille console alcatraz -[alcatraz]: -FreeBSD 14.0-RELEASE GENERIC +After updating, you must restart all your jails (probably one at a time, in +case of issues) to have Bastille convert the jail.conf and rc.conf files. +This simply involves renaming the epairs to the new syntax. -Welcome to FreeBSD! +If you have used the network sub-command to add any number of interfaces, you +will have to edit the jail.conf and rc.conf files for each jail to update +the names of the epair interfaces. This is because all epairs will have been +renamed to e0... in both files. For each additional one, simply increment +the number by 1. -Release Notes, Errata: https://www.FreeBSD.org/releases/ -Security Advisories: https://www.FreeBSD.org/security/ -FreeBSD Handbook: https://www.FreeBSD.org/handbook/ -FreeBSD FAQ: https://www.FreeBSD.org/faq/ -Questions List: https://www.FreeBSD.org/lists/questions/ -FreeBSD Forums: https://forums.FreeBSD.org/ +### Important Limitations -Documents installed with the system are in the /usr/local/share/doc/freebsd/ -directory, or can be installed later with: pkg install en-freebsd-doc -For other languages, replace "en" with a language code like de or fr. +Due to the JIB script that gets used when creating VNET jails, you +will face changes with the MAC address if these jails. -Show the version of FreeBSD installed: freebsd-version ; uname -a -Please include that output and any error messages when posting questions. -Introduction to manual pages: man man -FreeBSD directory layout: man hier +If you have any VNET jails (created with -V), the MAC addresses +will change if you did not also use -M when creating them. This +is due to the JIB script generating a MAC based on the jail interface +name. -To change this login announcement, see motd(5). -root@alcatraz:~ # -``` +If you did use -M when creating them, the MAC should stay the same. -```shell -root@alcatraz:~ # ps -auxw -USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND -root 83222 0.0 0.0 6412 2492 - IsJ 02:21 0:00.00 /usr/sbin/syslogd -ss -root 88531 0.0 0.0 6464 2508 - SsJ 02:21 0:00.01 /usr/sbin/cron -s -root 6587 0.0 0.0 6912 2788 3 R+J 02:42 0:00.00 ps -auxw -root 92441 0.0 0.0 6952 3024 3 IJ 02:21 0:00.00 login [pam] (login) -root 92565 0.0 0.0 7412 3756 3 SJ 02:21 0:00.01 -csh (csh) -root@alcatraz:~ # -``` +## Support -Community Support -================= If you've found a bug in Bastille, please submit it to the [Bastille Issue -Tracker](https://github.com/bastillebsd/bastille/issues/new). +Tracker](https://github.com/bastillebsd/bastille/issues/new) diff --git a/docs/chapters/centralized-assets.rst b/docs/chapters/centralized-assets.rst index 9c650b50..09199383 100644 --- a/docs/chapters/centralized-assets.rst +++ b/docs/chapters/centralized-assets.rst @@ -21,7 +21,7 @@ you prefer. ishmael ~ # bastille template "jail1 jail2" project/template -See the chapter on templates for details on how to create your own templates. +See :doc:`/chapters/template` for more details on templates. Mounting -------- @@ -36,7 +36,7 @@ access, simply use ``ro`` instead of ``rw`` as the option. .. code-block:: shell ishmael ~ # bastille mount "jail1 jail2" /my/host/directory /my/jail/directory nullfs rw 0 0 - + Cloning ------- @@ -46,9 +46,9 @@ To clone your jail, use the following command. .. code-block:: shell ishmael ~ # bastille clone myjail mynewjail 10.0.0.3 - + This will create an exact duplicate of ``myjail`` at ``mynewjail``. - + Custom Releases --------------- @@ -61,14 +61,14 @@ process will not work with any other jail types. .. code-block:: shell ishmael ~ # bastille create -T myjail 14.2-RELEASE 10.0.0.1 - + Once the jail is up and running, configure it to your liking, then run the following commmand to create a custom release based on your jail. .. code-block:: shell ishmael ~ # bastille convert myjail myrelease - + Once this process completes, you will be able to run the following command to create a jail based off your newly created release. diff --git a/docs/chapters/comparing.rst b/docs/chapters/comparing.rst index 91aa8eff..31d54fef 100644 --- a/docs/chapters/comparing.rst +++ b/docs/chapters/comparing.rst @@ -18,8 +18,7 @@ as a list of popular managers and their status on each option. | | Shell | Shell, C | Shell, | Shell | Shell, | | | | | Rust | | Python | +--------------+-------------+--------------+-----------+-----------+-----------+ -| Dep | None | C | Rust | None | Python | -| endencies | | | | | | +| Dependencies | None | C | Rust | None | Python | +--------------+-------------+--------------+-----------+-----------+-----------+ | Jail | vnet, | clone, | thick | basejail | clone, | | Types | bridged | copy, | | | basejail, | @@ -33,16 +32,15 @@ as a list of popular managers and their status on each option. | Jail | Yes | Yes | Yes | No | Yes | | Dependency | | | | | | +--------------+-------------+--------------+-----------+-----------+-----------+ -| Impo | Yes | Yes | Yes | Yes | Yes | -| rt/Export | | | | | | +| Import/ | Yes | Yes | Yes | Yes | Yes | +| Export | | | | | | +--------------+-------------+--------------+-----------+-----------+-----------+ | Boot | Yes | Yes | No | Yes using | Yes | | Order | | | | 'rcorder' | | | Priorities | | | | | | +--------------+-------------+--------------+-----------+-----------+-----------+ | Linux | Yes | Yes | No | No | Yes | -| c | | | | | | -| ontainers | | | | | | +| Containers | | | | | | +--------------+-------------+--------------+-----------+-----------+-----------+ | Automation | Templates | Makejail, | Flavours, | Flavours | Plugins | | | | Initscripts, | Images | | | @@ -90,6 +88,9 @@ as a list of popular managers and their status on each option. | | | jails & | | | | | | | NAT) | | | | +--------------+-------------+--------------+-----------+-----------+-----------+ +| PkgBase | Yes | Yes | No | No | No | +| Support | | | | | | ++--------------+-------------+--------------+-----------+-----------+-----------+ | Multi-target | Yes | No | No | No | No | | Commands | | | | | | +--------------+-------------+--------------+-----------+-----------+-----------+ diff --git a/docs/chapters/configuration.rst b/docs/chapters/configuration.rst index 5c6b7de0..9b3b186c 100644 --- a/docs/chapters/configuration.rst +++ b/docs/chapters/configuration.rst @@ -4,9 +4,10 @@ Configuration Bastille is configured using a default config file located at ``/usr/local/etc/bastille/bastille.conf``. When first installing bastille, you should run ``bastille setup``. This will ask if you want to copy the sample -config file to the above location. The defaults are sensible for UFS, but if you -want to use ZFS, you will have to change a few options. See the chapter on ZFS -Support. +config file to the above location. The defaults are sensible for UFS, but +if you use ZFS, ``bastille setup`` will configure it for you. If you have +multiple zpools, Bastille will ask which one you want to use. See also +:doc:`/chapters/zfs-support`. This is the default `bastille.conf` file. @@ -41,6 +42,24 @@ This is the default `bastille.conf` file. ## bastille_bootstrap_archives="base lib32 ports src test" bastille_bootstrap_archives="base" ## default: "base" + ## pkgbase package sets (used for FreeBSD 15+) + ## Any set with [-dbg] can be installed with debugging + ## symbols by adding '-dbg' to the package set + ## base[-dbg] - Base system + ## base-jail[-dbg] - Base system for jails + ## devel[-dbg] - Development tools + ## kernels[-dbg] - Base system kernels + ## lib32[-dbg] - 32-bit compatability libraries + ## minimal[-dbg] - Basic multi-user system + ## minimal-jail[-dbg] - Basic multi-user jail system + ## optional[-dbg] - Optional base system software + ## optional-jail[-dbg] - Optional base system software for jails + ## src - System source code + ## tests - System test suite + ## Whitespace separated list: + ## bastille_pkgbase_packages="base-jail lib32-dbg src" + bastille_pkgbase_packages="base-jail" ## default: "base-jail" + ## default timezone bastille_tzdata="" ## default: empty to use host's time zone @@ -108,7 +127,7 @@ The options here are fairly self-explanitory, but there are some things to note. Custom Configuration -------------------- -Bastille now supports using a custom config in addition to the default one. This +Bastille supports using a custom config in addition to the default one. This is nice if you have multiple users, or want to store different jails at different locations based on your needs. @@ -130,3 +149,304 @@ environment or user. Then, it can be used in a couple of ways. - If you use sudo, you will need to run it with ``sudo -E bastille bootstrap...`` to preserve your users environment. This can also be persisted by editing the sudoers file. - If you do set the ``BASTILLE_CONFIG`` variable, you do not need to specify the config file when running Bastille as that specified user. + +Note: FreeBSD introduced container technology twenty years ago, long before the +industry standardized on the term "container". Internally, FreeBSD refers to +these containers as "jails". + +Jail Startup Configuration +-------------------------- + +Bastille can start jails on system startup, and stop them on system shutdown. +To enable this functionality, we must first enable Bastille as a service using +``sysrc bastille_enable=YES``. Once you reboot your host, all jails with +``boot=on`` will be started when the host boots. + +If you have certain jails that must be started before other jails, you can use +the priority option. Jails will start in order starting at the lowest value, and +will stop in order starting at the highest value. So, jails with a priority value +of 1 will start first, and stop last. + +See :doc:`/chapters/targeting` for more info. + +Boot +^^^^ + +The boot setting controls whether a jail will be started on system startup. If +you have enabled bastille with ``sysrc bastille_enable=YES``, all jails with +``boot=on`` will start on system startup. Any jail(s) with ``boot=off`` will not +be started on system startup. + +By default, when jails are created with Bastille, the boot setting is set to ``on`` +by default. This can be overridden using the ``--no-boot`` flag. +See ``bastille create --no-boot TARGET...``. + +You can also use ``bastille start --boot TARGET`` to make Bastille respect the +boot setting. If ``-b|--boot`` is not used, the targeted jail(s) will start, +regardless of the boot setting. + +Jails will still shut down on system shutdown, regardless of this setting. + +The ``-b|--boot`` can also be used with the ``stop`` command. Any jails with +``boot=off`` will not be touched if ``stop`` is called with ``-b|--boot``. Same +goes for the ``restart`` command. + +This value can be changed using ``bastille config TARGET set boot [on|off]``. + +This value will be shown using ``bastille list all``. + +Depend +^^^^^^ + +Bastille supports configuring jails to depend on each other when started and +stopped. If jail1 "depends" on jail2, then jail2 will be started if it is not +running when ``bastille start jail1`` is called. Any jail that jail1 "depends" +on will first be verified running (started if stopped) before jail1 is started. + +For example, I have 3 jails called nginx, mariadb and nextcloud. I want to +ensure that nginx and mariadb are running before nextcloud is started. + +First we must add both jails to nextcloud's depend property with +``bastille config nextcloud set depend "mariadb nginx"``. +Then, when we start nextcloud with ``bastille start nextcloud`` it will verify +that nginx and mariadb are running (start if stopped) before starting nextcloud. + +When stopping a jail, any jail that "depends" on it will first be stopped. +For example, if we run ``bastille stop nginx``, then nextcloud will first be +stopped because it "depends" on nginx. + +Note that if we do a ``bastille restart nginx``, however, nextcloud will be +stopped, because it "depends" on nginx, but will not be started again, because +the jail we just restarted, nginx, does not depend on nextcloud. + +Parallel Startup +^^^^^^^^^^^^^^^^ + +Bastille supports starting, stopping and restarting jails in parallel mode using +the ``rc`` service script. To enable this functionality, set +``bastille_parallel_limit`` to a numeric value. + +For example, if you run ``sysrc bastille_parallel_limit=4``, then Bastille will +start 4 jails at a time on system startup, as well as stop or restart 4 jails at +a time when ``service bastille...`` is called. + +This value is set to 1 by default, to only start/stop/restart jails one at a time. + +Startup Delay +^^^^^^^^^^^^^ + +Sometimes it is necessary to let a jail start fully before continuing to the +next jail. + +We can do this with another sysrc value called ``bastille_startup_delay``. +Setting ``bastille_startup_delay=5`` will tell Bastille to wait 5 seconds between +starting each jail. + +You can also use ``bastille start -d|--delay 5 all`` or +``bastille restart -d|--delay 5 all`` to achieve the same thing. + +jail.conf +--------- + +In this section we'll look at the default config for a new container. The +defaults are sane for most applications, but if you want to tweak the settings +here they are. + +A ``jail.conf`` template is used each time a new container is created. This +template looks like this: + +.. code-block:: shell + + {name} { + devfs_ruleset = 4; + enforce_statfs = 2; + exec.clean; + exec.consolelog = /var/log/bastille/{name}_console.log; + exec.start = '/bin/sh /etc/rc'; + exec.stop = '/bin/sh /etc/rc.shutdown'; + host.hostname = {name}; + interface = {interface}; + mount.devfs; + mount.fstab = /usr/local/bastille/jails/{name}/fstab; + path = /usr/local/bastille/jails/{name}/root; + securelevel = 2; + + ip4.addr = interface|x.x.x.x; + ip6 = disable; + } + + +devfs_ruleset +^^^^^^^^^^^^^ + +.. code-block:: shell + + devfs_ruleset + The number of the devfs ruleset that is enforced for mounting + devfs in this jail. A value of zero (default) means no ruleset + is enforced. Descendant jails inherit the parent jail's devfs + ruleset enforcement. Mounting devfs inside a jail is possible + only if the allow.mount and allow.mount.devfs permissions are + effective and enforce_statfs is set to a value lower than 2. + Devfs rules and rulesets cannot be viewed or modified from inside + a jail. + + NOTE: It is important that only appropriate device nodes in devfs + be exposed to a jail; access to disk devices in the jail may + permit processes in the jail to bypass the jail sandboxing by + modifying files outside of the jail. See devfs(8) for + information on how to use devfs rules to limit access to entries + in the per-jail devfs. A simple devfs ruleset for jails is + available as ruleset #4 in /etc/defaults/devfs.rules. + + +enforce_statfs +^^^^^^^^^^^^^^ + +.. code-block:: shell + + enforce_statfs + This determines what information processes in a jail are able to + get about mount points. It affects the behaviour of the + following syscalls: statfs(2), fstatfs(2), getfsstat(2), and + fhstatfs(2) (as well as similar compatibility syscalls). When + set to 0, all mount points are available without any + restrictions. When set to 1, only mount points below the jail's + chroot directory are visible. In addition to that, the path to + the jail's chroot directory is removed from the front of their + pathnames. When set to 2 (default), above syscalls can operate + only on a mount-point where the jail's chroot directory is + located. + + +exec.clean +^^^^^^^^^^ + +.. code-block:: shell + + exec.clean + Run commands in a clean environment. The environment is + discarded except for HOME, SHELL, TERM and USER. HOME and SHELL + are set to the target login's default values. USER is set to the + target login. TERM is imported from the current environment. + The environment variables from the login class capability + database for the target login are also set. + + +exec.consolelog +^^^^^^^^^^^^^^^ + +.. code-block:: shell + + exec.consolelog + A file to direct command output (stdout and stderr) to. + + +exec.start +^^^^^^^^^^ + +.. code-block:: shell + + exec.start + Command(s) to run in the jail environment when a jail is created. + A typical command to run is "sh /etc/rc". + + +exec.stop +^^^^^^^^^ + +.. code-block:: shell + + exec.stop + Command(s) to run in the jail environment before a jail is + removed, and after any exec.prestop commands have completed. A + typical command to run is "sh /etc/rc.shutdown". + + +host.hostname +^^^^^^^^^^^^^ + +.. code-block:: shell + + host.hostname + The hostname of the jail. Other similar parameters are + host.domainname, host.hostuuid and host.hostid. + + +mount.devfs +^^^^^^^^^^^ + +.. code-block:: shell + + mount.devfs + Mount a devfs(5) filesystem on the chrooted /dev directory, and + apply the ruleset in the devfs_ruleset parameter (or a default of + ruleset 4: devfsrules_jail) to restrict the devices visible + inside the jail. + + +mount.fstab +^^^^^^^^^^^ + +.. code-block:: shell + + mount.fstab + An fstab(5) format file containing filesystems to mount before + creating a jail. + + +path +^^^^ + +.. code-block:: shell + + path + The directory which is to be the root of the jail. Any commands + run inside the jail, either by jail or from jexec(8), are run + from this directory. + + +securelevel +^^^^^^^^^^^ + +By default, Bastille containers run at ``securelevel = 2;``. See below for the +implications of kernel security levels and when they might be altered. + +Note: Bastille does not currently have any mechanism to automagically change +securelevel settings. My recommendation is this only be altered manually on a +case-by-case basis and that "Highly secure mode" is a sane default for most use +cases. + +.. code-block:: shell + + The kernel runs with five different security levels. Any super-user + process can raise the level, but no process can lower it. The security + levels are: + + -1 Permanently insecure mode - always run the system in insecure mode. + This is the default initial value. + + 0 Insecure mode - immutable and append-only flags may be turned off. + All devices may be read or written subject to their permissions. + + 1 Secure mode - the system immutable and system append-only flags may + not be turned off; disks for mounted file systems, /dev/mem and + /dev/kmem may not be opened for writing; /dev/io (if your platform + has it) may not be opened at all; kernel modules (see kld(4)) may + not be loaded or unloaded. The kernel debugger may not be entered + using the debug.kdb.enter sysctl. A panic or trap cannot be forced + using the debug.kdb.panic and other sysctl's. + + 2 Highly secure mode - same as secure mode, plus disks may not be + opened for writing (except by mount(2)) whether mounted or not. + This level precludes tampering with file systems by unmounting + them, but also inhibits running newfs(8) while the system is multi- + user. + + In addition, kernel time changes are restricted to less than or + equal to one second. Attempts to change the time by more than this + will log the message "Time adjustment clamped to +1 second". + + 3 Network secure mode - same as highly secure mode, plus IP packet + filter rules (see ipfw(8), ipfirewall(4) and pfctl(8)) cannot be + changed and dummynet(4) or pf(4) configuration cannot be adjusted. diff --git a/docs/chapters/gcp.rst b/docs/chapters/gcp.rst index c6fb5e72..a5ff2482 100644 --- a/docs/chapters/gcp.rst +++ b/docs/chapters/gcp.rst @@ -22,7 +22,7 @@ Apply the below patch to set the correct MTU. You may need to ``cp --- /usr/local/bin/jib 2022-07-31 03:27:04.163245000 +0000 +++ jib.fixed 2022-07-31 03:41:16.710401000 +0000 @@ -299,14 +299,14 @@ - + # Make sure the interface has been bridged if ! ifconfig "$iface$bridge" > /dev/null 2>&1; then - new=$( ifconfig bridge create ) || return @@ -31,12 +31,12 @@ Apply the below patch to set the correct MTU. You may need to ``cp ifconfig $new name "$iface$bridge" || return ifconfig "$iface$bridge" up || return fi - + # Create a new interface to the bridge - new=$( ifconfig epair create ) || return + new=$( ifconfig epair create mtu 1460 ) || return ifconfig "$iface$bridge" addm $new || return - + # Rename the new interface ## Configure bridge interface @@ -58,18 +58,18 @@ them through the external interface: .. code-block:: text ext_if="vtnet0" bridge_if="vtnet0bridge" - + set skip on lo scrub in # permissive NAT allows jail bridge and wireguard tunnels nat on $ext_if inet from !($ext_if) -> ($ext_if:0) - + block in pass out - + pass in proto tcp to port {22} - pass in inet proto icmp icmp-type { echoreq } + pass in proto icmp icmp-type { echoreq } pass in on $bridge_if Restart the host and make sure everything comes up correctly. You should see the diff --git a/docs/chapters/getting-started.rst b/docs/chapters/getting-started.rst new file mode 100644 index 00000000..d730b566 --- /dev/null +++ b/docs/chapters/getting-started.rst @@ -0,0 +1,101 @@ +Getting Started +=============== + +Bastille has many different options when it comes to creating +and managing jails. This guide is meant to show some basic +setup and configuration options. + +Setup +----- + +The first command a new user should run is ``bastille setup``. This +will configure the networking, storage, and firewall on your system +for use with Bastille. + +By default the ``bastille setup`` will configure a loopback interface, storage (ZFS if +enabled, otherwise UFS) and the ``pf`` firewall. + +Alternatively, you can run ``bastille setup OPTION`` command with any of the supported +options to configure the selected option by itself. + +To see a list of available options, see the :doc:`/chapters/subcommands/setup` subcommand. + +.. code-block:: shell + + ishmael ~ # bastille setup + +Now we are ready to bootstrap a release and start creating jails. + +Bootstrapping a Release +----------------------- + +To bootstrap a release, run ``bastille bootstrap RELEASE``. + +.. code-block:: shell + + ishmael ~ # bastille bootstrap 14.2-RELEASE + +This will fetch the necessary components of the specified release, and +enable us to create jails from the downloaded release. + +Creating a Jail +--------------- + +There are a few different types of jails we can create, described below. + +* Thin jails are the default, and are called thin because they use symlinks to + the bootstrapped release. They are lightweight and are created quickly. + +* Thick jails use the entire release, which is copied into the jail. The jail + then acts like a full BSD install, completely independent of the release. + Created with the ``--thick|-T`` option. + +* Clone jails are essentially clones of the bootstrapped release. Changes to the + release will affect the clone jail. Created with the ``--clone|-C`` option. + +* Empty jails are just that, empty. These should be used only if you know what + you are doing. Created with the ``--empty|-E`` option. + +* Linux jails are jails that run linux. Created with the ``--linux|-L`` option. + See :doc:`/chapters/linux-jails`. + +We will focus on thin jails for this guide. + +Classic/Standard Jail +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + ishmael ~ # bastille create nextcloud 14.2-RELEASE 10.1.1.4/24 + +This will create a classic jail, which uses the loopback interface +(created with ``bastille setup``) for outbound connections. + +To be able to reach a service inside the jail, use ``bastille rdr``. + +.. code-block:: shell + + ishmael ~ # bastille rdr nextcloud tcp 80 80 + +This will forward traffic from port 80 on the host to port 80 inside the jail. +See also :doc:`/chapters/subcommands/rdr`. + +VNET Jail +^^^^^^^^^ + +VNET jails can use either a host interface with ``-V`` or a manually created +bridge interface with ``-B``. You can also optionally set a static MAC for the +jail interface with ``-M``. + +.. code-block:: shell + + ishmael ~ # bastille create -BM nextcloud 14.2-RELEASE 192.168.1.50/24 bridge0 + +or + +.. code-block:: shell + + ishmael ~ # bastille create -VM nextcloud 14.2-RELEASE 192.168.1.50/24 vtnet0 + +The IP used for VNET jails should be an IP reachable inside your local network. +You can also specify 0.0.0.0 or DHCP to use DHCP. diff --git a/docs/chapters/gettingstarted.rst b/docs/chapters/gettingstarted.rst deleted file mode 100644 index 5a9b5e2f..00000000 --- a/docs/chapters/gettingstarted.rst +++ /dev/null @@ -1,118 +0,0 @@ -Getting Started -=============== - -This guide is meant to get you up and running with bastille, and will show you -a number of different options to create and manage your jails. - -Setup ------ - -The first command a new user should run is the ``bastille setup`` command. This -will attempt to configure the networking, storage, and firewall on your system -for use with Bastille. - -By default the setup command will configure a loopback interface, storage (ZFS if -enabled, otherwise UFS) and the pf firewall if you run it as below without any -options. - -Alternatively, you can run the ``setup`` command with any of the supported -options to configure the selected option by itself. - -To see a list of available options and switches, see the ``setup`` subcommand. - -.. code-block:: shell - - ishmael ~ # bastille setup - -Bootstrapping a Release ------------------------ - -Then we need to bootstrap a release for bastille to use. We will use -14.2-RELEASE. - -.. code-block:: shell - - ishmael ~ # bastille bootstrap 14.2-RELEASE - -Creating a Jail ---------------- - -Next we can create our first jail. Bastille can create a few different types of -jails. - -* Thin jails are the default, and are called thin because they use symlinks to - the bootstrapped release. They are lightweight and are created quickly. - -* Thick jails used the entire release, which is copied into the jail. The jail - then acts like a full BSD install, completely independent of the release. - Created with ``bastille create -T``. - -* Clone jails are essentially clones of the bootstrapped release. Changes to the - release will affect the clone jail. Created with ``bastille create -C``. - -* Empty jails are just that, empty. These should be used only if you know what - you are doing. Created with ``bastille create -E``. - -* Linux jails are jails that run linux. Created with ``bastille create -L``. - -Only clone, thin, and thick jails can be created with ``-V`` ``-B`` and ``-M``. - -We will focus on thin jails for the guide. - -Classic/Standard Jail -^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: shell - - ishmael ~ # bastille create nextcloud 14.2-RELEASE 10.1.1.4/24 vtnet0 - -This will create a classic jail and add the IP as an alias to the vtnet0 -interface. This jail will use NAT for its outbound traffic. If you want to run -a webserver of something similar inside it, you will have to redirect traffic -from the host using ``bastille rdr`` - -It the IP is reachable within your local subnet, however, then it is not -necessary to redirect the traffic. It will pass in and out normally. - -.. code-block:: shell - - ishmael ~ # bastille rdr nextcloud tcp 80 80 - -This will forward traffic from port 80 on the host to port 80 inside the jail. - -VNET Jail -^^^^^^^^^ - -VNET jails can use either a host interface with ``-V`` or a manually created -bridge interface with ``-B``. You can also optionally set a static MAC for the -jail interface with ``-M``. - -.. code-block:: shell - - ishmael ~ # bastille create -BM nextcloud 14.2-RELEASE 192.168.1.50/24 bridge0 - -or - -.. code-block:: shell - - ishmael ~ # bastille create -VM nextcloud 14.2-RELEASE 192.168.1.50/24 vtnet0 - -The IP used for VNET jails should be an IP reachable inside your local network. -You can also specify 0.0.0.0 or DHCP to use DHCP. - -Linux Jail -^^^^^^^^^^ - -Linux jails are still considered experimental, but they seem to work. First we -must bootstrap a linux distro (Linux distros are bootstrapped with the Debian -tool debootstrap). - -.. code-block:: shell - - ishmael ~ # bastille bootstrap bionic - -Then we can create our linux jail using this release. This will take a while... - -.. code-block:: shell - - ishmael ~ # bastille create -L linux_jail bionic 10.1.1.7/24 vtnet0 diff --git a/docs/chapters/hardened-bsd.rst b/docs/chapters/hardened-bsd.rst new file mode 100644 index 00000000..9c196097 --- /dev/null +++ b/docs/chapters/hardened-bsd.rst @@ -0,0 +1,95 @@ +HardenedBSD +=========== + +Bastille supports HardenedBSD as an OS since it is FreeBSD based. There +are some differences in how HBSD handles release names, updates, and +upgrades. + +Most of the Bastille commands will work with HardenedBSD, but please report +any bugs you may find. + +There are a number of ways in which HardenedBSD differs from FreeBSD. +Most of the functionality is the same, but some things are different. +See the following examples... + +Bootstrap +--------- + +HardenedBSD follows the ``STABLE`` branches of FreeBSD, and releases +are named ``X-stable``, where ``X`` is the major version of a given FreeBSD +branch/release. + +It also has a ``current`` release, which follows the master/current +branch for the latest FreeBSD release. + +When bootstrapping a release, use the above release keywords. + +Updating +-------- + +To update HardenedBSD jails/releases you can do the following: + +Thick Jails +^^^^^^^^^^^ + +1. Use ``bastille update TARGET`` to update the jail +2. Upgrade complete! + +Thin Jails +^^^^^^^^^^ + +See ``bastille update RELEASE`` to update thin jails, as thin +jails are based on a given release. + +Releases +^^^^^^^^ + +1. Use ``bastille update 15-stable`` to update the release to the latest version +2. Update complete! + +Upgrading +--------- + +To upgrade HardenedBSD jails to a different (higher) release (ie; 14-stable > 15-stable) +you can do the following: + +Thick Jails +^^^^^^^^^^^ + +1. Use ``bastille upgrade TARGET current`` to upgrade the jail to + the ``current`` release +2. Force the reinstallation or upgrade of all installed packages (ABI change): + ``pkg upgrade -f`` within each jail (or ``bastille pkg ALL upgrade -f``) +3. Upgrade complete! + +Thin Jails +^^^^^^^^^^ + +1. Ensure the new release is bootstrapped: ``bastille bootstrap 15-stable`` +2. Update the release: ``bastille update 15-stable`` +3. Stop the jail(s) that need to be updated. +4. Use ``bastille upgrade TARGET 15-stable`` to automatically change the + mount points to 15-stable +5. Start the jail(s) +6. Force the reinstallation or upgrade of all installed packages (ABI change): + ``pkg upgrade -f`` within each jail (or ``bastille pkg ALL upgrade -f``) +7. Upgrade complete! + +Releases +^^^^^^^^ + +The ``upgrade`` sub-command does not support upgrading a release +to a different release. See ``bastille bootstrap`` to bootstrap +the new release. + +Limitations +----------- + +Bastille tries its best to determine which *BSD you are using. It is possible to +mix and match any of the supported BSD distributions, but it is up to the end +user to ensure the correct environment/tools when doing so. See below... + +* Running HardenedBSD jails/releases requires many of the tools found only + in the HardenedBSD base. +* Running FreeBSD jails/releases requires many of the tools found only in + the FreeBSD base. diff --git a/docs/chapters/installation.rst b/docs/chapters/installation.rst index 3766477d..eebb969d 100644 --- a/docs/chapters/installation.rst +++ b/docs/chapters/installation.rst @@ -1,10 +1,11 @@ Installation ============ + Bastille is available in the official FreeBSD ports tree at ``sysutils/bastille``. Binary packages are available in quarterly and latest repositories. -Current version is ``1.0.1.250714``. +Current version is ``1.2.0.251201``. To install from the FreeBSD package repository: @@ -18,9 +19,6 @@ pkg .. code-block:: shell pkg install bastille - bastille setup - -To install from source (don't worry, no compiling): ports ----- @@ -28,7 +26,6 @@ ports .. code-block:: shell make -C /usr/ports/sysutils/bastille install clean - bastille setup git --- @@ -38,9 +35,8 @@ git git clone https://github.com/BastilleBSD/bastille.git cd bastille make install - bastille setup -This method will install the latest files from GitHub directly onto your +The ``git`` method will install the latest files from GitHub directly onto your system. It is verbose about the files it installs (for later removal), and also has a ``make uninstall`` target. You may need to manually copy the sample config into place before Bastille will run. (ie; diff --git a/docs/chapters/jail-config.rst b/docs/chapters/jail-config.rst deleted file mode 100644 index 8b15029b..00000000 --- a/docs/chapters/jail-config.rst +++ /dev/null @@ -1,197 +0,0 @@ -Note: FreeBSD introduced container technology twenty years ago, long before the -industry standardized on the term "container". Internally, FreeBSD refers to -these containers as "jails". - -jail.conf -========= -In this section we'll look at the default config for a new container. The -defaults are sane for most applications, but if you want to tweak the settings -here they are. - -A ``jail.conf`` template is used each time a new container is created. This -template looks like this: - -.. code-block:: shell - - {name} { - devfs_ruleset = 4; - enforce_statfs = 2; - exec.clean; - exec.consolelog = /var/log/bastille/{name}_console.log; - exec.start = '/bin/sh /etc/rc'; - exec.stop = '/bin/sh /etc/rc.shutdown'; - host.hostname = {name}; - interface = {interface}; - mount.devfs; - mount.fstab = /usr/local/bastille/jails/{name}/fstab; - path = /usr/local/bastille/jails/{name}/root; - securelevel = 2; - - ip4.addr = interface|x.x.x.x; - ip6 = disable; - } - - -devfs_ruleset -------------- -.. code-block:: shell - - devfs_ruleset - The number of the devfs ruleset that is enforced for mounting - devfs in this jail. A value of zero (default) means no ruleset - is enforced. Descendant jails inherit the parent jail's devfs - ruleset enforcement. Mounting devfs inside a jail is possible - only if the allow.mount and allow.mount.devfs permissions are - effective and enforce_statfs is set to a value lower than 2. - Devfs rules and rulesets cannot be viewed or modified from inside - a jail. - - NOTE: It is important that only appropriate device nodes in devfs - be exposed to a jail; access to disk devices in the jail may - permit processes in the jail to bypass the jail sandboxing by - modifying files outside of the jail. See devfs(8) for - information on how to use devfs rules to limit access to entries - in the per-jail devfs. A simple devfs ruleset for jails is - available as ruleset #4 in /etc/defaults/devfs.rules. - - -enforce_statfs --------------- -.. code-block:: shell - - enforce_statfs - This determines what information processes in a jail are able to - get about mount points. It affects the behaviour of the - following syscalls: statfs(2), fstatfs(2), getfsstat(2), and - fhstatfs(2) (as well as similar compatibility syscalls). When - set to 0, all mount points are available without any - restrictions. When set to 1, only mount points below the jail's - chroot directory are visible. In addition to that, the path to - the jail's chroot directory is removed from the front of their - pathnames. When set to 2 (default), above syscalls can operate - only on a mount-point where the jail's chroot directory is - located. - - -exec.clean ----------- -.. code-block:: shell - - exec.clean - Run commands in a clean environment. The environment is - discarded except for HOME, SHELL, TERM and USER. HOME and SHELL - are set to the target login's default values. USER is set to the - target login. TERM is imported from the current environment. - The environment variables from the login class capability - database for the target login are also set. - - -exec.consolelog ---------------- -.. code-block:: shell - - exec.consolelog - A file to direct command output (stdout and stderr) to. - - -exec.start ----------- -.. code-block:: shell - - exec.start - Command(s) to run in the jail environment when a jail is created. - A typical command to run is "sh /etc/rc". - - -exec.stop ---------- -.. code-block:: shell - - exec.stop - Command(s) to run in the jail environment before a jail is - removed, and after any exec.prestop commands have completed. A - typical command to run is "sh /etc/rc.shutdown". - - -host.hostname -------------- -.. code-block:: shell - - host.hostname - The hostname of the jail. Other similar parameters are - host.domainname, host.hostuuid and host.hostid. - - -mount.devfs ------------ -.. code-block:: shell - - mount.devfs - Mount a devfs(5) filesystem on the chrooted /dev directory, and - apply the ruleset in the devfs_ruleset parameter (or a default of - ruleset 4: devfsrules_jail) to restrict the devices visible - inside the jail. - - -mount.fstab ------------ -.. code-block:: shell - - mount.fstab - An fstab(5) format file containing filesystems to mount before - creating a jail. - - -path ----- -.. code-block:: shell - - path - The directory which is to be the root of the jail. Any commands - run inside the jail, either by jail or from jexec(8), are run - from this directory. - - -securelevel ------------ -By default, Bastille containers run at ``securelevel = 2;``. See below for the -implications of kernel security levels and when they might be altered. - -Note: Bastille does not currently have any mechanism to automagically change -securelevel settings. My recommendation is this only be altered manually on a -case-by-case basis and that "Highly secure mode" is a sane default for most use -cases. - -.. code-block:: shell - - The kernel runs with five different security levels. Any super-user - process can raise the level, but no process can lower it. The security - levels are: - - -1 Permanently insecure mode - always run the system in insecure mode. - This is the default initial value. - - 0 Insecure mode - immutable and append-only flags may be turned off. - All devices may be read or written subject to their permissions. - - 1 Secure mode - the system immutable and system append-only flags may - not be turned off; disks for mounted file systems, /dev/mem and - /dev/kmem may not be opened for writing; /dev/io (if your platform - has it) may not be opened at all; kernel modules (see kld(4)) may - not be loaded or unloaded. The kernel debugger may not be entered - using the debug.kdb.enter sysctl. A panic or trap cannot be forced - using the debug.kdb.panic and other sysctl's. - - 2 Highly secure mode - same as secure mode, plus disks may not be - opened for writing (except by mount(2)) whether mounted or not. - This level precludes tampering with file systems by unmounting - them, but also inhibits running newfs(8) while the system is multi- - user. - - In addition, kernel time changes are restricted to less than or - equal to one second. Attempts to change the time by more than this - will log the message "Time adjustment clamped to +1 second". - - 3 Network secure mode - same as highly secure mode, plus IP packet - filter rules (see ipfw(8), ipfirewall(4) and pfctl(8)) cannot be - changed and dummynet(4) or pf(4) configuration cannot be adjusted. diff --git a/docs/chapters/jail-startup-configuration.rst b/docs/chapters/jail-startup-configuration.rst deleted file mode 100644 index 42cf2a04..00000000 --- a/docs/chapters/jail-startup-configuration.rst +++ /dev/null @@ -1,90 +0,0 @@ -Jail Startup Configuration -========================== - -Bastille can start jails on system startup, and stop them on system shutdown. -To enable this functionality, we must first enable Bastille as a service using -``sysrc bastille_enable=YES``. Once you reboot your host, all jails with -``boot=on`` will be started when the host boots. - -If you have certain jails that must be started before other jails, you can use -the priority option. Jails will start in order starting at the lowest value, and -will stop in order starting at the highest value. So, jails with a priority value -of 1 will start first, and stop last. - -See the chapter on targeting for more info. - -Boot ----- - -The boot setting controls whether a jail will be started on system startup. If -you have enabled bastille with ``sysrc bastille_enable=YES``, all jails with -``boot=on`` will start on system startup. Any jail(s) with ``boot=off`` will not -be started on system startup. - -By default, when jails are created with Bastille, the boot setting is set to ``on`` -by default. This can be overridden using the ``--no-boot`` flag. -See ``bastille create --no-boot TARGET...``. - -You can also use ``bastille start --boot TARGET`` to make Bastille respect the -boot setting. If ``-b|--boot`` is not used, the targeted jail(s) will start, -regardless of the boot setting. - -Jails will still shut down on system shutdown, regardless of this setting. - -The ``-b|--boot`` can also be used with the ``stop`` command. Any jails with -``boot=off`` will not be touched if ``stop`` is called with ``-b|--boot``. Same -goes for the ``restart`` command. - -This value can be changed using ``bastille config TARGET set boot [on|off]``. - -This value will be shown using ``bastille list all``. - -Depend ------- - -Bastille supports configuring jails to depend on each other when started and -stopped. If jail1 "depends" on jail2, then jail2 will be started if it is not -running when ``bastille start jail1`` is called. Any jail that jail1 "depends" -on will first be verified running (started if stopped) before jail1 is started. - -For example, I have 3 jails called nginx, mariadb and nextcloud. I want to -ensure that nginx and mariadb are running before nextcloud is started. - -First we must add both jails to nextcloud's depend property with -``bastille config nextcloud set depend "mariadb nginx"``. -Then, when we start nextcloud with ``bastille start nextcloud`` it will verify -that nginx and mariadb are running (start if stopped) before starting nextcloud. - -When stopping a jail, any jail that "depends" on it will first be stopped. -For example, if we run ``bastille stop nginx``, then nextcloud will first be -stopped because it "depends" on nginx. - -Note that if we do a ``bastille restart nginx``, however, nextcloud will be -stopped, because it "depends" on nginx, but will not be started again, because -the jail we just restarted, nginx, does not depend on nextcloud. - -Parallel Startup ----------------- - -Bastille supports starting, stopping and restarting jails in parallel mode using -the ``rc`` service script. To enable this functionality, set -``bastille_parallel_limit`` to a numeric value. - -For example, if you run ``sysrc bastille_parallel_limit=4``, then Bastille will -start 4 jails at a time on system startup, as well as stop or restart 4 jails at -a time when ``service bastille...`` is called. - -This value is set to 1 by default, to only start/stop/restart jails one at a time. - -Startup Delay -------------- - -Sometimes it is necessary to let a jail start fully before continuing to the -next jail. - -We can do this with another sysrc value called ``bastille_startup_delay``. -Setting ``bastille_startup_delay=5`` will tell Bastille to wait 5 seconds between -starting each jail. - -You can also use ``bastille start -d|--delay 5 all`` or -``bastille restart -d|--delay 5 all`` to achieve the same thing. diff --git a/docs/chapters/linux-jails.rst b/docs/chapters/linux-jails.rst new file mode 100644 index 00000000..7fd6e245 --- /dev/null +++ b/docs/chapters/linux-jails.rst @@ -0,0 +1,34 @@ +Linux Jails +=========== + +Bastille can create Linux jails using the ``debootstrap`` tool. When +attempting to create a Linux jail, Bastille will need to load some modules +as well as install the ``debootstrap`` package. + +Getting Started +--------------- + +To get started, run ``bastille setup linux`` to load required modules +and install the ``debootstrap`` package. + +Bootstrapping a Linux Release +----------------------------- + +To bootstrap a Linux release, run ``bastille bootstrap bionic`` or +whichever release you want to bootstrap. Once bootstrapped, we can +use the ``--linux|-L`` option to create a Linux jail. + +Creating a Linux Jail +--------------------- + +To create a Linux jail, run ``bastille create -L mylinuxjail bionic 10.1.1.3``. +This will create and initialize your jail using the ``debootstrap`` tool. + +Once the jail is created, proceed to do your "linux stuff". + +Limitations +----------- + +* Linux jails are still considered experimental. + +* Linux jails cannot be created with any type of VNET options. \ No newline at end of file diff --git a/docs/chapters/migration.rst b/docs/chapters/migration.rst index 5055bb9a..610d5416 100644 --- a/docs/chapters/migration.rst +++ b/docs/chapters/migration.rst @@ -88,7 +88,7 @@ for remote systems you can use rsync: rsync -avh /iocage/images/jailname_$(date +%F).* root@10.0.1.10:/usr/local/bastille/backups/ - + Import the iocage backup file (use zip file name) .. code-block:: shell diff --git a/docs/chapters/networking.rst b/docs/chapters/networking.rst index 7f260990..cf40ad9c 100644 --- a/docs/chapters/networking.rst +++ b/docs/chapters/networking.rst @@ -1,43 +1,93 @@ Networking ========== -Host Network Configuration --------------------------- +Bastille is very flexible with its networking options. Below are the supported +networking modes, how they work, and some tips on where you might want to use +each one. -Bastille will automatically add and remove IP addresses to specified interfaces -as jails are started and stopped. Below is an outline of how Bastille handles -different types of jail network configurations. +Bastille also supports VLANs to some extent. See the VLAN section below. -* VNET mode: For VNET jails (``-V``) Bastille will create a bridge +Jail Network Modes +------------------ + +Bastille tries to be flexible in the different network modes it supports. Below +is a breakdown of each network mode, what each one does, as well as some +suggestions as to where you might want to use each one. + +VNET +^^^^ + +* For VNET jails (``-V``) Bastille will create a bridge interface and attach your jail to it. It will be called ``em0bridge`` or whatever your interface is called. This will be used for the host/jail epairs. Bastille will create/destroy these epairs as the jail is started/stopped. -* Bridged VNET mode: For bridged VNET jails (``-B``) you must manually create a +* This mode works best if you want your jail to be in your local network, acting + as a physical device with its own MAC address and IP. + +Bridged VNET +^^^^^^^^^^^^ + +* For bridged VNET jails (``-B``) you must manually create a bridge interface to attach your jail to. Bastille will then create and attach the host/jail epairs to this interface when the jail starts, and remove them\ when it stops. -* Alias mode: For classic/standard jails that use an IP that is accessible +* This mode is identical to `VNET` above, with one exception. The interface it + is attached to is a manually created bridge, as opposed to a regular interface + that is used with `VNET` above. + +Alias/Shared Interface +^^^^^^^^^^^^^^^^^^^^^^ + +* For classic/standard jails that use an IP that is accessible within your local subnet (alias mode) Bastille will add the IP to the specified interface as an alias. -* NAT mode: For classic/standard jails that use an IP not reachable in your local +* This mode is best used if you have one interface, and don't want the jail to + have its own MAC address. The jail IP will simply be added to the specified + interface as an additional IP, and will inherit the rest of the interface. + +* Note that this mode does not function as the two `VNET` modes above, but still + allows the jail to have an IP address inside your local network. + +NAT/Loopback Interface +^^^^^^^^^^^^^^^^^^^^^^ + +* For classic/standard jails that use an IP not reachable in your local subnet, Bastille will add the IP to the specified interface as an alias, and additionally, add it to the pf firewall table (if available) to allow the jail outbound access. If you do not specify an interface, Bastille will assume you have run the ``bastille setup`` command and will attempt to use ``bastille0`` - (which is created using the setup command) as its interface. If you have not run - ``bastille setup`` and do not specify an interface, Bastille will error. + (which is created using the setup command) as its interface. If you have not + run ``bastille setup`` and do not specify an interface, Bastille will error. -* Inherit mode: For classic/standard jails that are set to ``inherit`` or +* This mode works best if you want your jail to be in its own private network. + Bastille will dynamically add each jail IP to the firewall table to ensure + network connectivity. + +* This mode is similar to the Alias/Shared Interface mode, except that it is not + limited to IP addresses within your local network. + +Inherit +^^^^^^^ + +* For classic/standard jails that are set to ``inherit`` or ``ip_hostname``, bastille will simply set ``ip4`` to ``inherit`` inside the jail config. The jail will then function according the jail(8) documentation. -* ip_hostname mode: For classic/standard jails that are set to ``ip_hostname``, +* This mode makes the jail inherit the entire network stack of the host. + +IP Hostname +^^^^^^^^^^^ + +* For classic/standard jails that are set to ``ip_hostname``, bastille will simply set ``ip4`` to ``ip_hostname`` inside the jail config. The jail will then function according the jail(8) documentation. +* This is an advanced parameter. See the official FreeBSD jail(8) documentation + for details. + You cannot use ``-V|--vnet`` with any interface that is already a member of another bridge. For example, if you create a bridge, and assign ``vtnet0`` as a member, you will not be able to use ``vtnet0`` with ``-V|--vnet``. @@ -45,7 +95,10 @@ member, you will not be able to use ``vtnet0`` with ``-V|--vnet``. IP Address Options ------------------ -Bastille includes a number of IP options. +IPv4 Network +^^^^^^^^^^^^ + +Bastille includes a number of IP options for IPv4 networking. .. code-block:: shell @@ -54,18 +107,18 @@ Bastille includes a number of IP options. The IP address specified above can be any of the following options. * An IP in your local subnet should be chosen if you create your jail using - ``-V`` or ``-B`` (VNET jail). It is also preferable to add the subnet mask - (/24 or whaterver your subnet is) to the IP. + ``-V``, ``-B`` or ``-P`` (VNET jail). It is also preferable to add the + subnet mask (/24 or whaterver your subnet is) to the IP. * DHCP, SYNCDHCP, or 0.0.0.0 will configure your jail to use DHCP to obtain an - address from your router. This should only be used with ``-V`` and ``-B``. + address from your router. This should only be used with VNET jails. * Any IP address inside the RFC1918 range if you are not using a VNET jail. Bastille will automatically add this IP to the firewall table to allow outbound access. It you want traffic to be forwarded into the jail, you can use the ``bastille rdr`` command. -* Any IP in your local subnet without the ``-V`` or ``-B`` options will add the +* Any IP in your local subnet without any VNET options will add the IP as an alias to the selected interface, which will simply end up sharing the interface. If the IP is in your local subnet, you will not need the ``bastille rdr`` command. Traffic will pass in and out just as in a VNET jail. @@ -81,19 +134,78 @@ Note that jails support specifying an IP without the subnet (/24 or whatever yours is) but we highly recommend setting it, especially on VNET jails. Not doing so can cause issues in some rare cases. +IPv6 Network +^^^^^^^^^^^^ + Bastille also supports IPv6. Instead of an IPv4 address, you can specify an -IPv6 address when creating a jail to use IPv6. It is also possible to use both -by quoting an IPv4 and IPv6 address together as seen in the following example. +IPv6 address when creating a jail to use IPv6. .. code-block:: shell - bastille create alcatraz 13.2-RELEASE "192.168.1.50/24 2001:19f0:6c01:114c:0:100/64" vtnet0 + bastille create alcatraz 13.2-RELEASE 2001:19f0:6c01:114c:0:100/64 vtnet0 -For the ``inherit`` and ``ip_hostname`` options, you can also specify -``-D|--dual`` to use both IPv4 and IPv6 inside the jail. +The IP address specified above can be any of the following options. -Shared Interface ----------------- +* A valid IPv6 address including the subnet. + +* SLAAC will configure your jail to use router advertisement to obtain an + address from your router. This should only be used with VNET jails. + +Dual Stack Network +^^^^^^^^^^^^^^^^^^ + +It is also possible to use both IPv4 and IPv6 by quoting an IPv4 and IPv6 addresses together +as seen in the following examples. + +.. code-block:: shell + + bastille create alcatraz 14.3-RELEASE "192.168.1.50/24 2001:19f0:6c01:114c:0:100/64" vtnet0 + +.. code-block:: shell + + bastille create alcatraz 14.3-RELEASE "DHCP SLAAC" vtnet0 + +Note: For the ``inherit`` and ``ip_hostname`` options, you can also specify +``-D|--dual`` to use both IPv4 and IPv6 inside the jail. Otherwise, for dual +stack networking, simply supply both IPv4 and IPv6 addresses as seen above. + +Networking Limitations +---------------------- + +VNET Jail Interface Names +^^^^^^^^^^^^^^^^^^^^^^^^^ + +* FreeBSD has certain limitations when it comes to interface names. One + of these is that interface names cannot be longer than 15 characters. + Because of this, Bastille uses a generic name for any epairs created + whose corresponding jail name exceeds the maximum length. See below... + + ``e0a_jailname`` and ``e0b_jailname`` are the default epair interfaces for every + jail. The ``e0a`` side is on the host, while the ``e0b`` is in the jail. Due + to the above mentioned limitations, Bastille will name any epairs whose + jail names exceed the maximum length, to ``e0b_bastilleX`` and ``e0b_bastilleX`` + with the ``X`` starting at ``1`` and incrementing by 1 for each new epair. + So, ``mylongjailname`` will be ``e0a_bastille2`` and ``e0b_bastille2``. + +Netgraph and Proxmox VE +^^^^^^^^^^^^^^^^^^^^^^^ + +* When running a FreeBSD VM on Proxmox VE, you might encounter crashes when using + Netraph. This bug is being tracked at + https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=238326 + + One workaround is to add the following line to the ``jail.conf`` file of the affected + jail(s). + +.. code-block:: shell + + exec.prestop += "jng shutdown JAILNAME"; + +Network Scenarios +----------------- + +SOHO (Small Office/Home Office) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This scenario works best when you have just one computer, or a home or small office network that is separated from the rest of the internet by a router. So @@ -102,7 +214,7 @@ you are free to use `_. In this environment, we can create the container, give it a -unique private ip address within our local subnet, and attach +unique private ip address within our local subnet, and attach its ip address to our primary interface. .. code-block:: shell @@ -159,7 +271,7 @@ Your server was assigned the following six section subnet: The `vultr ipv6 subnet calculator `_ -is helpful in making sense of that ipv6 address. +is helpful in making sense of that ipv6 address. We could have also written that IPV6 address as 2001:19f0:6c01:114c:0:0 @@ -182,8 +294,8 @@ Just remember you cannot ping out from the container. Instead, install and use ``wget/curl/fetch`` to test the connectivity. -Virtual Network (VNET) ----------------------- +VNET (Virtual Network) +^^^^^^^^^^^^^^^^^^^^^^ (Added in 0.6.x) VNET is supported on FreeBSD 12+ only. @@ -251,8 +363,8 @@ Below is the definition of what these three parameters are used for and mean: net.link.bridge.pfil_bridge Set to 1 to enable filtering on the bridge interface, set to 0 to disable it. -Bridged Network (VNET bridged) ------------------------------- +Bridged VNET (Virtual Network) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To create a VNET based container and attach it to an external, already existing bridge, use the ``-B`` option, an IP/netmask and external bridge. @@ -311,21 +423,29 @@ on your system is. VLAN Configuration ------------------ +Jail VLAN Tagging +^^^^^^^^^^^^^^^^^ + Bastille supports VLANs to some extent when creating jails. When creating a jail, use the ``--vlan ID`` options to specify a VLAN ID for your jail. This will set the proper variables inside the jails `rc.conf` to add the jail to the specified -VLAN. When using this method, the interface being assigned must carry tagged VLAN -packets, e.g. you can bridge a VLAN trunk to the jail and in the jail you then can -access all VLANs. But be careful: This may have security implications. +VLAN. The jail will then take care of tagging the traffic. Do not use ``-v|--vlan`` +if you have already configured the host interface to tag the traffic. See limitations +below. -You cannot use the ``-V|--vnet`` options with interfaces that have dots (.) in the -name, which is the standard way of naming a VLAN interface. This is due to the -limitations of the JIB script that Bastille uses to manage VNET jails. +When using this method, the interface being assigned must be a trunk interface. +This means that it passes all traffic, leaving any VLAN tags as they are. + +Host VLAN Tagging +^^^^^^^^^^^^^^^^^ + +Another method is to configure a host interface to tag the traffic. This way, the +jail doesn't have to worry about it. + +You can only use ``-B|--bridge`` with host VLAN interfaces, due to the limitation +mentioned below. With this method we create the bridge interfaces in ``rc.conf`` +and configure them to tag the traffic by VLAD ID. -You can however use ``-B|--bridge`` with VLAN interfaces (even with dots in the -name). Using this method you create bridge interfaces in ``rc.conf`` and only -add VLANs that are needed for the jail. The jail only has access to these VLANs -and not to the whole trunk. Below is an ``rc.conf`` snippet that was provided by a user who has such a configuration. @@ -356,6 +476,20 @@ configuration. Notice that the interfaces are bridge interfaces, and can be used with ``-B|--bridge`` without issue. +VLAN Limitations +^^^^^^^^^^^^^^^^ + +* You cannot use the ``-V|--vnet`` options with interfaces that have dots (.) in the + name, which is the standard way of naming a VLAN interface. This is due to the + limitations of the JIB script that Bastille uses to manage VNET jails. + +* Do not attempt to configure both the host and the jail to tag VLAN traffic. + If you use the host method, do not use ``-v|--vlan`` when creating the jail. + Doing so will prevent the jail from having network access. + +Tip: Don't forget to set you gateway and nameserver is applicable +using ``-g|--gateway`` and ``-n|--nameserver``. + Regarding Routes ---------------- @@ -469,7 +603,7 @@ Create the firewall rules: block in all pass out quick keep state antispoof for $ext_if inet - pass in inet proto tcp from any to any port ssh flags S/SA modulate state + pass in proto tcp from any to any port ssh flags S/SA modulate state - Make sure to change the ``ext_if`` variable to match your host system interface. diff --git a/docs/chapters/pkgbase.rst b/docs/chapters/pkgbase.rst new file mode 100644 index 00000000..10fd14da --- /dev/null +++ b/docs/chapters/pkgbase.rst @@ -0,0 +1,61 @@ +Pkgbase +======= + +Pkgbase is the new method for managing the base system on a FreeBSD host +or jail. It is considered experimental for 15.0-RELEASE, but will be +made the default for version 16.0-RELEASE and above. + +Bootstrap +--------- + +To bootstrap a release using pkgbase, run ``bastille bootstrap --pkgbase RELEASE``. +For version 14, it is not supported. For version 15 it is optional, but +for version 16 and above, it is the default method of bootstrapping a release. + +Update +------ + +To update a release created with pkgbase, simply run ``bastille update RELEASE`` as +you would with legacy releases. + +To update a thick jail, run ``bastille update TARGET`` as you would with legacy +releases. + +To update a thin jail, you must update the release that it is based on. + +Upgrade +------- + +Upgrading is not supported for releases. See ``bastille bootstrap RELEASE`` to +bootstrap the required release. + +Upgrading is supported for both thin and thick jails. Thin jails will have their +mount points adjusted, and you will need to run ``bastille etcupdate`` on them +when upgrading from a major release to a newer major release. For example, +15.0-RELEASE to 16.0-RELEASE. + +Converting to Pkgbase +--------------------- + +Thick jails that are running legacy releases will have to be converted to pkgbase +before attempting to upgrade to 16.0-RELEASE. This can be done in two ways. + +1. Enter the jail, fetch the ``pkgbasify`` script, and run it. + +.. code-block:: shell + + fetch https://github.com/FreeBSDFoundation/pkgbasify/raw/refs/heads/main/pkgbasify.lua + chmod +x pkgbasify.lua + ./pkgbasify.lua + +2. Fetch the ``pkgbasify`` script and run it from the host using ``--rootdir``. + +.. code-block:: shell + + fetch https://github.com/FreeBSDFoundation/pkgbasify/raw/refs/heads/main/pkgbasify.lua + chmod +x pkgbasify.lua + ./pkgbasify.lua --rootdir /usr/local/bastille/jails/TARGET/root + +Converting a release to pkgbase can be done the same way, but we recommend simply destroying +and re-bootstrapping it using pkgbase. This will not work if you are running thin jails +based on the release in question. In such a case, follow step 2 above. \ No newline at end of file diff --git a/docs/chapters/subcommands/bootstrap.rst b/docs/chapters/subcommands/bootstrap.rst index 7bfa8cf3..7d49b060 100644 --- a/docs/chapters/subcommands/bootstrap.rst +++ b/docs/chapters/subcommands/bootstrap.rst @@ -101,12 +101,14 @@ Example Tips ^^^^ + See the documentation on templates for more information on how they work and how you can create or customize your own. Templates are a powerful part of Bastille and facilitate full container automation. Notes ^^^^^ + If you don't want to bother with git to use templates you can create them manually on the Bastille system and apply them. @@ -126,4 +128,5 @@ begin applying your template. Options: - -x | --debug Enable debug mode. \ No newline at end of file + -p | --pkgbase Bootstrap using pkgbase (15.0-RELEASE and above). + -x | --debug Enable debug mode. \ No newline at end of file diff --git a/docs/chapters/subcommands/clone.rst b/docs/chapters/subcommands/clone.rst index 614bbfce..34842660 100644 --- a/docs/chapters/subcommands/clone.rst +++ b/docs/chapters/subcommands/clone.rst @@ -3,6 +3,15 @@ clone Clone/duplicate an existing jail to a new jail. +Limitations +----------- + +* When cloning a vnet jail with multiple interfaces, + the default interface will be assigned the IP given + in the command. The rest of the interfaces will have + their network info set to ``ifconfig_inet=""``. This + is to avoid conflicts between the old and new jails. + .. code-block:: shell ishmael ~ # bastille clone help diff --git a/docs/chapters/subcommands/create.rst b/docs/chapters/subcommands/create.rst index 79c6d78f..7d79302c 100644 --- a/docs/chapters/subcommands/create.rst +++ b/docs/chapters/subcommands/create.rst @@ -4,7 +4,7 @@ create Create a jail uning any available bootstrapped release. To create a jail, simply provide a name, bootstrapped release, and IP address. -The format is ``bastille create NAME RELEASE IP [INTERFACE]`` +The format is ``bastille create NAME RELEASE IP [INTERFACE]`` Note that the ``interface`` is optional. Bastille will use the default interface that is configured when running the setup command. See ``bastille setup -l`` or @@ -56,20 +56,21 @@ options. See the below help output. Usage: bastille create [option(s)] NAME RELEASE IP [INTERFACE]" Options: - - -B | --bridge Enable VNET, and attach to a specified, already existing external bridge. - -C | --clone Create a clone jail. - -D | --dual Create jail with both IPv4 and IPv6 networking ('inherit' and 'ip_hostname' only). - -E | --empty Create an empty container, intended for custom jail builds (thin/thick/linux or unsupported). - -g | --gateway IP Specify a default router/gateway for the jail. - -L | --linux Create a Linux jail (experimental). - -M | --static-mac Generate a static MAC address for jail (VNET only). - -n | --nameserver IP,IP Specify nameserver(s) for the jail. Comma separated. - --no-validate Do not validate the release when creating the jail. - --no-boot Create jail with boot=off. - -p | --priority VALUE Set priority value for jail. - -T | --thick Creates a thick container, they consume more space as they are self contained and independent. - -V | --vnet Enable VNET, and attach to an existing, physical interface. - -v | --vlan VLANID Creates the jail with specified VLAN ID (VNET only). - -x | --debug Enable debug mode. - -Z | --zfs-opts zfs,options Comma separated list of ZFS options to create the jail with. This overrides the defaults. + + -B | --bridge Enable VNET, and attach to a specified, already existing external bridge. + -C | --clone Create a clone jail. + -D | --dual Create jail with both IPv4 and IPv6 networking ('inherit' and 'ip_hostname' only). + -E | --empty Create an empty container, intended for custom jail builds (thin/thick/linux or unsupported). + -g | --gateway IP Specify a default router/gateway for the jail. + -L | --linux Create a Linux jail (experimental). + -M | --static-mac Generate a static MAC address for jail (VNET only). + -n | --nameserver IP,IP Specify nameserver(s) for the jail. Comma separated. + --no-validate Do not validate the release when creating the jail. + --no-boot Create jail with boot=off. + -P | --passthrough Enable VNET, and pass the specified interface into the jail. + -p | --priority VALUE Set priority value for jail. + -T | --thick Creates a thick container, they consume more space as they are self contained and independent. + -V | --vnet Enable VNET, and attach to an existing, physical interface. + -v | --vlan VLANID Creates the jail with specified VLAN ID (VNET only). + -x | --debug Enable debug mode. + -Z | --zfs-opts zfs,options Comma separated list of ZFS options to create the jail with. This overrides the defaults. diff --git a/docs/chapters/subcommands/etcupdate.rst b/docs/chapters/subcommands/etcupdate.rst index dbaa7c76..cd9760bd 100644 --- a/docs/chapters/subcommands/etcupdate.rst +++ b/docs/chapters/subcommands/etcupdate.rst @@ -25,7 +25,7 @@ Next we can use the ``update`` command to apply the update to the jail. The output will show you which files were added, updated, changed, deleted, or have conflicts. To automatically resolve the conflicts, run the ``resolve`` command. - + .. code-block:: shell ishmael ~ # bastille etcupdate ishmael resolve diff --git a/docs/chapters/subcommands/export.rst b/docs/chapters/subcommands/export.rst index 873db8a7..abbbeac8 100644 --- a/docs/chapters/subcommands/export.rst +++ b/docs/chapters/subcommands/export.rst @@ -26,14 +26,16 @@ Available options are: Options: - -a | --auto Auto mode. Start/stop jail(s) if required. - --gz Export a ZFS jail using GZIP(.gz) compressed image. - -r | --raw Export a ZFS jail to an uncompressed RAW image. - -s | --safe Safely stop and start a ZFS jail before the exporting process. - --tgz Export a jail using simple .tgz compressed archive instead. - --txz Export a jail using simple .txz compressed archive instead. - -v | --verbose Be more verbose during the ZFS send operation. - --xz Export a ZFS jail using XZ(.xz) compressed image. - -x | --debug Enable debug mode. + -a | --auto Auto mode. Start/stop jail(s) if required. + -l | --live Export a running jail (ZFS only). + --gz Export to '.gz' compressed image (ZFS only). + --xz Export to a '.xz' compressed image (ZFS only). + --zst Export to a .zst compressed image (ZFS only). + --raw Export to an uncompressed RAW image (ZFS only). + --tgz Export to a '.tgz' compressed archive. + --txz Export to a '.txz' compressed archive. + --tzst Export to a '.tzst' compressed archive. + -v | --verbose Enable verbose mode (ZFS only). + -x | --debug Enable debug mode. - Note: If no export option specified, the container should be redirected to standard output. + Note: If no export option specified, the container should be redirected to standard output. diff --git a/docs/chapters/subcommands/import.rst b/docs/chapters/subcommands/import.rst index 0fed6b2f..cc2fa504 100644 --- a/docs/chapters/subcommands/import.rst +++ b/docs/chapters/subcommands/import.rst @@ -19,9 +19,9 @@ To import to a specified release, specify it as the last argument. Options: - -f | --force Force an archive import regardless if the checksum file does not match or missing. - -M | --static-mac Generate static MAC for jail when importing foreign jails like iocage. - -v | --verbose Be more verbose during the ZFS receive operation. - -x | --debug Enable debug mode. + -f | --force Force an archive import regardless if the checksum file does not match or missing. + -M | --static-mac Generate static MAC for jail when importing foreign jails like iocage. + -v | --verbose Enable verbose mode (ZFS only). + -x | --debug Enable debug mode. - Tip: If no option specified, container should be imported from standard input. \ No newline at end of file + Tip: If no option specified, container should be imported from standard input. \ No newline at end of file diff --git a/docs/chapters/subcommands/limits.rst b/docs/chapters/subcommands/limits.rst index 6d9c14b1..b4e0ddbe 100644 --- a/docs/chapters/subcommands/limits.rst +++ b/docs/chapters/subcommands/limits.rst @@ -44,7 +44,7 @@ This file can be edited manually using ``bastille edit TARGET cpuset.conf``. ishmael ~ # bastille limits help Usage: bastille limits [option(s)] TARGET [add|remove|clear|reset|(list|show [active])|stats] OPTION [VALUE] - + Example: bastille limits TARGET add memoryuse 1G Example: bastille limits TARGET add cpu 0,1,2 @@ -52,4 +52,4 @@ This file can be edited manually using ``bastille edit TARGET cpuset.conf``. -a | --auto Auto mode. Start/stop jail(s) if required. -l | --log Enable logging for the specified rule (rctl only). - -x | --debug Enable debug mode. + -x | --debug Enable debug mode. diff --git a/docs/chapters/subcommands/list.rst b/docs/chapters/subcommands/list.rst index fa1c4074..560a9fe7 100644 --- a/docs/chapters/subcommands/list.rst +++ b/docs/chapters/subcommands/list.rst @@ -16,7 +16,7 @@ Use ``-p|--pretty`` to print in columns instead of rows. Usage: bastille list [option(s)] [RELEASE (-p)] [all] [backup(s)] [export(s)] [import(s)] [ip(s)] [jail(s)] [limit(s)] [log(s)] [path(s)] [port(s)] [prio|priority] [release(s)] [state(s)] [template(s)] [type] Options: - + -d | --down List stopped jails only. -j | --json List jails or sub-arg(s) in json format. -p | --pretty Print JSON in columns. Must be used with -j|--json. diff --git a/docs/chapters/subcommands/migrate.rst b/docs/chapters/subcommands/migrate.rst index 1666383d..f38e8bd3 100644 --- a/docs/chapters/subcommands/migrate.rst +++ b/docs/chapters/subcommands/migrate.rst @@ -1,7 +1,7 @@ migrate ======= -The ``migrate`` sub-command allows migrating the targeted jail(s) to +The ``migrate`` sub-command allows migrating the targeted jail(s) to another remote system. See the chapter on Migration. This sub-command supports multiple targets. @@ -13,18 +13,20 @@ port by supplying it as in ``user@host:port``. ishmael ~ # bastille migrate help Usage: bastille migrate [option(s)] TARGET USER@HOST[:PORT] - + Examples: bastille migrate attica migrate@192.168.10.100 bastille migrate attica migrate@192.168.1.10:20022 + bastille migrate --keyfile id_rsa attica migrate@192.168.1.10 Options: - -a | --auto Auto mode. Start/stop jail(s) if required. - -d | --destroy Destroy local jail after migration. - -b | --backup Retain archives on remote system. - | --doas Use 'doas' instead of 'sudo'. - -l | --live Migrate a running jail (ZFS only). - -p | --password Use password based authentication. - -x | --debug Enable debug mode. \ No newline at end of file + -a | --auto Auto mode. Start/stop jail(s) if required. + -b | --backup Retain archives on remote system. + -d | --destroy Destroy local jail after migration. + | --doas Use 'doas' instead of 'sudo'. + -k | --keyfile Specify an alternative private keyfile name. Must be in '~/.ssh' + -l | --live Migrate a running jail (ZFS only). + -p | --password Use password based authentication. + -x | --debug Enable debug mode. \ No newline at end of file diff --git a/docs/chapters/subcommands/mount.rst b/docs/chapters/subcommands/mount.rst index dd5bf73b..2120fd27 100644 --- a/docs/chapters/subcommands/mount.rst +++ b/docs/chapters/subcommands/mount.rst @@ -63,7 +63,7 @@ It is possible to do the same for the jail path, but again, not recommemded. ishmael ~ # bastille mount azkaban "/storage/my\ directory\ with\ spaces" /media/foo nullfs ro 0 0 [azkaban]: Added: /storage/my\040directory\040with\040spaces /usr/local/bastille/jails/azkaban/root/media/foo nullfs ro 0 0 - + .. code-block:: shell ishmael ~ # bastille mount help diff --git a/docs/chapters/subcommands/network.rst b/docs/chapters/subcommands/network.rst index a31f1892..316a7822 100644 --- a/docs/chapters/subcommands/network.rst +++ b/docs/chapters/subcommands/network.rst @@ -40,11 +40,11 @@ network TARGET remove INTERFACE`` while both jails are stopped. Options: - -a | --auto Start/stop jail(s) if required. - -B | --bridge Add a bridge VNET interface. - -M | --static-mac Generate a static MAC address for the interface (VNET only). - -n | --no-ip Create interface without an IP (VNET only). - -P | --passthrough Add a raw interface. - -V | --vnet Add a VNET interface. - -v | --vlan VLANID Assign VLAN ID to interface (VNET only). - -x | --debug Enable debug mode. \ No newline at end of file + -a | --auto Start/stop jail(s) if required. + -B | --bridge Add a bridge VNET interface. + -M | --static-mac Generate a static MAC address for the interface (VNET only). + -n | --no-ip Create interface without an IP (VNET only). + -P | --passthrough Add a raw interface. + -V | --vnet Add a VNET interface. + -v | --vlan VLANID Assign VLAN ID to interface (VNET only). + -x | --debug Enable debug mode. \ No newline at end of file diff --git a/docs/chapters/subcommands/rdr.rst b/docs/chapters/subcommands/rdr.rst index 3874d63f..0f78df00 100644 --- a/docs/chapters/subcommands/rdr.rst +++ b/docs/chapters/subcommands/rdr.rst @@ -11,22 +11,22 @@ interfaces as this will include the jail interface - you should specify the interface they run on in rc.conf (or other config files) .. code-block:: shell - + # bastille rdr dev1 tcp 2001 22 [jail1]: IPv4 tcp/2001:22 on em0 - + # bastille rdr dev1 list rdr on em0 inet proto tcp from any to any port = 2001 -> 10.17.89.1 port 22 - + # bastille rdr dev1 udp 2053 53 [jail1]: IPv4 udp/2053:53 on em0 - + # bastille rdr dev1 list rdr pass on em0 inet proto tcp from any to any port = 2001 -> 10.17.89.1 port 22 rdr pass on em0 inet proto udp from any to any port = 2053 -> 10.17.89.1 port 53 - + # bastille rdr dev1 clear nat cleared @@ -34,17 +34,18 @@ The ``rdr`` command includes 4 additional options: .. code-block:: shell - -d | --destination [destination] Limit rdr to a destination IP. Useful if you have multiple IPs on one interface. - -i | --interface [interface] Set the interface to create the rdr rule on. Useful if you have multiple interfaces. - -s | --source [source] Limit rdr to a source IP or table. Useful to only allow access from certain sources. - -t | --type [ipv4|ipv6] Specify IP type. Must be used if -s or -d are used. Defaults to both. + -d | --destination IP Limit rdr to a destination IP. Useful if you have multiple IPs on one interface. + -i | --interface IF,IF Specify interface(s) to apply rule to. Comman separated. + -s | --source IP|table Limit rdr to a source IP or table. + -t | --type ipv4|ipv6 Specify IP type. Must be used if -s or -d are used. Defaults to both. + -x | --debug Enable debug mode. .. code-block:: shell # bastille rdr -i vtnet0 dev1 udp 8000 80 [jail1]: IPv4 tcp/8000:80 on vtnet0 - + # bastille rdr -s 192.168.0.1 dev1 tcp 8080 81 [jail1]: IPv4 tcp/8080:81 on em0 @@ -75,11 +76,11 @@ Simply use the table name instead of an IP address or subnet. # bastille rdr --help Usage: bastille rdr TARGET [option(s)] [clear|reset|list|(tcp|udp host_port jail_port [log ['(' logopts ')'] ] )] - + Options: - -d | --destination [destination] Limit rdr to a destination IP. Useful if you have multiple IPs on one interface. - -i | --interface [interface] Set the interface to create the rdr rule on. Useful if you have multiple interfaces. - -s | --source [source] Limit rdr to a source IP or table. Useful to only allow access from certain sources. - -t | --type [ipv4|ipv6] Specify IP type. Must be used if -s or -d are used. Defaults to both. - -x | --debug Enable debug mode. + -d | --destination IP Limit rdr to a destination IP. Useful if you have multiple IPs on one interface. + -i | --interface IF,IF Specify interface(s) to apply rule to. Comman separated. + -s | --source IP|table Limit rdr to a source IP or table. + -t | --type ipv4|ipv6 Specify IP type. Must be used if -s or -d are used. Defaults to both. + -x | --debug Enable debug mode. diff --git a/docs/chapters/subcommands/restart.rst b/docs/chapters/subcommands/restart.rst index 86e3749b..9079779c 100644 --- a/docs/chapters/subcommands/restart.rst +++ b/docs/chapters/subcommands/restart.rst @@ -3,8 +3,9 @@ restart Restart jail(s). -Bastille will only restart targeted jail(s) if they are running. Jails that -are stopped will not be started. +Bastille will attempt to stop, then start the targetted jail(s). If a jail is +not running, Bastille will still start it. To avoid this, run the restart +command with ``-i|--ignore`` to skip any stopped jail(s). .. code-block:: shell @@ -21,7 +22,8 @@ are stopped will not be started. Options: - -b | --boot Respect jail boot setting. - -d | --delay VALUE Time (seconds) to wait after starting each jail. - -v | --verbose Print every action on jail restart. - -x | --debug Enable debug mode. \ No newline at end of file + -b | --boot Respect jail boot setting. + -d | --delay VALUE Time (seconds) to wait after starting each jail. + -i | --ignore Ignore stopped jails (do not start if stopped). + -v | --verbose Print every action on jail restart. + -x | --debug Enable debug mode. diff --git a/docs/chapters/subcommands/setup.rst b/docs/chapters/subcommands/setup.rst index 92fee0da..70922333 100644 --- a/docs/chapters/subcommands/setup.rst +++ b/docs/chapters/subcommands/setup.rst @@ -2,38 +2,42 @@ setup ===== The ``setup`` sub-command attempts to automatically configure a host system for -Bastille jails. This allows you to configure networking, firewall, storage, vnet -and bridge options for a Bastille host with one command. +Bastille jails. This allows you to configure networking, firewall, storage, and +some additional options for a Bastille host with one command. Options ------- Below is a list of available options that can be used with the ``setup`` command. -.. code-block:: shell +The ``bridge`` options will attempt to configure a bridge interface for use with +bridged VNET (``-B``) jails. - ishmael ~ # bastille setup -h - Usage: bastille setup [option(s)] [bridge] - [loopback] - [pf|firewall] - [shared] - [vnet] - [storage] - - Options: - - -y | --yes Assume always yes on prompts. - -x | --debug Enable debug mode. +The ``linux`` options will attempt to configure your system to run +Linux (``-L|--linux``) jails. This will load some required kernel modules, and +add the to ``/boot/loader.conf``. The ``loopback`` option will configure a loopback interface called ``bastille0`` that will be used as a default when not specifying an interface with the ``create`` command. +The ``netgraph`` option will attempt to configure your system to use ``netgraph`` +as the network mode as opposed to the standard ``if_bridge`` mode. + +The ``pf|firewall`` option will configure the pf firewall by enabling the service +and creating the default ``pf.conf`` file. Once this is done, you can use the +``rdr`` command to forward traffic into a jail. + The ``shared`` option will configure the interface you choose to also be used as the default when not specifying an interface with the ``create`` command. -Please note. You CANNOT run both a loopback and a shared interface with Bastille. -Only one should be configured. If you configure one, it will disable the other. +The ``storage`` option will attempt to configure a pool and dataset for Bastille, +but only if ZFS in enabled on your system. Otherwise it will use UFS. + +The ``vnet`` option will configure your system for use with VNET (``-V``) jails. + +Limitations +----------- The ``loopback`` option is the default, and is enough for most use cases. It is simply an ``lo`` interface that jails will get linked to on creation. It is not @@ -42,37 +46,28 @@ attached to any specific interface. This is the simplest networking option. The is not specified during the ``create`` command. If an interface is specified, these options have no effect. Instead, the specified interface will be used. +Please note. You CANNOT run both a loopback and a shared interface with Bastille. +Only one should be configured. If you configure one, it will disable the other. The ``shared`` option is for cases where you want an actual interface to use with Bastille as opposed to a loopback. Jails will be linked to the shared interface on creation. -The ``pf|firewall`` option will configure the pf firewall by enabling the service -and creating the default ``pf.conf`` file. Once this is done, you can use the -``rdr`` command to forward traffic into a jail. - -The ``storage`` option will attempt to configure a pool and dataset for Bastille, -but only if ZFS in enabled on your system. Otherwise it will use UFS. - -The ``vnet`` option will configure your system for use with VNET ``-V`` jails. - -The ``bridge`` options will attempt to configure a bridge interface for use with -bridged VNET ``-B`` jails. - Running ``bastille setup`` without any options will attempt to auto-configure the -``filesystem``, ``loopback``, ``firewall`` and ``storage`` options. +``loopback``, ``firewall`` and ``storage`` options. .. code-block:: shell ishmael ~ # bastille setup -h Usage: bastille setup [option(s)] [bridge] - [filesystem] + [linux] [loopback] + [netgraph] [pf|firewall] [shared] - [vnet] [storage] + [vnet] Options: - -y | --yes Assume always yes on prompts. - -x | --debug Enable debug mode. + -y | --yes Assume always yes on prompts. + -x | --debug Enable debug mode. diff --git a/docs/chapters/subcommands/template.rst b/docs/chapters/subcommands/template.rst index a5ed1cc5..507e8694 100644 --- a/docs/chapters/subcommands/template.rst +++ b/docs/chapters/subcommands/template.rst @@ -18,7 +18,7 @@ The TEMPLATE arg should be called with the ``project/template`` format. ishmael ~ # bastille template help Usage: bastille template [option(s)] TARGET [--convert] TEMPLATE - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. diff --git a/docs/chapters/subcommands/verify.rst b/docs/chapters/subcommands/verify.rst index de5cb3d4..25501147 100644 --- a/docs/chapters/subcommands/verify.rst +++ b/docs/chapters/subcommands/verify.rst @@ -23,7 +23,7 @@ release or template . Detected Bastillefile hook. [Bastillefile]: CMD mkdir -p /usr/local/etc/pkg/repos - CMD echo 'FreeBSD: { url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest" }' > + CMD echo 'FreeBSD: { url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest" }' > /usr/local/etc/pkg/repos/FreeBSD.conf CONFIG set allow.mlock=1; CONFIG set ip6=inherit; diff --git a/docs/chapters/subcommands/zfs.rst b/docs/chapters/subcommands/zfs.rst index dc7a8c62..f0726c71 100644 --- a/docs/chapters/subcommands/zfs.rst +++ b/docs/chapters/subcommands/zfs.rst @@ -1,20 +1,22 @@ zfs === -Manage ZFS properties, create, destroy and rollback snapshots, jail and unjail datasets (ZFS only), -and check ZFS usage for targeted jail(s). +Manage ZFS properties, create, destroy and rollback snapshots, jail and unjail +datasets (ZFS only), and check ZFS usage for targeted jail(s). Snapshot Management ------------------- -Bastille has the ability to create, destroy, and rollback snapshots when using ZFS. To create a snapshot, -run ``bastille zfs TARGET snapshot``. This will create a snapshot with the default ``bastille_TARGET_DATE`` -naming scheme. You can also specify a TAG to use as the naming scheme, such as ``bastille zfs TARGET snapshot mytag``. +Bastille has the ability to create, destroy, and rollback snapshots when using +ZFS. To create a snapshot, run ``bastille zfs TARGET snapshot``. This will create +a snapshot with the default ``bastille_TARGET_DATE`` naming scheme. You can also +specify a TAG to use as the naming scheme, such as ``bastille zfs TARGET snapshot mytag``. Bastille will then create the snapshot with ``@mytag`` as the snapshot name. -Rolling back a snapshot follows the same syntax. If no TAG is supplied, Bastille will attempt to use the -most recent snapshot following the default naming scheme above. To rollback a snapshot with a custom tag, run -``bastille zfs TARGET rollback`` or ``bastille zfs TARGET rollback mytag``. +Rolling back a snapshot follows the same syntax. If no TAG is supplied, Bastille +will attempt to use the most recent snapshot following the default naming scheme +above. To rollback a snapshot with a custom tag, run ``bastille zfs TARGET rollback`` +or ``bastille zfs TARGET rollback mytag``. To destroy a snaphot however, you must supply a TAG. To destroy a snapshot, run ``bastille zfs TARGET destroy mytag``. @@ -32,4 +34,4 @@ To destroy a snaphot however, you must supply a TAG. To destroy a snapshot, run -a | --auto Auto mode. Start/stop jail(s) if required. -v | --verbose Enable verbose mode. - -x | --debug Enable debug mode. \ No newline at end of file + -x | --debug Enable debug mode. diff --git a/docs/chapters/targeting.rst b/docs/chapters/targeting.rst index cab9c518..5efa7ab7 100644 --- a/docs/chapters/targeting.rst +++ b/docs/chapters/targeting.rst @@ -2,21 +2,20 @@ Targeting ========= Bastille uses a ``subcommand TARGET ARGS`` syntax, meaning that each command -requires a target. Targets are usually containers, but can also be releases. +requires a target. Targets are usually jails, but can also be releases. -Targeting a container is done by providing the exact jail name, the JID of the -jail, a tag, or by typing the starting few characters of a jail. If more than one -matching jail is found, you will see an error saying so. +Targeting a jail is done by providing the exact jail name, the JID of the +jail, a tag, or by typing the starting few characters of a jail. -If you use a tag as the TARGET, Bastille will target any and all jail(s) that have -the tag assigned. If you have a jail with the same name as the tag you are trying to +If you use a tag as the TARGET, Bastille will target any and all jails that have +that tag assigned. If you have a jail with the same name as the tag you are trying to target, Bastille will target the jail, and not the tag. Targeting a release is done by providing the exact release name. (Note: do not include the ``-pX`` point-release version.) -Bastille includes a pre-defined keyword [ALL|all] to target all running -containers. It is also possible to target multiple jails by grouping them in +Bastille includes a pre-defined keyword of [ALL|all] to target all running +jails. It is also possible to target multiple jails by grouping them in quotes, as seen below. .. code-block:: shell @@ -27,7 +26,7 @@ Priority -------- The priority value determines in what order commands are executed if multiple -jails are targetted, including the ALL target. +jails are targetted, including the [ALL|all] target. It also controls in what order jails are started and stopped on system startup and shutdown. This requires Bastille to be enabled with ``sysrc bastille_enable=YES``. @@ -43,21 +42,8 @@ This value can be changed using ``bastille config TARGET set priority VALUE``. This value will be shown using ``bastille list all``. -Parallel Mode -------------- - -Any command that supports multiple targets, also supports parallel mode. This -means that Bastille will run the command on multiple jails at a single time, -depending on the value given. - -To use parallel mode, run ``bastille -p 4 pkg ALL update``, for example, to start -updating packages in all jails, 4 processes at a time. - -Note that the ``-p`` option should follow the main ``bastille`` command, and not -the sub-command. - -Examples: Containers --------------------- +Examples: Jails +--------------- .. code-block:: shell @@ -66,25 +52,25 @@ Examples: Containers +-----------+--------+------------------+-------------------------------------------------------------+ | command | target | args | description | +===========+========+==================+=============================================================+ -| cmd | ALL | 'sockstat -4' | execute `sockstat -4` in ALL containers (ip4 sockets) | +| cmd | ALL | 'sockstat -4' | execute `sockstat -4` in ALL jails (ip4 sockets) | +-----------+--------+-----+------------+-------------------------------------------------------------+ | console | mariadb02 | --- | console (shell) access to mariadb02 | +----+------+--------+-----+------------+-------------------------------------------------------------+ -| pkg | web01 | 'install nginx' | install nginx package in web01 container | +| pkg | web01 | 'install nginx' | install nginx package in web01 jail | +-----------+--------+------------------+-------------------------------------------------------------+ -| pkg | ALL | upgrade | upgrade packages in ALL containers | +| pkg | ALL | upgrade | upgrade packages in ALL jails | +-----------+--------+------------------+-------------------------------------------------------------+ -| pkg | ALL | audit | (CVE) audit packages in ALL containers | +| pkg | ALL | audit | (CVE) audit packages in ALL jails | +-----------+--------+------------------+-------------------------------------------------------------+ -| sysrc | web01 | nginx_enable=YES | execute `sysrc nginx_enable=YES` in web01 container | +| sysrc | web01 | nginx_enable=YES | execute `sysrc nginx_enable=YES` in web01 jail | +-----------+--------+------------------+-------------------------------------------------------------+ -| template | ALL | username/base | apply `username/base` template to ALL containers | +| template | ALL | username/base | apply `username/base` template to ALL jails | +-----------+--------+------------------+-------------------------------------------------------------+ -| start | web02 | --- | start web02 container | +| start | web02 | --- | start web02 jail | +----+------+----+---+------------------+--------------+----------------------------------------------+ -| cp | bastion03 | /tmp/resolv.conf-cf etc/resolv.conf | copy host-path to container-path in bastion03| +| cp | bastion03 | /tmp/resolv.conf-cf etc/resolv.conf | copy host-path to jail-path in bastion03 | +----+------+----+---+---------------------------------+----------------------------------------------+ -| create | folsom | 13.2-RELEASE 10.17.89.10 | create 13.2 container named `folsom` with IP | +| create | folsom | 13.2-RELEASE 10.17.89.10 | create 13.2 jail named `folsom` with IP | +-----------+--------+---------------------------------+----------------------------------------------+ diff --git a/docs/chapters/template.rst b/docs/chapters/template.rst index 6be4cd4f..38a5801a 100644 --- a/docs/chapters/template.rst +++ b/docs/chapters/template.rst @@ -132,7 +132,7 @@ escape it. Escaping it will cause errors. Bootstrapping Templates ----------------------- -The official templates for Bastille are all on Gthub, and mirror the directory +The official templates for Bastille are all on Gthub, and mirror the directory structure of the ports tree. So, ``nginx`` is in the ``www`` directory in the templates, just like it is in the FreeBSD ports tree. To bootstrap the entire set of official predefined templates run the following command: @@ -155,7 +155,7 @@ Creating Templates Templates can be created and placed inside the templates directory in the ``project/template`` format. Alternatively you can run the ``bastille template`` command from a relative path, making sure it is still in the above format. - + Template Examples ----------------- @@ -250,7 +250,7 @@ directory names in the ``bastille/templates`` directory. chsh: user information updated Template Complete. -.. _Bastille Templates: https://gitlab.com/BastilleBSD-Templates +.. _Bastille Templates: https://github.com/BastilleBSD/templates Using Ports in Templates ------------------------ diff --git a/docs/chapters/upgrading.rst b/docs/chapters/upgrading.rst index 5a3ba02f..a8e7544c 100644 --- a/docs/chapters/upgrading.rst +++ b/docs/chapters/upgrading.rst @@ -12,26 +12,25 @@ To keep releases updated, use ``bastille update RELEASE`` To keep thick jails updated, use ``bastille update TARGET`` ----------------------- -Minor Release Upgrades ----------------------- +Minor Release Upgrades - Legacy +------------------------------- -To upgrade Bastille jails for a minor release (ie; 13.1→13.2) you can do the +To upgrade Bastille jails for a minor release (ie; 13.1 > 13.2) you can do the following: Thick Jails ------------ +^^^^^^^^^^^ 1. Use ``bastille upgrade TARGET 13.2-RELEASE`` to upgrade the jail to 13.2-RELEASE -2. Use ``bastille upgrade TARGET 13.2-RELEASE update`` to apply the updates +2. Use ``bastille upgrade TARGET 13.2-RELEASE install`` to apply the updates 3. Reboot the jail ``bastille restart TARGET`` -4. Use ``bastille upgrade TARGET 13.2-RELEASE update`` to finish applying the +4. Use ``bastille upgrade TARGET 13.2-RELEASE install`` to finish applying the upgrade 5. Upgrade complete! Thin Jails ----------- +^^^^^^^^^^ 1. Ensure the new release version is bootstrapped: ``bastille bootstrap 13.2-RELEASE`` 2. Update the release (optional): ``bastille update 13.2-RELEASE`` @@ -40,31 +39,29 @@ Thin Jails 5. Start the jail(s) 6. Upgrade complete! ----------------------- -Major Release Upgrades ----------------------- +Major Release Upgrades - Legacy +------------------------------- -To upgrade Bastille jails for a major release (ie; 12.4→13.2) you can do the +To upgrade Bastille jails for a major release (ie; 12.4 > 13.2) you can do the following: Thick Jails ------------ +^^^^^^^^^^^ 1. Use ``bastille upgrade TARGET 13.2-RELEASE`` to upgrade the jail to 13.2-RELEASE -2. Use ``bastille upgrade TARGET 13.2-RELEASE update`` to apply the updates +2. Use ``bastille upgrade TARGET 13.2-RELEASE install`` to apply the updates 3. Reboot the jail ``bastille restart TARGET`` -4. Use ``bastille upgrade TARGET 13.2-RELEASE update`` to finish applying the +4. Use ``bastille upgrade TARGET 13.2-RELEASE install`` to finish applying the upgrade 5. Force the reinstallation or upgrade of all installed packages (ABI change): ``pkg upgrade -f`` within each jail (or ``bastille pkg ALL upgrade -f``) 6. Upgrade complete! Thin Jails ----------- +^^^^^^^^^^ -1. Ensure the new release version is bootstrapped and updated to the latest - patch release: ``bastille bootstrap 13.2-RELEASE`` +1. Ensure the new release version is bootstrapped: ``bastille bootstrap 13.2-RELEASE`` 2. Update the release: ``bastille update 13.2-RELEASE`` 3. Stop the jail(s) that need to be updated. 4. Use ``bastille upgrade TARGET 13.2-RELEASE`` to automatically change the @@ -79,28 +76,102 @@ Thin Jails ``pkg upgrade -f`` within each jail (or ``bastille pkg ALL upgrade -f``) 10. Upgrade complete! ----------------------------------- +Minor Release Upgrades - Pkgbase +-------------------------------- + +To upgrade Bastille jails for a minor release (ie; 15.1 > 15.2) you can do the +following: + +Thick Jails +^^^^^^^^^^^ + +1. Use ``bastille upgrade TARGET 15.2-RELEASE`` to upgrade the jail to + 15.2-RELEASE +2. Reboot the jail ``bastille restart TARGET`` +3. Upgrade complete! + +Thin Jails +^^^^^^^^^^ + +1. Ensure the new release version is bootstrapped: ``bastille bootstrap --pkgbase 15.2-RELEASE`` +2. Update the release (optional): ``bastille update 15.2-RELEASE`` +3. Stop the jail(s) that need to be updated. +4. Use ``bastille upgrade TARGET 15.2-RELEASE`` to automatically change the mount points to 15.2-RELEASE +5. Start the jail(s) +6. Upgrade complete! + +Major Release Upgrades - Pkgbase +-------------------------------- + +To upgrade Bastille jails for a major release (ie; 15.5 > 16.0) you can do the +following: + +Thick Jails +^^^^^^^^^^^ + +1. Use ``bastille upgrade TARGET 16.0-RELEASE`` to upgrade the jail to + 16.0-RELEASE +2. Reboot the jail ``bastille restart TARGET`` +3. Force the reinstallation or upgrade of all installed packages (ABI change): + ``pkg upgrade -f`` within each jail (or ``bastille pkg ALL upgrade -f``) +4. Upgrade complete! + +Thin Jails +^^^^^^^^^^ + +1. Ensure the new release version is bootstrapped: ``bastille bootstrap 16.0-RELEASE`` +2. Update the release: ``bastille update 16.0-RELEASE`` +3. Stop the jail(s) that need to be updated. +4. Use ``bastille upgrade TARGET 16.0-RELEASE`` to automatically change the + mount points to 16.0-RELEASE +5. Use ``bastille etcupdate bootstrap 16.0-RELEASE`` to bootstrap src for + 16.0-RELEASE +6. Use ``bastille etcupdate TARGET update 16.0-RELEASE`` to update the contents + of /etc for 16.0-RELEASE +7. Use ``bastille etcupdate TARGET resolve`` to resolve any conflicts +8. Start the jail(s) +9. Force the reinstallation or upgrade of all installed packages (ABI change): + ``pkg upgrade -f`` within each jail (or ``bastille pkg ALL upgrade -f``) +10. Upgrade complete! + +Updating +-------- + +To keep jails updated with the latest security patches and base, +use the ``bastille update`` command. + +Thick Jails +^^^^^^^^^^^ + +Use ``bastille update TARGET`` to update the jail with the latest +patches and security updates. + +Thin Jails +^^^^^^^^^^ + +Use ``bastille update RELEASE`` to update the release that any thin jails +are based on with the latest patches and security updates. + Revert Upgrade / Downgrade Process ---------------------------------- -The downgrade process (not usually needed) is similar to the upgrade process +The downgrade process (not usually needed) is similar to the upgrade process, only in reverse. Thick Jails ------------ +^^^^^^^^^^^ Thick jails should not be downgraded and is not supported in general on FreeBSD. Thin Jails ----------- +^^^^^^^^^^ Not recommended, but you can run ``bastille upgrade TARGET 13.1-RELEASE`` to downgrade a thin jail. Make sure to run ``bastille etcupdate TARGET update 13.1-RELEASE`` to keep the contents of /etc updated with each release. -The pkg reinstallation will also need to be repeated after the jail restarts on +The pkg re-installation will also need to be repeated after the jail restarts on the previous release. ------------- Old Releases ------------ @@ -108,10 +179,10 @@ After upgrading all jails from one release to the next you may find that you now have bootstrapped a release that is no longer used. Once you've decided that you no longer need the option to revert the change you can destroy the old release. - ``bastille list releases`` to list all bootstrapped releases. ``bastille destroy X.Y-RELEASE`` to fully delete the release, including the -cache. +cache (cache is not used with pkgbase). -``bastille destroy [-c|--no-cache] X.Y-RELEASE`` to retain the cache directory. +``bastille destroy -c|--no-cache X.Y-RELEASE`` to retain the cache directory +(not supported when using pkgbase). diff --git a/docs/chapters/usage.rst b/docs/chapters/usage.rst index ace08701..5bfc240b 100644 --- a/docs/chapters/usage.rst +++ b/docs/chapters/usage.rst @@ -36,7 +36,7 @@ Usage rcp cp(1) files from a jail to host. rdr Redirect host port to jail port. rename Rename a jail. - restart Restart a running jail. + restart Restart a jail. service Manage services within targeted jail(s). setup Attempt to auto-configure network, firewall and storage and more... start Start a stopped jail. @@ -54,4 +54,3 @@ Usage Use "bastille -v|--version" for version information. Use "bastille command -h|--help" for more information about a command. Use "bastille -c|--config config.conf command" to specify a non-default config file. - Use "bastille -p|--parallel VALUE command" to run bastille in parallel mode. diff --git a/docs/chapters/zfs-support.rst b/docs/chapters/zfs-support.rst index ca6046c4..2944ac83 100644 --- a/docs/chapters/zfs-support.rst +++ b/docs/chapters/zfs-support.rst @@ -85,8 +85,8 @@ and being able to fully manage it from within the jail. To add a dataset to a jail, we can run ``bastille zfs TARGET jail pool/dataset /path/inside/jail``. -This will mount ``pool/dataset`` into the jail at ``/path/inside/jail`` when the -jail is started, and unmount and unjail it when the jail is stopped. +This will assign ``pool/dataset`` to the jail and mount it +at ``/path/inside/jail``. You can manually change the path where the dataset will be mounted by ``bastille edit TARGET zfs.conf`` and adjusting the path after you have added it, @@ -105,34 +105,5 @@ simple. To remove a dataset from being jailed, we can run ``bastille zfs TARGET unjail pool/dataset``. -Template Approach -^^^^^^^^^^^^^^^^^ - -While it is possible to "jail" a dataset using a template, it is a bit more -"hacky" than the above apporach. -Below is a template that you can use that will add the necessary bits to the -``jail.conf`` file to "jail" a dataset. - -.. code-block:: shell - - ARG JAIL_NAME - ARG DATASET - ARG MOUNT - - CONFIG set allow.mount - CONFIG set allow.mount.devfs - CONFIG set allow.mount.zfs - CONFIG set enforce_statfs 1 - - CONFIG set "exec.created += '/sbin/zfs jail ${JAIL_NAME} ${DATASET}'" - CONFIG set "exec.start += '/sbin/zfs set mountpoint=${MOUNT} ${DATASET}'" - - RESTART - - CONFIG set "exec.prestop += 'jexec -l -U root ${JAIL_NAME} /sbin/zfs umount ${DATASET}'" - CONFIG set "exec.prestop += '/sbin/zfs unjail ${JAIL_NAME} ${DATASET}'" - - RESTART - -This template can be applied using ``bastille template TARGET project/template --arg DATASET=zpool/dataset --arg MOUNT=/path/inside/jail``. -We do not need the ``JAIL_NAME`` arg, as it will be auto-filled from the supplied ``TARGET`` name. +NOTE: You must unjail any jailed datasets before attempting to destroy +a jail. diff --git a/docs/conf.py b/docs/conf.py index 68dd29f6..0e56430f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -5,9 +5,9 @@ copyright = '2018-2025, Christer Edwards' author = 'Christer Edwards' # The short X.Y version -version = '1.0.1' +version = '1.2.0' # The full version, including alpha/beta/rc tags -release = '1.0.1.250714' +release = '1.2.0.251201' # -- General configuration --------------------------------------------------- diff --git a/docs/index.rst b/docs/index.rst index da1c60c3..c95b27a7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -11,22 +11,23 @@ https://docs.bastillebsd.org. :maxdepth: 2 :caption: Contents: + chapters/comparing chapters/installation - chapters/gettingstarted + chapters/getting-started chapters/configuration chapters/targeting - chapters/jail-startup-configuration - chapters/networking - chapters/usage - chapters/comparing - chapters/upgrading - chapters/centralized-assets chapters/subcommands/index - chapters/template - chapters/jail-config - chapters/zfs-support + chapters/usage + chapters/networking chapters/gcp + chapters/upgrading chapters/migration + chapters/centralized-assets + chapters/template + chapters/hardened-bsd + chapters/linux-jails + chapters/pkgbase + chapters/zfs-support copyright diff --git a/tests/core/bootstrap-release/Bastillefile b/tests/core/bootstrap-release/Bastillefile new file mode 100644 index 00000000..74d16faf --- /dev/null +++ b/tests/core/bootstrap-release/Bastillefile @@ -0,0 +1,4 @@ +ARG RELEASE +ARG OPTIONS + +CMD bastille bootstrap ${OPTIONS} ${RELEASE} diff --git a/tests/core/bootstrap-template/Bastillefile b/tests/core/bootstrap-template/Bastillefile new file mode 100644 index 00000000..3791e7d0 --- /dev/null +++ b/tests/core/bootstrap-template/Bastillefile @@ -0,0 +1,4 @@ +ARG TEMPLATE_URL +ARG OPTIONS + +CMD bastille bootstrap ${OPTIONS} ${TEMPLATE_URL} diff --git a/tests/core/clone/Bastillefile b/tests/core/clone/Bastillefile new file mode 100644 index 00000000..0fea6cf7 --- /dev/null +++ b/tests/core/clone/Bastillefile @@ -0,0 +1,6 @@ +ARG OPTIONS +ARG JAIL +ARG NEW_JAIL +ARG NEW_IP + +CMD bastille clone ${OPTIONS} ${JAIL} ${NEW_JAIL} ${NEW_IP} diff --git a/tests/core/cmd/Bastillefile b/tests/core/cmd/Bastillefile new file mode 100644 index 00000000..910d8a96 --- /dev/null +++ b/tests/core/cmd/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG ARGS + +CMD bastille cmd ${OPTIONS} ${JAIL} ${ARGS} diff --git a/tests/core/config/Bastillefile b/tests/core/config/Bastillefile new file mode 100644 index 00000000..e4ee43fb --- /dev/null +++ b/tests/core/config/Bastillefile @@ -0,0 +1,7 @@ +ARG OPTIONS +ARG JAIL +ARG ACTION +ARG PROPERTY +ARG VALUE + +CMD bastille config ${OPTIONS} ${JAIL} ${ACTION} ${PROPERTY} ${VALUE} diff --git a/tests/core/console/Bastillefile b/tests/core/console/Bastillefile new file mode 100644 index 00000000..fbeee048 --- /dev/null +++ b/tests/core/console/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG USER + +CMD bastille console ${OPTIONS} ${JAIL} ${USER} diff --git a/tests/core/convert-jail/Bastillefile b/tests/core/convert-jail/Bastillefile new file mode 100644 index 00000000..4a28d4c3 --- /dev/null +++ b/tests/core/convert-jail/Bastillefile @@ -0,0 +1,4 @@ +ARG JAIL +ARG OPTIONS + +CMD bastille convert ${OPTIONS} ${JAIL} diff --git a/tests/core/convert-release/Bastillefile b/tests/core/convert-release/Bastillefile new file mode 100644 index 00000000..790d189c --- /dev/null +++ b/tests/core/convert-release/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG RELEASE + +CMD bastille convert ${OPTIONS} ${JAIL} ${RELEASE} diff --git a/tests/core/cp/Bastillefile b/tests/core/cp/Bastillefile new file mode 100644 index 00000000..f05c8f61 --- /dev/null +++ b/tests/core/cp/Bastillefile @@ -0,0 +1,6 @@ +ARG OPTIONS +ARG JAIL +ARG HOST_PATH +ARG JAIL_PATH + +CMD bastille cp ${OPTIONS} ${JAIL} ${HOST_PATH} ${JAIL_PATH} diff --git a/tests/core/create/Bastillefile b/tests/core/create/Bastillefile new file mode 100644 index 00000000..6efbdf1f --- /dev/null +++ b/tests/core/create/Bastillefile @@ -0,0 +1,7 @@ +ARG OPTIONS +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE + +CMD bastille create ${OPTIONS} ${JAIL} ${RELEASE} ${IP} ${INTERFACE} diff --git a/tests/core/destroy-jail/Bastillefile b/tests/core/destroy-jail/Bastillefile new file mode 100644 index 00000000..64ae1850 --- /dev/null +++ b/tests/core/destroy-jail/Bastillefile @@ -0,0 +1,4 @@ +ARG OPTIONS +ARG JAIL + +CMD bastille destroy ${OPTIONS} ${JAIL} diff --git a/tests/core/destroy-release/Bastillefile b/tests/core/destroy-release/Bastillefile new file mode 100644 index 00000000..d895e012 --- /dev/null +++ b/tests/core/destroy-release/Bastillefile @@ -0,0 +1,6 @@ +# unit-tests/destroy-release + +ARG OPTIONS +ARG RELEASE + +CMD bastille destroy ${OPTIONS} ${RELEASE} diff --git a/tests/core/edit/Bastillefile b/tests/core/edit/Bastillefile new file mode 100644 index 00000000..6392e085 --- /dev/null +++ b/tests/core/edit/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG FILE + +CMD bastille edit ${OPTIONS} ${JAIL} ${FILE} diff --git a/tests/core/etcupdate/Bastillefile b/tests/core/etcupdate/Bastillefile new file mode 100644 index 00000000..7bc1a6ab --- /dev/null +++ b/tests/core/etcupdate/Bastillefile @@ -0,0 +1,6 @@ +ARG OPTIONS +ARG JAIL +ARG ACTION +ARG RELEASE + +CMD bastille etcupdate ${OPTIONS} ${JAIL} ${ACTION} ${RELEASE} diff --git a/tests/core/export/Bastillefile b/tests/core/export/Bastillefile new file mode 100644 index 00000000..4d7f248f --- /dev/null +++ b/tests/core/export/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG PATH + +CMD bastille export ${OPTIONS} ${JAIL} ${PATH} diff --git a/tests/core/htop/Bastillefile b/tests/core/htop/Bastillefile new file mode 100644 index 00000000..1f1d8aa3 --- /dev/null +++ b/tests/core/htop/Bastillefile @@ -0,0 +1,4 @@ +ARG OPTIONS +ARG JAIL + +CMD bastille htop ${OPTIONS} ${JAIL} diff --git a/tests/core/import/Bastillefile b/tests/core/import/Bastillefile new file mode 100644 index 00000000..9ec8025d --- /dev/null +++ b/tests/core/import/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG FILE +ARG RELEASE + +CMD bastille import ${OPTIONS} ${FILE} ${RELEASE} diff --git a/tests/core/jcp/Bastillefile b/tests/core/jcp/Bastillefile new file mode 100644 index 00000000..f0095f74 --- /dev/null +++ b/tests/core/jcp/Bastillefile @@ -0,0 +1,7 @@ +ARG OPTIONS +ARG SOURCE_JAIL +ARG SOURCE_JAIL_PATH +ARG DESTINATION_JAIL +ARG DESTINATION_JAIL_PATH + +CMD bastille jcp ${OPTIONS} ${SOURCE_JAIL} ${SOURCE_JAIL_PATH} ${DESTINATION_JAIL} ${DESTINATION_JAIL_PATH} diff --git a/tests/core/limits/Bastillefile b/tests/core/limits/Bastillefile new file mode 100644 index 00000000..03f87ff4 --- /dev/null +++ b/tests/core/limits/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG ARGS + +CMD bastille limits ${OPTIONS} ${JAIL} ${ARGS} diff --git a/tests/core/list/Bastillefile b/tests/core/list/Bastillefile new file mode 100644 index 00000000..293d4ab6 --- /dev/null +++ b/tests/core/list/Bastillefile @@ -0,0 +1,4 @@ +ARG OPTIONS +ARG ARGS + +CMD bastille list ${OPTIONS} ${ARGS} diff --git a/tests/core/migrate/Bastillefile b/tests/core/migrate/Bastillefile new file mode 100644 index 00000000..4c06ce93 --- /dev/null +++ b/tests/core/migrate/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG HOST + +CMD bastille migrate ${OPTIONS} ${JAIL} ${HOST} diff --git a/tests/core/mount/Bastillefile b/tests/core/mount/Bastillefile new file mode 100644 index 00000000..b29e4a94 --- /dev/null +++ b/tests/core/mount/Bastillefile @@ -0,0 +1,7 @@ +ARG OPTIONS +ARG JAIL +ARG HOST_PATH +ARG JAIL_PATH +ARG ARGS + +CMD bastille mount ${OPTIONS} ${JAIL} ${HOST_PATH} ${JAIL_PATH} ${ARGS} diff --git a/tests/core/network/Bastillefile b/tests/core/network/Bastillefile new file mode 100644 index 00000000..28084b9e --- /dev/null +++ b/tests/core/network/Bastillefile @@ -0,0 +1,7 @@ +ARG OPTIONS +ARG JAIL +ARG ACTION +ARG INTERFACE +ARG IP + +CMD bastille network ${OPTIONS} ${JAIL} ${ACTION} ${INTERFACE} ${IP} diff --git a/tests/core/pkg/Bastillefile b/tests/core/pkg/Bastillefile new file mode 100644 index 00000000..7021f3be --- /dev/null +++ b/tests/core/pkg/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG ARGS + +CMD bastille pkg ${OPTIONS} ${JAIL} ${ARGS} diff --git a/tests/core/rcp/Bastillefile b/tests/core/rcp/Bastillefile new file mode 100644 index 00000000..ee01f767 --- /dev/null +++ b/tests/core/rcp/Bastillefile @@ -0,0 +1,6 @@ +ARG OPTIONS +ARG JAIL +ARG JAIL_PATH +ARG HOST_PATH + +CMD bastille rcp ${OPTIONS} ${JAIL} ${JAIL_PATH} ${HOST_PATH} diff --git a/tests/core/rdr/Bastillefile b/tests/core/rdr/Bastillefile new file mode 100644 index 00000000..67c6cea6 --- /dev/null +++ b/tests/core/rdr/Bastillefile @@ -0,0 +1,9 @@ +ARG OPTIONS +ARG JAIL +ARG ACTION +ARG PROTOCOL +ARG HOST_PORT +ARG JAIL_PORT +ARG LOG + +CMD bastille rdr ${OPTIONS} ${JAIL} ${ACTION} ${PROTOCOL} ${HOST_PORT} ${JAIL_PORT} ${LOG} diff --git a/tests/core/rename/Bastillefile b/tests/core/rename/Bastillefile new file mode 100644 index 00000000..da296544 --- /dev/null +++ b/tests/core/rename/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG NEW_JAIL + +CMD bastille rename ${OPTIONS} ${JAIL} ${NEW_JAIL} diff --git a/tests/core/restart/Bastillefile b/tests/core/restart/Bastillefile new file mode 100644 index 00000000..7aa2926a --- /dev/null +++ b/tests/core/restart/Bastillefile @@ -0,0 +1,4 @@ +ARG OPTIONS +ARG JAIL + +CMD bastille restart ${OPTIONS} ${JAIL} diff --git a/tests/core/service/Bastillefile b/tests/core/service/Bastillefile new file mode 100644 index 00000000..6b2ab50a --- /dev/null +++ b/tests/core/service/Bastillefile @@ -0,0 +1,6 @@ +ARG OPTIONS +ARG JAIL +ARG SERVICE +ARG ARGS + +CMD bastille service ${OPTIONS} ${JAIL} ${SERVICE} ${ARGS} diff --git a/tests/core/setup/Bastillefile b/tests/core/setup/Bastillefile new file mode 100644 index 00000000..928052cf --- /dev/null +++ b/tests/core/setup/Bastillefile @@ -0,0 +1,6 @@ +# core/setup + +ARG OPTIONS +ARG ARGS + +CMD bastille setup ${OPTIONS} ${ARGS} diff --git a/tests/core/start/Bastillefile b/tests/core/start/Bastillefile new file mode 100644 index 00000000..0d0b422f --- /dev/null +++ b/tests/core/start/Bastillefile @@ -0,0 +1,4 @@ +ARG OPTIONS +ARG JAIL + +CMD bastille start ${OPTIONS} ${JAIL} diff --git a/tests/core/stop/Bastillefile b/tests/core/stop/Bastillefile new file mode 100644 index 00000000..4d0e254e --- /dev/null +++ b/tests/core/stop/Bastillefile @@ -0,0 +1,4 @@ +ARG OPTIONS +ARG JAIL + +CMD bastille stop ${OPTIONS} ${JAIL} diff --git a/tests/core/sysrc/Bastillefile b/tests/core/sysrc/Bastillefile new file mode 100644 index 00000000..05808029 --- /dev/null +++ b/tests/core/sysrc/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG ARGS + +CMD bastille sysrc ${OPTIONS} ${JAIL} ${ARGS} diff --git a/tests/core/tags/Bastillefile b/tests/core/tags/Bastillefile new file mode 100644 index 00000000..4a514c46 --- /dev/null +++ b/tests/core/tags/Bastillefile @@ -0,0 +1,6 @@ +ARG OPTIONS +ARG JAIL +ARG ACTION +ARG TAGS + +CMD bastille tags ${OPTIONS} ${JAIL} ${ACTION} ${TAGS} diff --git a/tests/core/template/Bastillefile b/tests/core/template/Bastillefile new file mode 100644 index 00000000..eba83f9a --- /dev/null +++ b/tests/core/template/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG TEMPLATE + +CMD bastille template ${OPTIONS} ${JAIL} ${TEMPLATE} diff --git a/tests/core/top/Bastillefile b/tests/core/top/Bastillefile new file mode 100644 index 00000000..249a34c0 --- /dev/null +++ b/tests/core/top/Bastillefile @@ -0,0 +1,4 @@ +ARG OPTIONS +ARG JAIL + +CMD bastille top ${OPTIONS} ${JAIL} diff --git a/tests/core/umount/Bastillefile b/tests/core/umount/Bastillefile new file mode 100644 index 00000000..393dd673 --- /dev/null +++ b/tests/core/umount/Bastillefile @@ -0,0 +1,5 @@ +ARG OPTIONS +ARG JAIL +ARG JAIL_PATH + +CMD bastille umount ${OPTIONS} ${JAIL} ${JAIL_PATH} diff --git a/tests/core/update/Bastillefile b/tests/core/update/Bastillefile new file mode 100644 index 00000000..24b9a357 --- /dev/null +++ b/tests/core/update/Bastillefile @@ -0,0 +1,4 @@ +ARG OPTIONS +ARG JAIL + +CMD bastille update ${OPTIONS} ${JAIL} diff --git a/tests/core/upgrade/Bastillefile b/tests/core/upgrade/Bastillefile new file mode 100644 index 00000000..8bacd4d9 --- /dev/null +++ b/tests/core/upgrade/Bastillefile @@ -0,0 +1,6 @@ +ARG OPTIONS +ARG JAIL +ARG RELEASE +ARG ARGS + +CMD bastille upgrade ${OPTIONS} ${JAIL} ${RELEASE} ${ARGS} diff --git a/tests/core/verify-release/Bastillefile b/tests/core/verify-release/Bastillefile new file mode 100644 index 00000000..8abd8d6c --- /dev/null +++ b/tests/core/verify-release/Bastillefile @@ -0,0 +1,4 @@ +ARG OPTIONS +ARG RELEASE + +CMD bastille verify ${OPTIONS} ${RELEASE} diff --git a/tests/core/verify-template/Bastillefile b/tests/core/verify-template/Bastillefile new file mode 100644 index 00000000..de52fbb7 --- /dev/null +++ b/tests/core/verify-template/Bastillefile @@ -0,0 +1,4 @@ +ARG OPTIONS +ARG TEMPLATE + +CMD bastille verify ${OPTIONS} ${TEMPLATE} diff --git a/tests/core/zfs/Bastillefile b/tests/core/zfs/Bastillefile new file mode 100644 index 00000000..7a55f9c4 --- /dev/null +++ b/tests/core/zfs/Bastillefile @@ -0,0 +1,6 @@ +ARG OPTIONS +ARG JAIL +ARG ACTION +ARG ARGS + +CMD bastille zfs ${OPTIONS} ${JAIL} ${ACTION} ${ARGS} diff --git a/tests/ufs-tests/init/Bastillefile b/tests/ufs-tests/init/Bastillefile new file mode 100644 index 00000000..d3b954e8 --- /dev/null +++ b/tests/ufs-tests/init/Bastillefile @@ -0,0 +1,45 @@ +# ufs-tests/init + +ARG JAIL=folsom +ARG RELEASE=14.3-RELEASE +ARG IP=10.1.1.1 +ARG INTERFACE=vtnet0 +ARG NEW_INTERFACE=vtnet0 +ARG BRIDGE=vtnet0bridge + +ARG CLONE_NEW_JAIL=attica +ARG CLONE_NEW_IP=10.1.1.2 + +ARG CONVERT_NEW_RELEASE=testrelease + +ARG CP_HOST_PATH=/etc/resolv.conf +ARG CP_JAIL_PATH=/tmp + +ARG RCP_JAIL_PATH=/etc/resolv.conf +ARG RCP_HOST_PATH=/tmp + +ARG SETUP_BRIDGE_INTERFACE=vtnet0 + +ARG JCP_JAIL1=folsom +ARG JCP_JAIL2=attica +ARG JCP_IP1=10.1.1.1 +ARG JCP_IP2=10.1.1.2 +ARG JCP_SOURCE_PATH=/etc/resolv.conf +ARG JCP_DESTINATION_PATH=/tmp + +ARG EXPORT_FILE=/tmp/*.txz +ARG EXPORT_PATH=/tmp + +ARG MOUNT_HOST_FILE=/etc/resolv.conf +ARG MOUNT_JAIL_FILE=/tmp/etc/resolv.conf +ARG MOUNT_HOST_PATH=/usr/local/etc +ARG MOUNT_JAIL_PATH=/tmp/usr/local/etc + +ARG RENAME_NEW_JAIL=attica + +ARG TAGS="prod,dev" + +ARG TEMPLATE_URL=https://github.com/BastilleBSD/templates.git +ARG TEMPLATE_TEMPLATE=www/nginx + +INCLUDE ufs-tests/master --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_INTERFACE=${NEW_INTERFACE} --arg BRIDGE=${BRIDGE} --arg CLONE_NEW_JAIL=${CLONE_NEW_JAIL} --arg CLONE_NEW_IP=${CLONE_NEW_IP} --arg CONVERT_NEW_RELEASE=${CONVERT_NEW_RELEASE} --arg CP_HOST_PATH=${CP_HOST_PATH} --arg CP_JAIL_PATH=${CP_JAIL_PATH} --arg RCP_JAIL_PATH=${RCP_JAIL_PATH} --arg RCP_HOST_PATH=${RCP_HOST_PATH} --arg SETUP_BRIDGE_INTERFACE=${SETUP_BRIDGE_INTERFACE} --arg JCP_JAIL1=${JCP_JAIL1} --arg JCP_JAIL2=${JCP_JAIL2} --arg JCP_IP1=${JCP_IP1} --arg JCP_IP2=${JCP_IP2} --arg JCP_SOURCE_PATH=${JCP_SOURCE_PATH} --arg JCP_DESTINATION_PATH=${JCP_DESTINATION_PATH} --arg EXPORT_FILE=${EXPORT_FILE} --arg EXPORT_PATH=${EXPORT_PATH} --arg MOUNT_HOST_FILE=${MOUNT_HOST_FILE} --arg MOUNT_JAIL_FILE=${MOUNT_JAIL_FILE} --arg MOUNT_HOST_PATH=${MOUNT_HOST_PATH} --arg MOUNT_JAIL_PATH=${MOUNT_JAIL_PATH} --arg RENAME_NEW_JAIL=${RENAME_NEW_JAIL} --arg TAGS=${TAGS} --arg TEMPLATE_URL=${TEMPLATE_URL} --arg TEMPLATE_TEMPLATE=${TEMPLATE_TEMPLATE} diff --git a/tests/ufs-tests/master/Bastillefile b/tests/ufs-tests/master/Bastillefile new file mode 100644 index 00000000..64dc1bb9 --- /dev/null +++ b/tests/ufs-tests/master/Bastillefile @@ -0,0 +1,137 @@ +# ufs-tests/master + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG NEW_INTERFACE +ARG BRIDGE + +ARG CLONE_NEW_JAIL +ARG CLONE_NEW_IP + +ARG CONVERT_NEW_RELEASE + +ARG CP_HOST_PATH +ARG CP_JAIL_PATH + +ARG RCP_JAIL_PATH +ARG RCP_HOST_PATH + +ARG SETUP_BRIDGE_INTERFACE + +ARG JCP_JAIL1 +ARG JCP_JAIL2 +ARG JCP_IP1 +ARG JCP_IP2 +ARG JCP_SOURCE_PATH +ARG JCP_DESTINATION_PATH + +ARG EXPORT_FILE +ARG EXPORT_PATH + +ARG MOUNT_HOST_FILE +ARG MOUNT_JAIL_FILE +ARG MOUNT_HOST_PATH +ARG MOUNT_JAIL_PATH + +ARG RENAME_NEW_JAIL + +ARG TAGS + +ARG TEMPLATE_URL +ARG TEMPLATE_TEMPLATE + +# ***************** +# ***** Setup ***** +# ***************** + +INCLUDE unit-tests/setup +INCLUDE unit-tests/setup-bridge --arg ARGS=${SETUP_BRIDGE_INTERFACE} + +# ********************* +# ***** Bootstrap ***** +# ********************* + +INCLUDE unit-tests/bootstrap-releaseLegacy --arg RELEASE=${RELEASE} + +# ***************** +# ***** Clone ***** +# ***************** + +INCLUDE unit-tests/clone-thick --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_JAIL=${CLONE_NEW_JAIL} --arg NEW_IP=${CLONE_NEW_IP} +INCLUDE unit-tests/clone-thin --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_JAIL=${CLONE_NEW_JAIL} --arg NEW_IP=${CLONE_NEW_IP} + +# ******************* +# ***** Convert ***** +# ******************* + +INCLUDE unit-tests/convert-jail --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} +INCLUDE unit-tests/convert-release --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_RELEASE=${CONVERT_NEW_RELEASE} + +# ********************** +# ***** cp/rcp/jcp ***** +# ********************** + +INCLUDE unit-tests/cp --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg HOST_PATH=${CP_HOST_PATH} --arg JAIL_PATH=${CP_JAIL_PATH} +INCLUDE unit-tests/rcp --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg JAIL_PATH=${RCP_JAIL_PATH} --arg HOST_PATH=${RCP_HOST_PATH} +INCLUDE unit-tests/jcp --arg JAIL1=${JCP_JAIL1} --arg JAIL2=${JCP_JAIL2} --arg RELEASE=${RELEASE} --arg IP1=${JCP_IP1} --arg IP2=${JCP_IP2} --arg INTERFACE=${INTERFACE} --arg SOURCE_JAIL_PATH=${JCP_SOURCE_PATH} --arg DESTINATION_JAIL_PATH=${JCP_DESTINATION_PATH} + +# ****************** +# ***** Create ***** +# ****************** + +INCLUDE unit-tests/create-thick --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} +INCLUDE unit-tests/create-thinBridge --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${BRIDGE} +INCLUDE unit-tests/create-thinVnet --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +# ************************* +# ***** Export/Import ***** +# ************************* + +INCLUDE unit-tests/export-import --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg FILE=${EXPORT_FILE} --arg PATH=${EXPORT_PATH} + +# ************************ +# ***** Mount/Umount ***** +# ************************ + +INCLUDE unit-tests/mount-umount --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg HOST_FILE=${MOUNT_HOST_FILE} --arg JAIL_FILE=${MOUNT_JAIL-FILE} --arg HOST_PATH=${MOUNT_HOST_PATH} --arg JAIL_PATH=${MOUNT_JAIL_PATH} + +# *************** +# ***** pkg ***** +# *************** + +INCLUDE unit-tests/pkg --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +# ****************** +# ***** Rename ***** +# ****************** + +INCLUDE unit-tests/rename-standard --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_JAIL=${RENAME_NEW_JAIL} +INCLUDE unit-tests/rename-vnet --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_JAIL=${RENAME_NEW_JAIL} + +# ****************************** +# ***** Start/Stop/Restart ***** +# ****************************** + +INCLUDE unit-tests/start-stop --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} +INCLUDE unit-tests/restart --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +# ************************* +# ***** Service/Sysrc ***** +# ************************* + +INCLUDE unit-tests/service --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +# **************** +# ***** Tags ***** +# **************** + +INCLUDE unit-tests/tags --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg TAGS=${TAGS} + +# ******************** +# ***** Template ***** +# ******************** + +INCLUDE unit-tests/bootstrap-template --arg TEMPLATE_URL=${TEMPLATE_URL} +INCLUDE unit-tests/template --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg TEMPLATE=${TEMPLATE_TEMPLATE} diff --git a/tests/unit-tests/bootstrap-releaseLegacy/Bastillefile b/tests/unit-tests/bootstrap-releaseLegacy/Bastillefile new file mode 100644 index 00000000..8a4fc33d --- /dev/null +++ b/tests/unit-tests/bootstrap-releaseLegacy/Bastillefile @@ -0,0 +1,7 @@ +# unit-tests/bootstrap-releaseLegacy + +ARG RELEASE + +INCLUDE core/bootstrap-release --arg RELEASE=${RELEASE} +INCLUDE core/destroy-release --arg OPTIONS="-cf" --arg RELEASE=${RELEASE} +INCLUDE core/bootstrap-release --arg RELEASE=${RELEASE} diff --git a/tests/unit-tests/bootstrap-releasePkgbase/Bastillefile b/tests/unit-tests/bootstrap-releasePkgbase/Bastillefile new file mode 100644 index 00000000..a99c9a8d --- /dev/null +++ b/tests/unit-tests/bootstrap-releasePkgbase/Bastillefile @@ -0,0 +1,6 @@ +# unit-tests/bootstrap-releasePkgbase + +ARG RELEASE + +INCLUDE core/bootstrap-release --arg OPTIONS="-p" --arg RELEASE=${RELEASE} +INCLUDE core/destroy-release --arg RELEASE=${RELEASE} diff --git a/tests/unit-tests/bootstrap-template/Bastillefile b/tests/unit-tests/bootstrap-template/Bastillefile new file mode 100644 index 00000000..bdf1c720 --- /dev/null +++ b/tests/unit-tests/bootstrap-template/Bastillefile @@ -0,0 +1,6 @@ +# unit-tests/bootstrap-template + +ARG OPTIONS +ARG TEMPLATE_URL + +INCLUDE core/bootstrap-template --arg OPTIONS=${OPTIONS} --arg TEMPLATE_URL=${TEMPLATE_URL} diff --git a/tests/unit-tests/clone-clone/Bastillefile b/tests/unit-tests/clone-clone/Bastillefile new file mode 100644 index 00000000..bd43f67b --- /dev/null +++ b/tests/unit-tests/clone-clone/Bastillefile @@ -0,0 +1,16 @@ +# unit-tests/clone-clone + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG NEW_JAIL +ARG NEW_IP + +INCLUDE core/create --arg OPTIONS="-C" --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/clone --arg OPTIONS="-a" --arg JAIL=${JAIL} --arg NEW_JAIL=${NEW_JAIL} --arg NEW_IP=${NEW_IP} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${NEW_JAIL} diff --git a/tests/unit-tests/clone-thick/Bastillefile b/tests/unit-tests/clone-thick/Bastillefile new file mode 100644 index 00000000..7e8f0d6f --- /dev/null +++ b/tests/unit-tests/clone-thick/Bastillefile @@ -0,0 +1,16 @@ +# unit-tests/clone-thick + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG NEW_JAIL +ARG NEW_IP + +INCLUDE core/create --arg OPTIONS="-T" --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/clone --arg OPTIONS="-a" --arg JAIL=${JAIL} --arg NEW_JAIL=${NEW_JAIL} --arg NEW_IP=${NEW_IP} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${NEW_JAIL} diff --git a/tests/unit-tests/clone-thin/Bastillefile b/tests/unit-tests/clone-thin/Bastillefile new file mode 100644 index 00000000..b17dc097 --- /dev/null +++ b/tests/unit-tests/clone-thin/Bastillefile @@ -0,0 +1,16 @@ +# unit-tests/clone-thin + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG NEW_JAIL +ARG NEW_IP + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/clone --arg OPTIONS="-a" --arg JAIL=${JAIL} --arg NEW_JAIL=${NEW_JAIL} --arg NEW_IP=${NEW_IP} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${NEW_JAIL} diff --git a/tests/unit-tests/convert-jail/Bastillefile b/tests/unit-tests/convert-jail/Bastillefile new file mode 100644 index 00000000..0b9595aa --- /dev/null +++ b/tests/unit-tests/convert-jail/Bastillefile @@ -0,0 +1,12 @@ +# unit-tests/convert-jail + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/convert-jail --arg OPTIONS="-ay" --arg JAIL=${JAIL} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/convert-release/Bastillefile b/tests/unit-tests/convert-release/Bastillefile new file mode 100644 index 00000000..377fe7e9 --- /dev/null +++ b/tests/unit-tests/convert-release/Bastillefile @@ -0,0 +1,15 @@ +# unit-tests/convert-release + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG NEW_RELEASE + +INCLUDE core/create --arg OPTIONS="-T" --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/convert-release --arg OPTIONS="-ay" --arg JAIL=${JAIL} --arg RELEASE=${NEW_RELEASE} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} + +INCLUDE core/destroy-release --arg OPTIONS="-fy" --arg RELEASE=${NEW_RELEASE} diff --git a/tests/unit-tests/cp/Bastillefile b/tests/unit-tests/cp/Bastillefile new file mode 100644 index 00000000..17339605 --- /dev/null +++ b/tests/unit-tests/cp/Bastillefile @@ -0,0 +1,14 @@ +# unit-tests/cp + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG HOST_PATH +ARG JAIL_PATH + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/cp --arg JAIL=${JAIL} --arg HOST_PATH=${HOST_PATH} --arg JAIL_PATH=${JAIL_PATH} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/create-clone/Bastillefile b/tests/unit-tests/create-clone/Bastillefile new file mode 100644 index 00000000..ae3c414d --- /dev/null +++ b/tests/unit-tests/create-clone/Bastillefile @@ -0,0 +1,10 @@ +# unit-test/create-clone + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE + +INCLUDE core/create --arg OPTIONS="-C" --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/create-thick/Bastillefile b/tests/unit-tests/create-thick/Bastillefile new file mode 100644 index 00000000..026f497f --- /dev/null +++ b/tests/unit-tests/create-thick/Bastillefile @@ -0,0 +1,10 @@ +# unit-tests/create-thick + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE + +INCLUDE core/create --arg OPTIONS="-T" --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/create-thinBridge/Bastillefile b/tests/unit-tests/create-thinBridge/Bastillefile new file mode 100644 index 00000000..42a98ace --- /dev/null +++ b/tests/unit-tests/create-thinBridge/Bastillefile @@ -0,0 +1,14 @@ +# unit-test/create-thinBridge + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE + +INCLUDE core/create --arg OPTIONS="-BM" --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} + +INCLUDE core/create --arg OPTIONS="-BM" --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/create-thinVnet/Bastillefile b/tests/unit-tests/create-thinVnet/Bastillefile new file mode 100644 index 00000000..32f609e8 --- /dev/null +++ b/tests/unit-tests/create-thinVnet/Bastillefile @@ -0,0 +1,14 @@ +# unit-test/create-thinVnet + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE + +INCLUDE core/create --arg OPTIONS="-VM" --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} + +INCLUDE core/create --arg OPTIONS="-VM" --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/export-import/Bastillefile b/tests/unit-tests/export-import/Bastillefile new file mode 100644 index 00000000..e730f92f --- /dev/null +++ b/tests/unit-tests/export-import/Bastillefile @@ -0,0 +1,21 @@ +# unit-tests/export-import + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG FILE +ARG PATH + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/export --arg OPTIONS="-a --txz" --arg JAIL=${JAIL} --arg PATH=${PATH} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} + +INCLUDE core/import --arg FILE=${FILE} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} + +CMD rm -rf ${PATH}/*.txz +CMD rm -rf ${PATH}/*.sha256 diff --git a/tests/unit-tests/jcp/Bastillefile b/tests/unit-tests/jcp/Bastillefile new file mode 100644 index 00000000..948fcd14 --- /dev/null +++ b/tests/unit-tests/jcp/Bastillefile @@ -0,0 +1,19 @@ +# unit-tests/jcp + +ARG JAIL1 +ARG JAIL2 +ARG RELEASE +ARG IP1 +ARG IP2 +ARG INTERFACE +ARG SOURCE_JAIL_PATH +ARG DESTINATION_JAIL_PATH + +INCLUDE core/create --arg JAIL=${JAIL1} --arg RELEASE=${RELEASE} --arg IP=${IP1} --arg INTERFACE=${INTERFACE} + +INCLUDE core/create --arg JAIL=${JAIL2} --arg RELEASE=${RELEASE} --arg IP=${IP2} --arg INTERFACE=${INTERFACE} + +INCLUDE core/jcp --arg SOURCE_JAIL=${JAIL1} --arg SOURCE_JAIL_PATH=${SOURCE_JAIL_PATH} --arg DESTINATION_JAIL=${JAIL2} --arg DESTINATION_JAIL_PATH=${DESTINATION_JAIL_PATH} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL1} +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL2} diff --git a/tests/unit-tests/mount-umount/Bastillefile b/tests/unit-tests/mount-umount/Bastillefile new file mode 100644 index 00000000..22a63135 --- /dev/null +++ b/tests/unit-tests/mount-umount/Bastillefile @@ -0,0 +1,23 @@ +# unit-tests/mount-umount + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG HOST_PATH +ARG JAIL_PATH +ARG HOST_FILE +ARG JAIL_FILE +ARG ARGS + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/mount --arg JAIL=${JAIL} --arg HOST_PATH=${HOST_PATH} --arg JAIL_PATH=${JAIL_PATH} --arg ARGS="${ARGS}" + +INCLUDE core/mount --arg JAIL=${JAIL} --arg HOST_PATH=${HOST_FILE} --arg JAIL_PATH=${JAIL_FILE} --arg ARGS="${ARGS}" + +INCLUDE core/umount --arg JAIL=${JAIL} --arg JAIL_PATH=${JAIL_PATH} + +INCLUDE core/umount --arg JAIL=${JAIL} --arg JAIL_PATH=${JAIL_FILE} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/pkg/Bastillefile b/tests/unit-tests/pkg/Bastillefile new file mode 100644 index 00000000..45304c43 --- /dev/null +++ b/tests/unit-tests/pkg/Bastillefile @@ -0,0 +1,18 @@ +# unit-tests/pkg + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +# -ay +INCLUDE core/pkg --arg OPTIONS="-ay" --arg JAIL=${JAIL} --arg ARGS="install nginx" +INCLUDE core/pkg --arg OPTIONS="-ay" --arg JAIL=${JAIL} --arg ARGS="remove nginx" + +# -aHy +INCLUDE core/pkg --arg OPTIONS="-aHy" --arg JAIL=${JAIL} --arg ARGS="install nginx" +INCLUDE core/pkg --arg OPTIONS="-aHy" --arg JAIL=${JAIL} --arg ARGS="remove nginx" + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/rcp/Bastillefile b/tests/unit-tests/rcp/Bastillefile new file mode 100644 index 00000000..ec935f9d --- /dev/null +++ b/tests/unit-tests/rcp/Bastillefile @@ -0,0 +1,14 @@ +# unit-tests/rcp + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG JAIL_PATH +ARG HOST_PATH + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/rcp --arg JAIL=${JAIL} --arg JAIL_PATH=${JAIL_PATH} --arg HOST_PATH=${HOST_PATH} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/rename-standard/Bastillefile b/tests/unit-tests/rename-standard/Bastillefile new file mode 100644 index 00000000..4deab299 --- /dev/null +++ b/tests/unit-tests/rename-standard/Bastillefile @@ -0,0 +1,15 @@ +# unit-tests/rename-standard + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG NEW_JAIL + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/rename --arg OPTIONS="-a" --arg JAIL=${JAIL} --arg NEW_JAIL=${NEW_JAIL} + +INCLUDE core/start --arg JAIL=${NEW_JAIL} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${NEW_JAIL} diff --git a/tests/unit-tests/rename-vnet/Bastillefile b/tests/unit-tests/rename-vnet/Bastillefile new file mode 100644 index 00000000..c47bf957 --- /dev/null +++ b/tests/unit-tests/rename-vnet/Bastillefile @@ -0,0 +1,15 @@ +# unit-tests/rename-vnet + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG NEW_JAIL + +INCLUDE core/create --arg OPTIONS="-V" --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/rename --arg OPTIONS="-a" --arg JAIL=${JAIL} --arg NEW_JAIL=${NEW_JAIL} + +INCLUDE core/start --arg JAIL=${NEW_JAIL} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${NEW_JAIL} diff --git a/tests/unit-tests/restart/Bastillefile b/tests/unit-tests/restart/Bastillefile new file mode 100644 index 00000000..b4e16fd1 --- /dev/null +++ b/tests/unit-tests/restart/Bastillefile @@ -0,0 +1,15 @@ +# unit-tests/restart + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/restart --arg JAIL=${JAIL} +INCLUDE core/restart --arg OPTIONS="-d 5" --arg JAIL=${JAIL} +INCLUDE core/restart --arg OPTIONS="-b" --arg JAIL=${JAIL} +INCLUDE core/restart --arg OPTIONS="-i" --arg JAIL=${JAIL} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/service/Bastillefile b/tests/unit-tests/service/Bastillefile new file mode 100644 index 00000000..ec7c61bb --- /dev/null +++ b/tests/unit-tests/service/Bastillefile @@ -0,0 +1,12 @@ +# unit-tests/service + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/service --arg JAIL=${JAIL} --arg SERVICE="jail" --arg ARGS="status" + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/setup-bridge/Bastillefile b/tests/unit-tests/setup-bridge/Bastillefile new file mode 100644 index 00000000..01fe0d53 --- /dev/null +++ b/tests/unit-tests/setup-bridge/Bastillefile @@ -0,0 +1,6 @@ +# unit-tests/setup-bridge + +ARG OPTIONS="bridge" +ARG ARGS + +INCLUDE core/setup --arg OPTIONS=${OPTIONS} --arg ARGS=${ARGS} diff --git a/tests/unit-tests/setup/Bastillefile b/tests/unit-tests/setup/Bastillefile new file mode 100644 index 00000000..aa8b01c3 --- /dev/null +++ b/tests/unit-tests/setup/Bastillefile @@ -0,0 +1,3 @@ +# unit-tests/setup + +INCLUDE core/setup diff --git a/tests/unit-tests/start-stop/Bastillefile b/tests/unit-tests/start-stop/Bastillefile new file mode 100644 index 00000000..0a03a173 --- /dev/null +++ b/tests/unit-tests/start-stop/Bastillefile @@ -0,0 +1,13 @@ +# unit-tests/start-stop + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/stop --arg JAIL=${JAIL} +INCLUDE core/start --arg JAIL=${JAIL} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/tags/Bastillefile b/tests/unit-tests/tags/Bastillefile new file mode 100644 index 00000000..1df23cd3 --- /dev/null +++ b/tests/unit-tests/tags/Bastillefile @@ -0,0 +1,14 @@ +# unit-tests/tags + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/tags --arg JAIL=${JAIL} --arg ACTION=add --arg TAGS="prod,web" + +INCLUDE core/tags --arg JAIL=${JAIL} --arg ACTION=delete --arg TAGS="prod,web" + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/unit-tests/template/Bastillefile b/tests/unit-tests/template/Bastillefile new file mode 100644 index 00000000..18eb952f --- /dev/null +++ b/tests/unit-tests/template/Bastillefile @@ -0,0 +1,13 @@ +# unit-tests/template + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG TEMPLATE + +INCLUDE core/create --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +INCLUDE core/template --arg OPTIONS="-a" --arg JAIL=${JAIL} --arg TEMPLATE=${TEMPLATE} + +INCLUDE core/destroy-jail --arg OPTIONS="-afy" --arg JAIL=${JAIL} diff --git a/tests/zfs-tests/init/Bastillefile b/tests/zfs-tests/init/Bastillefile new file mode 100644 index 00000000..22ae0592 --- /dev/null +++ b/tests/zfs-tests/init/Bastillefile @@ -0,0 +1,45 @@ +# zfs-tests/init + +ARG JAIL=folsom +ARG RELEASE=14.3-RELEASE +ARG IP=10.1.1.1 +ARG INTERFACE=vtnet0 +ARG NEW_INTERFACE=vtnet0 +ARG BRIDGE=vtnet0bridge + +ARG CLONE_NEW_JAIL=attica +ARG CLONE_NEW_IP=10.1.1.2 + +ARG CONVERT_NEW_RELEASE=testrelease + +ARG CP_HOST_PATH=/etc/resolv.conf +ARG CP_JAIL_PATH=/tmp + +ARG RCP_JAIL_PATH=/etc/resolv.conf +ARG RCP_HOST_PATH=/tmp + +ARG SETUP_BRIDGE_INTERFACE=vtnet0 + +ARG JCP_JAIL1=folsom +ARG JCP_JAIL2=attica +ARG JCP_IP1=10.1.1.1 +ARG JCP_IP2=10.1.1.2 +ARG JCP_SOURCE_PATH=/etc/resolv.conf +ARG JCP_DESTINATION_PATH=/tmp + +ARG EXPORT_FILE=/tmp/*.txz +ARG EXPORT_PATH=/tmp + +ARG MOUNT_HOST_FILE=/etc/resolv.conf +ARG MOUNT_JAIL_FILE=/tmp/etc/resolv.conf +ARG MOUNT_HOST_PATH=/usr/local/etc +ARG MOUNT_JAIL_PATH=/tmp/usr/local/etc + +ARG RENAME_NEW_JAIL=attica + +ARG TAGS="prod,dev" + +ARG TEMPLATE_URL=https://github.com/BastilleBSD/templates.git +ARG TEMPLATE_TEMPLATE=www/nginx + +INCLUDE zfs-tests/master --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_INTERFACE=${NEW_INTERFACE} --arg BRIDGE=${BRIDGE} --arg CLONE_NEW_JAIL=${CLONE_NEW_JAIL} --arg CLONE_NEW_IP=${CLONE_NEW_IP} --arg CONVERT_NEW_RELEASE=${CONVERT_NEW_RELEASE} --arg CP_HOST_PATH=${CP_HOST_PATH} --arg CP_JAIL_PATH=${CP_JAIL_PATH} --arg RCP_JAIL_PATH=${RCP_JAIL_PATH} --arg RCP_HOST_PATH=${RCP_HOST_PATH} --arg SETUP_BRIDGE_INTERFACE=${SETUP_BRIDGE_INTERFACE} --arg JCP_JAIL1=${JCP_JAIL1} --arg JCP_JAIL2=${JCP_JAIL2} --arg JCP_IP1=${JCP_IP1} --arg JCP_IP2=${JCP_IP2} --arg JCP_SOURCE_PATH=${JCP_SOURCE_PATH} --arg JCP_DESTINATION_PATH=${JCP_DESTINATION_PATH} --arg EXPORT_FILE=${EXPORT_FILE} --arg EXPORT_PATH=${EXPORT_PATH} --arg MOUNT_HOST_FILE=${MOUNT_HOST_FILE} --arg MOUNT_JAIL_FILE=${MOUNT_JAIL_FILE} --arg MOUNT_HOST_PATH=${MOUNT_HOST_PATH} --arg MOUNT_JAIL_PATH=${MOUNT_JAIL_PATH} --arg RENAME_NEW_JAIL=${RENAME_NEW_JAIL} --arg TAGS=${TAGS} --arg TEMPLATE_URL=${TEMPLATE_URL} --arg TEMPLATE_TEMPLATE=${TEMPLATE_TEMPLATE} diff --git a/tests/zfs-tests/master/Bastillefile b/tests/zfs-tests/master/Bastillefile new file mode 100644 index 00000000..776170d7 --- /dev/null +++ b/tests/zfs-tests/master/Bastillefile @@ -0,0 +1,139 @@ +# zfs-tests/master + +ARG JAIL +ARG RELEASE +ARG IP +ARG INTERFACE +ARG NEW_INTERFACE +ARG BRIDGE + +ARG CLONE_NEW_JAIL +ARG CLONE_NEW_IP + +ARG CONVERT_NEW_RELEASE + +ARG CP_HOST_PATH +ARG CP_JAIL_PATH + +ARG RCP_JAIL_PATH +ARG RCP_HOST_PATH + +ARG SETUP_BRIDGE_INTERFACE + +ARG JCP_JAIL1 +ARG JCP_JAIL2 +ARG JCP_IP1 +ARG JCP_IP2 +ARG JCP_SOURCE_PATH +ARG JCP_DESTINATION_PATH + +ARG EXPORT_FILE +ARG EXPORT_PATH + +ARG MOUNT_HOST_FILE +ARG MOUNT_JAIL_FILE +ARG MOUNT_HOST_PATH +ARG MOUNT_JAIL_PATH + +ARG RENAME_NEW_JAIL + +ARG TAGS + +ARG TEMPLATE_URL +ARG TEMPLATE_TEMPLATE + +# ***************** +# ***** Setup ***** +# ***************** + +INCLUDE unit-tests/setup +INCLUDE unit-tests/setup-bridge --arg ARGS=${SETUP_BRIDGE_INTERFACE} + +# ********************* +# ***** Bootstrap ***** +# ********************* + +INCLUDE unit-tests/bootstrap-releaseLegacy --arg RELEASE=${RELEASE} + +# ***************** +# ***** Clone ***** +# ***************** + +INCLUDE unit-tests/clone-clone --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_JAIL=${CLONE_NEW_JAIL} --arg NEW_IP=${CLONE_NEW_IP} +INCLUDE unit-tests/clone-thick --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_JAIL=${CLONE_NEW_JAIL} --arg NEW_IP=${CLONE_NEW_IP} +INCLUDE unit-tests/clone-thin --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_JAIL=${CLONE_NEW_JAIL} --arg NEW_IP=${CLONE_NEW_IP} + +# ******************* +# ***** Convert ***** +# ******************* + +INCLUDE unit-tests/convert-jail --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} +INCLUDE unit-tests/convert-release --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_RELEASE=${CONVERT_NEW_RELEASE} + +# ********************** +# ***** cp/rcp/jcp ***** +# ********************** + +INCLUDE unit-tests/cp --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg HOST_PATH=${CP_HOST_PATH} --arg JAIL_PATH=${CP_JAIL_PATH} +INCLUDE unit-tests/rcp --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg JAIL_PATH=${RCP_JAIL_PATH} --arg HOST_PATH=${RCP_HOST_PATH} +INCLUDE unit-tests/jcp --arg JAIL1=${JCP_JAIL1} --arg JAIL2=${JCP_JAIL2} --arg RELEASE=${RELEASE} --arg IP1=${JCP_IP1} --arg IP2=${JCP_IP2} --arg INTERFACE=${INTERFACE} --arg SOURCE_JAIL_PATH=${JCP_SOURCE_PATH} --arg DESTINATION_JAIL_PATH=${JCP_DESTINATION_PATH} + +# ****************** +# ***** Create ***** +# ****************** + +INCLUDE unit-tests/create-clone --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} # ZFS only +INCLUDE unit-tests/create-thick --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} +INCLUDE unit-tests/create-thinBridge --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${BRIDGE} +INCLUDE unit-tests/create-thinVnet --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +# ************************* +# ***** Export/Import ***** +# ************************* + +INCLUDE unit-tests/export-import --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg FILE=${EXPORT_FILE} --arg PATH=${EXPORT_PATH} + +# ************************ +# ***** Mount/Umount ***** +# ************************ + +INCLUDE unit-tests/mount-umount --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg HOST_FILE=${MOUNT_HOST_FILE} --arg JAIL_FILE=${MOUNT_JAIL-FILE} --arg HOST_PATH=${MOUNT_HOST_PATH} --arg JAIL_PATH=${MOUNT_JAIL_PATH} + +# *************** +# ***** pkg ***** +# *************** + +INCLUDE unit-tests/pkg --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +# ****************** +# ***** Rename ***** +# ****************** + +INCLUDE unit-tests/rename-standard --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_JAIL=${RENAME_NEW_JAIL} +INCLUDE unit-tests/rename-vnet --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg NEW_JAIL=${RENAME_NEW_JAIL} + +# ****************************** +# ***** Start/Stop/Restart ***** +# ****************************** + +INCLUDE unit-tests/start-stop --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} +INCLUDE unit-tests/restart --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +# ************************* +# ***** Service/Sysrc ***** +# ************************* + +INCLUDE unit-tests/service --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} + +# **************** +# ***** Tags ***** +# **************** + +INCLUDE unit-tests/tags --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg TAGS=${TAGS} + +# ******************** +# ***** Template ***** +# ******************** + +INCLUDE unit-tests/bootstrap-template --arg TEMPLATE_URL=${TEMPLATE_URL} +INCLUDE unit-tests/template --arg JAIL=${JAIL} --arg RELEASE=${RELEASE} --arg IP=${IP} --arg INTERFACE=${INTERFACE} --arg TEMPLATE=${TEMPLATE_TEMPLATE} diff --git a/usr/local/bin/bastille b/usr/local/bin/bastille index 73bd7787..8157b31c 100755 --- a/usr/local/bin/bastille +++ b/usr/local/bin/bastille @@ -32,7 +32,7 @@ PATH=${PATH}:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin -BASTILLE_VERSION=1.0.1.250714 +BASTILLE_VERSION=1.2.0.251201 # Validate config file # Copy default when 'setup' is called @@ -120,7 +120,6 @@ Available Commands: Use "bastille -v|--version" for version information. Use "bastille command -h|--help" for more information about a command. Use "bastille -c|--config FILE command" to specify a non-default config file. -Use "bastille -p|--parallel VALUE command" to run bastille in parallel mode. EOF exit 1 @@ -147,8 +146,6 @@ bastille_perms_check . /usr/local/share/bastille/common.sh # Handle options -bastille_parallel_mode=0 -bastille_process_limit="${bastille_process_limit:-1}" while [ "$#" -gt 0 ]; do case "${1}" in -h|--help|help) @@ -168,18 +165,9 @@ while [ "$#" -gt 0 ]; do error_exit "Not a valid config file: ${BASTILLE_CONFIG}" fi # Load common.sh after setting BASTILLE_CONFIG - . /usr/local/share/bastille/common.sh + . /usr/local/share/bastille/common.sh shift 2 ;; - -p|--parallel) - bastille_parallel_mode=1 - bastille_process_limit="${2}" - if ! echo "${bastille_process_limit}" | grep -Eq "^[0-9]+$"; then - error_exit "Not a valid process limit: ${bastille_process_limit}" - else - shift 2 - fi - ;; -*) error_exit "Unknown Option: \"${1}\"" ;; @@ -189,9 +177,6 @@ while [ "$#" -gt 0 ]; do esac done -# Export parallel and limit -export bastille_process_limit - if [ "$#" -lt 1 ]; then usage else @@ -201,12 +186,14 @@ fi # Handle sub-commands. case "${CMD}" in - # Commands that don't allow parallel mode + # 38 total commands bootstrap| \ clone| \ cmd| \ + config| \ console| \ convert| \ + cp| \ create| \ destroy| \ edit| \ @@ -214,39 +201,31 @@ case "${CMD}" in export| \ htop| \ import| \ + jcp| \ limits| \ list| \ migrate| \ monitor| \ + mount| \ network| \ pkg| \ rcp| \ rdr| \ rename| \ + restart| \ service| \ setup| \ - top| \ - update| \ - upgrade| \ - verify| \ - zfs) - if [ "${bastille_parallel_mode}" -eq 1 ]; then - error_exit "Command does not support parallel mode: ${CMD}" - fi - ;; - # Commands that allow parallel mode - config| \ - cp| \ - jcp| \ - limits| \ - mount| \ - restart| \ start| \ stop| \ sysrc| \ tags| \ template| \ - umount) + top| \ + umount| \ + update| \ + upgrade| \ + verify| \ + zfs) ;; *) usage @@ -263,8 +242,8 @@ if [ -f "${SCRIPTPATH}" ]; then : "${SH:=sh}" - exec "${SH}" "${SCRIPTPATH}" "$@" + exec ${SH} "${SCRIPTPATH}" "$@" else - error_exit "${SCRIPTPATH} not found." + error_exit "${SCRIPTPATH} not found." fi diff --git a/usr/local/etc/bastille/bastille.conf.sample b/usr/local/etc/bastille/bastille.conf.sample index a3f9b7c2..698458e4 100644 --- a/usr/local/etc/bastille/bastille.conf.sample +++ b/usr/local/etc/bastille/bastille.conf.sample @@ -23,10 +23,28 @@ bastille_sharedir="/usr/local/share/bastille" ## default ## ports - The FreeBSD ports (3rd party applications) tree ## src - The source code to the kernel + userland ## test - The FreeBSD test suite -## this is a whitespace separated list: +## Whitespace separated list: ## bastille_bootstrap_archives="base lib32 ports src test" bastille_bootstrap_archives="base" ## default: "base" +## pkgbase package sets (used for FreeBSD 15+) +## Any set with [-dbg] can be installed with debugging +## symbols by adding '-dbg' to the package set +## base[-dbg] - Base system +## base-jail[-dbg] - Base system for jails +## devel[-dbg] - Development tools +## kernels[-dbg] - Base system kernels +## lib32[-dbg] - 32-bit compatability libraries +## minimal[-dbg] - Basic multi-user system +## minimal-jail[-dbg] - Basic multi-user jail system +## optional[-dbg] - Optional base system software +## optional-jail[-dbg] - Optional base system software for jails +## src - System source code +## tests - System test suite +## Whitespace separated list: +## bastille_pkgbase_packages="base-jail lib32-dbg src" +bastille_pkgbase_packages="base-jail" ## default: "base-jail" + ## default timezone bastille_tzdata="" ## default: empty to use host's time zone @@ -42,14 +60,16 @@ bastille_url_midnightbsd="https://www.midnightbsd.org/ftp/MidnightBSD/releases/" bastille_zfs_enable="NO" ## default: "NO" bastille_zfs_zpool="" ## default: "" bastille_zfs_prefix="bastille" ## default: "bastille" -bastille_zfs_options="-o compress=lz4 -o atime=off" ## default: "-o compress=lz4 -o atime=off" +bastille_zfs_options="-o compress=on -o atime=off" ## default: "-o compress=on -o atime=off" ## Export/Import options bastille_compress_xz_options="-0 -v" ## default "-0 -v" bastille_decompress_xz_options="-c -d -v" ## default "-c -d -v" bastille_compress_gz_options="-1 -v" ## default "-1 -v" bastille_decompress_gz_options="-k -d -c -v" ## default "-k -d -c -v" -bastille_export_options="" ## default "" predefined export options, e.g. "--safe --gz" +bastille_compress_zst_options="-3 -v" ## default "-3 -v" +bastille_decompress_zst_options="-k -d -c -v" ## default "-k -d -c -v" +bastille_export_options="" ## default "" predefined export options, e.g. "--live --gz" ## Networking bastille_network_vnet_type="if_bridge" ## default: "if_bridge" diff --git a/usr/local/etc/rc.d/bastille b/usr/local/etc/rc.d/bastille index 51abbb3b..77606bf6 100755 --- a/usr/local/etc/rc.d/bastille +++ b/usr/local/etc/rc.d/bastille @@ -29,25 +29,46 @@ rcvar=${name}_enable : ${bastille_conf:="/usr/local/etc/bastille/bastille.conf"} : ${bastille_startup_delay:=0} : ${bastille_parallel_limit:=1} +: ${bastille_jail_list:=ALL} command=/usr/local/bin/${name} start_cmd="bastille_start" stop_cmd="bastille_stop" restart_cmd="bastille_restart" -bastille_start() -{ - ${command} -p ${bastille_parallel_limit} start --boot --delay ${bastille_startup_delay} ALL +list_jails() { + local _jailsdir=$(. $bastille_conf; echo $bastille_jailsdir) + local _jail_list=$(find ${_jailsdir}/* -mindepth 1 -maxdepth 1 -type f -name jail.conf | xargs -n1 dirname | xargs -n1 basename) + for _jail in ${_jail_list}; do + _priority="$(sysrc -f ${_jailsdir}/${_jail}/settings.conf -n priority)" + echo "${_jail} ${_priority}" + done } -bastille_stop() -{ - ${command} -p ${bastille_parallel_limit} stop ALL +sort_jails() { + local _order="${1}" + if [ "${_order}" = "forward" ]; then + bastille_jail_list="$(list_jails | sort -k2 -n | awk '{print $1}')" + elif [ "${_order}" = "reverse" ]; then + bastille_jail_list="$(list_jails | sort -k2 -nr | awk '{print $1}')" + else + echo "[ERROR]: Fatal error, could not get jail list." + fi } -bastille_restart() -{ - ${command} -p ${bastille_parallel_limit} restart --boot --delay ${bastille_startup_delay} ALL +bastille_start() { + sort_jails "forward" + echo "${bastille_jail_list}" | xargs -P ${bastille_parallel_limit} -I JAIL ${command} start --boot --delay ${bastille_startup_delay} JAIL +} + +bastille_stop() { + sort_jails "reverse" + echo "${bastille_jail_list}" | xargs -P ${bastille_parallel_limit} -I JAIL ${command} stop JAIL +} + +bastille_restart() { + sort_jails "forward" + echo "${bastille_jail_list}" | xargs -P ${bastille_parallel_limit} -I JAIL ${command} restart --boot --delay ${bastille_startup_delay} JAIL } load_rc_config ${name} diff --git a/usr/local/man/man8/bastille.8.gz b/usr/local/man/man8/bastille.8.gz deleted file mode 100644 index 8f40bcbf..00000000 Binary files a/usr/local/man/man8/bastille.8.gz and /dev/null differ diff --git a/usr/local/share/bastille/bootstrap.sh b/usr/local/share/bastille/bootstrap.sh index a0e0339e..5b55fb08 100644 --- a/usr/local/share/bastille/bootstrap.sh +++ b/usr/local/share/bastille/bootstrap.sh @@ -33,50 +33,21 @@ . /usr/local/share/bastille/common.sh usage() { - error_notify "Usage: bastille bootstrap [option(s)] RELEASE|TEMPLATE [update|arch]" + error_notify "Usage: bastille bootstrap [option(s)] RELEASE [update|arch]" + error_notify " TEMPLATE" cat << EOF - + Options: - - -x | --debug Enable debug mode. + + -p | --pkgbase Bootstrap using pkgbase (15.0-RELEASE and above). + -x | --debug Enable debug mode. EOF exit 1 } -validate_release_url() { - - info "\nBootstrapping release: ${RELEASE}..." - - ## check upstream url, else warn user - if [ -n "${NAME_VERIFY}" ]; then - - RELEASE="${NAME_VERIFY}" - - info "\nFetching ${PLATFORM_OS} distfiles..." - - if ! fetch -qo /dev/null "${UPSTREAM_URL}/MANIFEST" 2>/dev/null; then - error_exit "Unable to fetch MANIFEST. See 'bootstrap urls'." - fi - - # Alternate RELEASE/ARCH fetch support - if [ "${OPTION}" = "--i386" ] || [ "${OPTION}" = "--32bit" ]; then - ARCH="i386" - RELEASE="${RELEASE}-${ARCH}" - fi - - bootstrap_directories - bootstrap_release - - else - usage - fi -} - bootstrap_directories() { - # Ensure required directories are in place - ## ${bastille_prefix} if [ ! -d "${bastille_prefix}" ]; then if checkyesno bastille_zfs_enable; then @@ -89,7 +60,7 @@ bootstrap_directories() { chmod 0750 "${bastille_prefix}" # Make sure the dataset is mounted in the proper place elif [ -d "${bastille_prefix}" ] && checkyesno bastille_zfs_enable; then - if ! zfs list "${bastille_zfs_zpool}/${bastille_zfs_prefix}" >/dev/null; then + if ! zfs list "${bastille_zfs_zpool}/${bastille_zfs_prefix}" >/dev/null 2>&1; then zfs create ${bastille_zfs_options} -o mountpoint="${bastille_prefix_mountpoint}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}" elif [ "$(zfs get -H -o value mountpoint ${bastille_zfs_zpool}/${bastille_zfs_prefix})" != "${bastille_prefix}" ]; then zfs set mountpoint="${bastille_prefix_mountpoint}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}" @@ -194,208 +165,282 @@ bootstrap_directories() { fi } -bootstrap_release() { +cleanup_directories() { - ## if release exists quit, else bootstrap additional distfiles + # Cleanup on failed bootstrap + if checkyesno bastille_zfs_enable; then + if [ -n "${bastille_zfs_zpool}" ]; then + if zfs list "${bastille_zfs_zpool}/${bastille_zfs_prefix}/cache/${RELEASE}" >/dev/null 2>/dev/null; then + zfs destroy "${bastille_zfs_zpool:?}/${bastille_zfs_prefix:?}/cache/${RELEASE}" + fi + if zfs list "${bastille_zfs_zpool}/${bastille_zfs_prefix}/releases/${RELEASE}" >/dev/null 2>/dev/null; then + zfs destroy "${bastille_zfs_zpool:?}/${bastille_zfs_prefix:?}/releases/${RELEASE}" + fi + fi + elif [ -d "${bastille_cachedir}/${RELEASE}" ]; then + if [ -d "${bastille_cachedir}/${RELEASE}" ]; then + rm -rf "${bastille_cachedir:?}/${RELEASE}" + fi + if [ -d "${bastille_releasesdir}/${RELEASE}" ]; then + rm -rf "${bastille_releasesdir:?}/${RELEASE}" + fi + fi +} + +validate_release() { + + info "\nAttempting to bootstrap ${PLATFORM_OS} release: ${RELEASE}" + + # Set release name to sane release + RELEASE="${NAME_VERIFY}" + + ### FreeBSD ### + if [ "${PLATFORM_OS}" = "FreeBSD" ]; then + MAJOR_VERSION=$(echo ${RELEASE} | grep -Eo '^[0-9]+') + MINOR_VERSION=$(echo ${RELEASE} | sed -E 's/^[0-9]+\.([0-9]+)-.*$/\1/') + if [ "${MAJOR_VERSION}" -ge 16 ]; then + PKGBASE=1 + elif [ "${MAJOR_VERSION}" -le 14 ] && [ "${PKGBASE}" -eq 1 ]; then + error_exit "[ERROR]: Pkgbase is not supported for release: ${RELEASE}" + fi + ### Linux ### + elif [ "${PLATFORM_OS}" = "Linux/Debian" ] || [ "${PLATFORM_OS}" = "Linux/Ubuntu" ]; then + info "\nEnsuring Linux compatability..." + if ! bastille setup -y linux >/dev/null 2>/dev/null; then + error_notify "[ERROR]: Failed to configure linux." + error_exit "See 'bastille setup linux' for more details." + fi + elif [ "${PLATFORM_OS}" != "FreeBSD" ] && [ "${PKGBASE}" -eq 1 ]; then + error_exit "[ERROR]: Pkgbase is not supported for platform: ${PLATFORM_OS}" + fi + + + # Validate OPTION + if [ -n "${OPTION}" ]; then + # Alternate RELEASE/ARCH fetch support + if [ "${OPTION}" = "--i386" ] || [ "${OPTION}" = "--32bit" ]; then + ARCH="i386" + RELEASE="${RELEASE}-${ARCH}" + fi + fi +} + +bootstrap_release_legacy() { + + # Verify release URL + if ! fetch -qo /dev/null "${UPSTREAM_URL}/MANIFEST" 2>/dev/null; then + ERRORS=$((ERRORS + 1)) + error_notify "Unable to fetch MANIFEST. See 'bootstrap urls'." + return 1 + fi + + # Validate already installed archives if [ -f "${bastille_releasesdir}/${RELEASE}/COPYRIGHT" ]; then - ## check distfiles list and skip existing cached files bastille_bootstrap_archives=$(echo "${bastille_bootstrap_archives}" | sed "s/base//") - # TODO check how to handle this # shellcheck disable=SC2010 bastille_cached_files=$(ls "${bastille_cachedir}/${RELEASE}" | grep -v "MANIFEST" | tr -d ".txz") for distfile in ${bastille_cached_files}; do bastille_bootstrap_archives=$(echo "${bastille_bootstrap_archives}" | sed "s/${distfile}//") done - - ## check if release already bootstrapped, else continue bootstrapping if [ -z "${bastille_bootstrap_archives}" ]; then info "\nBootstrap appears complete!\n" exit 0 - else - info "\nFetching additional distfiles..." fi fi - for _archive in ${bastille_bootstrap_archives}; do - ## check if the dist files already exists then extract - FETCH_VALIDATION="0" - if [ -f "${bastille_cachedir}/${RELEASE}/${_archive}.txz" ]; then - info "\nExtracting ${PLATFORM_OS} ${RELEASE} ${_archive}.txz..." - if /usr/bin/tar -C "${bastille_releasesdir}/${RELEASE}" -xf "${bastille_cachedir}/${RELEASE}/${_archive}.txz"; then - ## silence motd at container login - touch "${bastille_releasesdir}/${RELEASE}/root/.hushlogin" - touch "${bastille_releasesdir}/${RELEASE}/usr/share/skel/dot.hushlogin" - else - error_exit "[ERROR]: Failed to extract ${_archive}.txz." + # Bootstrap archives + for archive in ${bastille_bootstrap_archives}; do + if [ -f "${bastille_cachedir}/${RELEASE}/${archive}.txz" ]; then + info "\nExtracting ${PLATFORM_OS} archive: ${archive}.txz" + if ! /usr/bin/tar -C "${bastille_releasesdir}/${RELEASE}" -xf "${bastille_cachedir}/${RELEASE}/${archive}.txz"; then + ERRORS=$((ERRORS + 1)) + error_continue "[ERROR]: Failed to extract archive: ${archive}.txz." fi else - ## get the manifest for dist files checksum validation + # Fetch MANIFEST if [ ! -f "${bastille_cachedir}/${RELEASE}/MANIFEST" ]; then - fetch "${UPSTREAM_URL}/MANIFEST" -o "${bastille_cachedir}/${RELEASE}/MANIFEST" || FETCH_VALIDATION="1" + info "\nFetching MANIFEST..." + if ! fetch "${UPSTREAM_URL}/MANIFEST" -o "${bastille_cachedir}/${RELEASE}/MANIFEST"; then + ERRORS=$((ERRORS + 1)) + error_continue "[ERROR]: Failed to fetch MANIFEST." + fi fi - if [ "${FETCH_VALIDATION}" -ne "0" ]; then - ## perform cleanup only for stale/empty directories on failure - if checkyesno bastille_zfs_enable; then - if [ -n "${bastille_zfs_zpool}" ]; then - if [ ! "$(ls -A "${bastille_cachedir}/${RELEASE}")" ]; then - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/cache/${RELEASE}" - fi - if [ ! "$(ls -A "${bastille_releasesdir}/${RELEASE}")" ]; then - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/releases/${RELEASE}" - fi - fi - fi - if [ -d "${bastille_cachedir}/${RELEASE}" ]; then - if [ ! "$(ls -A "${bastille_cachedir}/${RELEASE}")" ]; then - rm -rf "${bastille_cachedir:?}/${RELEASE}" - fi - fi - if [ -d "${bastille_releasesdir}/${RELEASE}" ]; then - if [ ! "$(ls -A "${bastille_releasesdir}/${RELEASE}")" ]; then - rm -rf "${bastille_releasesdir:?}/${RELEASE}" - fi - fi - error_exit "[ERROR]: Bootstrap failed." + # Fetch distfile + if [ ! -f "${bastille_cachedir}/${RELEASE}/${archive}.txz" ]; then + info "\nFetching distfile: ${archive}.txz" + if ! fetch "${UPSTREAM_URL}/${archive}.txz" -o "${bastille_cachedir}/${RELEASE}/${archive}.txz"; then + ERRORS=$((ERRORS + 1)) + error_continue "[ERROR]: Failed to fetch archive: ${archive}.txz" fi + fi - ## fetch for missing dist files - if [ ! -f "${bastille_cachedir}/${RELEASE}/${_archive}.txz" ]; then - if ! fetch "${UPSTREAM_URL}/${_archive}.txz" -o "${bastille_cachedir}/${RELEASE}/${_archive}.txz"; then - ## alert only if unable to fetch additional dist files - error_exit "[ERROR]: Failed to fetch ${_archive}.txz" - fi + # Validate checksums + info "\nValidating checksum for archive: ${archive}.txz" + if [ -f "${bastille_cachedir}/${RELEASE}/${archive}.txz" ]; then + SHA256_DIST=$(grep -w "${archive}.txz" "${bastille_cachedir}/${RELEASE}/MANIFEST" | awk '{print $2}') + SHA256_FILE=$(sha256 -q "${bastille_cachedir}/${RELEASE}/${archive}.txz") + if [ "${SHA256_FILE}" != "${SHA256_DIST}" ]; then + ERRORS=$((ERRORS + 1)) + error_continue "[ERROR]: Failed to validate checksum for archive: ${archive}.txz" + else + echo "MANIFEST: ${SHA256_DIST}" + echo "DOWNLOAD: ${SHA256_FILE}" + info "\nChecksum validated." fi + fi - ## compare checksums on the fetched dist files - if [ -f "${bastille_cachedir}/${RELEASE}/${_archive}.txz" ]; then - SHA256_DIST=$(grep -w "${_archive}.txz" "${bastille_cachedir}/${RELEASE}/MANIFEST" | awk '{print $2}') - SHA256_FILE=$(sha256 -q "${bastille_cachedir}/${RELEASE}/${_archive}.txz") - if [ "${SHA256_FILE}" != "${SHA256_DIST}" ]; then - rm "${bastille_cachedir}/${RELEASE}/${_archive}.txz" - error_exit "[ERROR]: Failed validation for ${_archive}.txz. Please retry bootstrap!" - else - info "\nValidated checksum for ${RELEASE}: ${_archive}.txz" - echo "MANIFEST: ${SHA256_DIST}" - echo "DOWNLOAD: ${SHA256_FILE}" - fi - fi - - ## extract the fetched dist files - if [ -f "${bastille_cachedir}/${RELEASE}/${_archive}.txz" ]; then - info "\nExtracting ${PLATFORM_OS} ${RELEASE} ${_archive}.txz..." - if /usr/bin/tar -C "${bastille_releasesdir}/${RELEASE}" -xf "${bastille_cachedir}/${RELEASE}/${_archive}.txz"; then - ## silence motd at container login - touch "${bastille_releasesdir}/${RELEASE}/root/.hushlogin" - touch "${bastille_releasesdir}/${RELEASE}/usr/share/skel/dot.hushlogin" - else - error_exit "[ERROR]: Failed to extract ${_archive}.txz." - fi + # Extract distfile + info "\nExtracting archive: ${archive}.txz" + if [ -f "${bastille_cachedir}/${RELEASE}/${archive}.txz" ]; then + if ! /usr/bin/tar -C "${bastille_releasesdir}/${RELEASE}" -xf "${bastille_cachedir}/${RELEASE}/${archive}.txz"; then + ERRORS=$((ERRORS + 1)) + error_continue "[ERROR]: Failed to extract archive: ${archive}.txz." fi + fi fi done - info "\nBootstrap successful." - echo "See 'bastille --help' for available commands." - + # Cleanup on error + if [ "${ERRORS}" -ne 0 ]; then + return 1 + fi + + # Silence motd at container login + touch "${bastille_releasesdir}/${RELEASE}/root/.hushlogin" + touch "${bastille_releasesdir}/${RELEASE}/usr/share/skel/dot.hushlogin" } -debootstrap_release() { +bootstrap_release_pkgbase() { - # Make sure to check/bootstrap directories first. - NOCACHEDIR=1 - RELEASE="${DIR_BOOTSTRAP}" - bootstrap_directories + info "\nUsing PkgBase..." - #check and install OS dependencies @hackacad - #ToDo: add function 'linux_pre' for sysrc etc. + ### FreeBSD ### + if [ "${PLATFORM_OS}" = "FreeBSD" ]; then - required_mods="fdescfs linprocfs linsysfs tmpfs" - linuxarc_mods="linux linux64" - for _req_kmod in ${required_mods}; do - if [ ! "$(sysrc -f /boot/loader.conf -qn ${_req_kmod}_load)" = "YES" ] && \ - [ ! "$(sysrc -f /boot/loader.conf.local -qn ${_req_kmod}_load)" = "YES" ]; then - warn "${_req_kmod} not enabled in /boot/loader.conf, Should I do that for you? (N|y)" - read answer - case "${answer}" in - [Nn][Oo]|[Nn]|"") - error_exit "Cancelled, Exiting." - ;; - [Yy][Ee][Ss]|[Yy]) - # Skip already loaded known modules. - if ! kldstat -m ${_req_kmod} >/dev/null 2>&1; then - info "\nLoading kernel module: ${_req_kmod}" - kldload -v ${_req_kmod} - fi - info "\nPersisting module: ${_req_kmod}" - sysrc -f /boot/loader.conf ${_req_kmod}_load=YES - ;; - esac - else - # If already set in /boot/loader.conf, check and try to load the module. - if ! kldstat -m ${_req_kmod} >/dev/null 2>&1; then - info "\nLoading kernel module: ${_req_kmod}" - kldload -v ${_req_kmod} + local abi="${PLATFORM_OS}:${MAJOR_VERSION}:${HW_MACHINE_ARCH}" + local fingerprints="${bastille_releasesdir}/${RELEASE}/usr/share/keys/pkgbase-${MAJOR_VERSION}" + local host_fingerprintsdir="/usr/share/keys/pkgbase-${MAJOR_VERSION}" + local release_fingerprintsdir="${bastille_releasesdir}/${RELEASE}/usr/share/keys" + if [ "${FREEBSD_BRANCH}" = "release" ]; then + local repo_name="FreeBSD-base-release-${MINOR_VERSION}" + elif [ "${FREEBSD_BRANCH}" = "current" ]; then + local repo_name="FreeBSD-base-latest" + fi + local repo_dir="${bastille_sharedir}/pkgbase" + + # Verify trusted pkg keys + if [ ! -f "${host_fingerprintsdir}/trusted/awskms-${MAJOR_VERSION}" ]; then + if ! fetch -o "${host_fingerprintsdir}/trusted" https://cgit.freebsd.org/src/tree/share/keys/pkgbase-${MAJOR_VERSION}/trusted/awskms-${MAJOR_VERSION} + then + ERRORS=$((ERRORS + 1)) + error_notify "[ERROR]: Failed to fetch trusted pkg keys." + return 1 + fi + fi + if [ ! -f "${host_fingerprintsdir}/trusted/backup-signing-${MAJOR_VERSION}" ]; then + if ! fetch -o "${host_fingerprintsdir}/trusted" https://cgit.freebsd.org/src/tree/share/keys/pkgbase-${MAJOR_VERSION}/trusted/backup-signing-${MAJOR_VERSION} + then + ERRORS=$((ERRORS + 1)) + error_notify "[ERROR]: Failed to fetch trusted backup pkg keys." + return 1 fi fi - done - # Mandatory Linux modules/rc. - for _lin_kmod in ${linuxarc_mods}; do - if ! kldstat -n ${_lin_kmod} >/dev/null 2>&1; then - info "\nLoading kernel module: ${_lin_kmod}" - kldload -v ${_lin_kmod} + # Validate COPYRIGHT existence + if [ -f "${bastille_releasesdir}/${RELEASE}/COPYRIGHT" ]; then + # Verify package sets + bastille_pkgbase_packages=$(echo "${bastille_pkgbase_packages}" | sed "s/base-jail//") + if [ -z "${bastille_pkgbase_packages}" ]; then + info "\nBootstrap appears complete!" + exit 0 + fi + fi + + # Copy fingerprints into releasedir + if ! mkdir -p "${release_fingerprintsdir}"; then + ERRORS=$((ERRORS + 1)) + error_notify "[ERROR]: Faild to create fingerprints directory." + return 1 + fi + if ! cp -a "${host_fingerprintsdir}" "${release_fingerprintsdir}"; then + ERRORS=$((ERRORS + 1)) + error_notify "[ERROR]: Failed to copy fingerprints directory." + return 1 + fi + + info "\nUpdating ${repo_name} repository..." + + # Update PkgBase repo + if ! pkg --rootdir "${bastille_releasesdir}/${RELEASE}" \ + --repo-conf-dir="${repo_dir}" \ + -o IGNORE_OSVERSION="yes" \ + -o VERSION_MAJOR="${MAJOR_VERSION}" \ + -o VERSION_MINOR="${MINOR_VERSION}" \ + -o ABI="${abi}" \ + -o ASSUME_ALWAYS_YES="yes" \ + -o FINGERPRINTS="${fingerprints}" \ + update -r "${repo_name}"; then + + ERRORS=$((ERRORS + 1)) + error_notify "[ERROR]: Failed to update repository: ${repo_name}" + fi + + info "\nInstalling packages..." + + for package in ${bastille_pkgbase_packages}; do + + # Check if package set is already installed + if ! pkg --rootdir "${bastille_releasesdir}/${RELEASE}" info "FreeBSD-set-${package}" 2>/dev/null; then + # Install package set + if ! pkg --rootdir "${bastille_releasesdir}/${RELEASE}" \ + --repo-conf-dir="${repo_dir}" \ + -o IGNORE_OSVERSION="yes" \ + -o VERSION_MAJOR="${MAJOR_VERSION}" \ + -o VERSION_MINOR="${MINOR_VERSION}" \ + -o ABI="${abi}" \ + -o ASSUME_ALWAYS_YES="yes" \ + -o FINGERPRINTS="${fingerprints}" \ + install -r "${repo_name}" \ + FreeBSD-set-"${package}"; then + + ERRORS=$((ERRORS + 1)) + error_continue "[ERROR]: Failed to install package set: ${package}" + fi + else + info "\nPackage set already installed: ${package}" fi done - if [ ! "$(sysrc -qn linux_enable)" = "YES" ] && \ - [ ! "$(sysrc -f /etc/rc.conf.local -qn linux_enable)" = "YES" ]; then - sysrc linux_enable=YES + # Cleanup on error + if [ "${ERRORS}" -ne 0 ]; then + return 1 fi - if ! which -s debootstrap; then - warn "Debootstrap not found. Should it be installed? (N|y)" - read answer - case $answer in - [Nn][Oo]|[Nn]|"") - error_exit "[ERROR]: debootstrap is required for boostrapping a Linux jail." - ;; - [Yy][Ee][Ss]|[Yy]) - pkg install -y debootstrap - ;; + # Silence motd at login + touch "${bastille_releasesdir}/${RELEASE}/root/.hushlogin" + touch "${bastille_releasesdir}/${RELEASE}/usr/share/skel/dot.hushlogin" + fi +} + +bootstrap_release_linux() { + + if [ "${PLATFORM_OS}" = "Linux/Debian" ] || [ "${PLATFORM_OS}" = "Linux/Ubuntu" ]; then + # Fetch the Linux flavor + if ! debootstrap --foreign --arch=${ARCH_BOOTSTRAP} --no-check-gpg ${LINUX_FLAVOR} "${bastille_releasesdir}"/${RELEASE}; then + ERRORS=$((ERRORS + 1)) + error_notify "[ERROR]: Failed to fetch Linux release: ${LINUX_FLAVOR}" + return 1 + fi + + # Set necessary settings + case "${LINUX_FLAVOR}" in + bionic|focal|jammy|buster|bullseye|bookworm|noble) + info "Increasing APT::Cache-Start" + echo "APT::Cache-Start 251658240;" > "${bastille_releasesdir}"/${RELEASE}/etc/apt/apt.conf.d/00aptitude + ;; esac fi - - # Fetch the Linux flavor - info "\nFetching ${PLATFORM_OS} distfiles..." - if ! debootstrap --foreign --arch=${ARCH_BOOTSTRAP} --no-check-gpg ${LINUX_FLAVOR} "${bastille_releasesdir}"/${DIR_BOOTSTRAP}; then - - ## perform cleanup only for stale/empty directories on failure - if checkyesno bastille_zfs_enable; then - if [ -n "${bastille_zfs_zpool}" ]; then - if [ ! "$(ls -A "${bastille_releasesdir}/${DIR_BOOTSTRAP}")" ]; then - zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/releases/${DIR_BOOTSTRAP}" - fi - fi - fi - - if [ -d "${bastille_releasesdir}/${DIR_BOOTSTRAP}" ]; then - if [ ! "$(ls -A "${bastille_releasesdir}/${DIR_BOOTSTRAP}")" ]; then - rm -rf "${bastille_releasesdir:?}/${DIR_BOOTSTRAP}" - fi - fi - error_exit "[ERROR]: Bootstrap failed." - fi - - case "${LINUX_FLAVOR}" in - bionic|focal|jammy|buster|bullseye|bookworm) - info "Increasing APT::Cache-Start" - echo "APT::Cache-Start 251658240;" > "${bastille_releasesdir}"/${DIR_BOOTSTRAP}/etc/apt/apt.conf.d/00aptitude - ;; - esac - - info "\nBootstrap successful." - info "\nSee 'bastille --help' for available commands." } bootstrap_template() { @@ -413,60 +458,73 @@ bootstrap_template() { fi ## define basic variables - _url=${BASTILLE_TEMPLATE_URL} - _user=${BASTILLE_TEMPLATE_USER} - _repo=${BASTILLE_TEMPLATE_REPO%.*} # Remove the trailing ".git" - _raw_template_dir=${bastille_templatesdir}/${_user}/${_repo} + url=${BASTILLE_TEMPLATE_URL} + user=${BASTILLE_TEMPLATE_USER} + repo=${BASTILLE_TEMPLATE_REPO%.*} # Remove the trailing ".git" + raw_template_dir=${bastille_templatesdir}/${user}/${repo} ## support for non-git if ! which -s git; then error_notify "Git not found." error_exit "Not yet implemented." else - if [ ! -d "${_raw_template_dir}/.git" ]; then - git clone "${_url}" "${_raw_template_dir}" ||\ + if [ ! -d "${raw_template_dir}/.git" ]; then + git clone "${url}" "${raw_template_dir}" ||\ error_notify "Clone unsuccessful." - elif [ -d "${_raw_template_dir}/.git" ]; then - git -C "${_raw_template_dir}" pull ||\ + elif [ -d "${raw_template_dir}/.git" ]; then + git -C "${raw_template_dir}" pull ||\ error_notify "Template update unsuccessful." fi fi - if [ ! -f ${_raw_template_dir}/Bastillefile ]; then + if [ ! -f ${raw_template_dir}/Bastillefile ]; then # Extract template in project/template format - find "${_raw_template_dir}" -type f -name Bastillefile | while read -r _file; do - _template_dir="$(dirname ${_file})" - _project_dir="$(dirname ${_template_dir})" - _template_name="$(basename ${_template_dir})" - _project_name="$(basename ${_project_dir})" - _complete_template="${_project_name}/${_template_name}" - cp -fR "${_project_dir}" "${bastille_templatesdir}" - bastille verify "${_complete_template}" + find "${raw_template_dir}" -type f -name Bastillefile | while read -r file; do + template_dir="$(dirname ${file})" + project_dir="$(dirname ${template_dir})" + template_name="$(basename ${template_dir})" + project_name="$(basename ${project_dir})" + complete_template="${project_name}/${template_name}" + cp -fR "${project_dir}" "${bastille_templatesdir}" + bastille verify "${complete_template}" done - + # Remove the cloned repo - if [ -n "${_user}" ]; then - rm -r "${bastille_templatesdir:?}/${_user:?}" + if [ -n "${user}" ]; then + rm -r "${bastille_templatesdir:?}/${user:?}" fi - + else # Verify a single template - bastille verify "${_user}/${_repo}" + bastille verify "${user}/${repo}" fi } # Handle options. +PKGBASE=0 +ERRORS=0 while [ "$#" -gt 0 ]; do case "${1}" in -h|--help|help) usage ;; + -p|--pkgbase) + PKGBASE=1 + shift + ;; -x|--debug) enable_debug shift ;; - -*) - error_exit "[ERROR]: Unknown Option: \"${1}\"" + -*) + for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do + case ${_opt} in + p) PKGBASE=1 ;; + x) enable_debug ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + esac + done + shift ;; *) break @@ -476,13 +534,13 @@ done RELEASE="${1}" OPTION="${2}" -NOCACHEDIR= +NOCACHEDIR="" HW_MACHINE=$(sysctl hw.machine | awk '{ print $2 }') HW_MACHINE_ARCH=$(sysctl hw.machine_arch | awk '{ print $2 }') bastille_root_check -#Validate if ZFS is enabled in rc.conf and bastille.conf. +# Validate if ZFS is enabled in rc.conf and bastille.conf. if [ "$(sysrc -n zfs_enable)" = "YES" ] && ! checkyesno bastille_zfs_enable; then warn "ZFS is enabled in rc.conf but not bastille.conf. Do you want to continue? (N|y)" read answer @@ -514,7 +572,6 @@ if checkyesno bastille_zfs_enable; then fi # bootstrapping from aarch64/arm64 Debian or Ubuntu require a different value for ARCH -# create a new variable if [ "${HW_MACHINE_ARCH}" = "aarch64" ]; then HW_MACHINE_ARCH_LINUX="arm64" else @@ -538,76 +595,52 @@ fi [ -n "${BASTILLE_URL_MIDNIGHTBSD}" ] && bastille_url_midnightbsd="${BASTILLE_URL_MIDNIGHTBSD}" ## Filter sane release names -case "${1}" in +case "${RELEASE}" in [2-4].[0-9]*) - ## check for MidnightBSD releases name + ### MidnightBSD ### + PLATFORM_OS="MidnightBSD" NAME_VERIFY=$(echo "${RELEASE}") UPSTREAM_URL="${bastille_url_midnightbsd}${HW_MACHINE_ARCH}/${NAME_VERIFY}" - PLATFORM_OS="MidnightBSD" - validate_release_url ;; - *-CURRENT|*-current) - ## check for FreeBSD releases name - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]{2,2})\.[0-9](-CURRENT)$' | tr '[:lower:]' '[:upper:]') - UPSTREAM_URL=$(echo "${bastille_url_freebsd}${HW_MACHINE}/${HW_MACHINE_ARCH}/${NAME_VERIFY}" | sed 's/releases/snapshots/') + *-current|*-CURRENT) + ### FreeBSD ### PLATFORM_OS="FreeBSD" - validate_release_url + NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]+)\.[0-9](-CURRENT)$' | tr '[:lower:]' '[:upper:]') + UPSTREAM_URL=$(echo "${bastille_url_freebsd}${HW_MACHINE}/${HW_MACHINE_ARCH}/${NAME_VERIFY}" | sed 's/releases/snapshots/') + FREEBSD_BRANCH="current" + ;; + *\.*-stable|*\.*-STABLE) + ### FreeBSD ### + PLATFORM_OS="FreeBSD" + NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]+)\.[0-9](-STABLE)$' | tr '[:lower:]' '[:upper:]') + UPSTREAM_URL=$(echo "${bastille_url_freebsd}${HW_MACHINE}/${HW_MACHINE_ARCH}/${NAME_VERIFY}" | sed 's/releases/snapshots/') + FREEBSD_BRANCH="current" ;; *-RELEASE|*-release|*-RC[1-9]|*-rc[1-9]|*-BETA[1-9]) - ## check for FreeBSD releases name - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([0-9]{1,2})\.[0-9](-RELEASE|-RC[1-9]|-BETA[1-9])$' | tr '[:lower:]' '[:upper:]') - UPSTREAM_URL="${bastille_url_freebsd}${HW_MACHINE}/${HW_MACHINE_ARCH}/${NAME_VERIFY}" + ### FreeBSD ### PLATFORM_OS="FreeBSD" - validate_release_url + NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([0-9]+)\.[0-9](-RELEASE|-RC[1-9]|-BETA[1-9])$' | tr '[:lower:]' '[:upper:]') + UPSTREAM_URL="${bastille_url_freebsd}${HW_MACHINE}/${HW_MACHINE_ARCH}/${NAME_VERIFY}" + FREEBSD_BRANCH="release" ;; - *-stable-LAST|*-STABLE-last|*-stable-last|*-STABLE-LAST) - ## check for HardenedBSD releases name(previous infrastructure, keep for reference) - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]{2,2})(-stable-last)$' | sed 's/STABLE/stable/g' | sed 's/last/LAST/g') - UPSTREAM_URL="${bastille_url_hardenedbsd}${HW_MACHINE}/${HW_MACHINE_ARCH}/hardenedbsd-${NAME_VERIFY}" + current|CURRENT) + ### HardenedBSD ### PLATFORM_OS="HardenedBSD" - validate_release_url + NAME_VERIFY=$(echo "${RELEASE}" | sed 's/CURRENT/current/g') + UPSTREAM_URL="${bastille_url_hardenedbsd}${NAME_VERIFY}/${HW_MACHINE}/${HW_MACHINE_ARCH}/installer/LATEST" ;; - *-stable-build-[0-9]*|*-STABLE-BUILD-[0-9]*) - ## check for HardenedBSD(specific stable build releases) - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '([0-9]{1,2})(-stable-build)-([0-9]{1,3})$' | sed 's/BUILD/build/g' | sed 's/STABLE/stable/g') - NAME_RELEASE=$(echo "${NAME_VERIFY}" | sed 's/-build-[0-9]\{1,3\}//g') - NAME_BUILD=$(echo "${NAME_VERIFY}" | sed 's/[0-9]\{1,2\}-stable-//g') - UPSTREAM_URL="${bastille_url_hardenedbsd}${NAME_RELEASE}/${HW_MACHINE}/${HW_MACHINE_ARCH}/${NAME_BUILD}" + [1-9]*-stable|[1-9]*-STABLE) + ### HardenedBSD ### PLATFORM_OS="HardenedBSD" - validate_release_url - ;; - *-stable-build-latest|*-stable-BUILD-LATEST|*-STABLE-BUILD-LATEST) - ## check for HardenedBSD(latest stable build release) - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '([0-9]{1,2})(-stable-build-latest)$' | sed 's/STABLE/stable/g' | sed 's/build/BUILD/g' | sed 's/latest/LATEST/g') - NAME_RELEASE=$(echo "${NAME_VERIFY}" | sed 's/-BUILD-LATEST//g') - NAME_BUILD=$(echo "${NAME_VERIFY}" | sed 's/[0-9]\{1,2\}-stable-BUILD-//g') - UPSTREAM_URL="${bastille_url_hardenedbsd}${NAME_RELEASE}/${HW_MACHINE}/${HW_MACHINE_ARCH}/installer/${NAME_BUILD}" - PLATFORM_OS="HardenedBSD" - validate_release_url - ;; - current-build-[0-9]*|CURRENT-BUILD-[0-9]*) - ## check for HardenedBSD(specific current build releases) - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '(current-build)-([0-9]{1,3})' | sed 's/BUILD/build/g' | sed 's/CURRENT/current/g') - NAME_RELEASE=$(echo "${NAME_VERIFY}" | sed 's/current-.*/current/g') - NAME_BUILD=$(echo "${NAME_VERIFY}" | sed 's/current-//g') - UPSTREAM_URL="${bastille_url_hardenedbsd}${NAME_RELEASE}/${HW_MACHINE}/${HW_MACHINE_ARCH}/${NAME_BUILD}" - PLATFORM_OS="HardenedBSD" - validate_release_url - ;; - current-build-latest|current-BUILD-LATEST|CURRENT-BUILD-LATEST) - ## check for HardenedBSD(latest current build release) - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '(current-build-latest)' | sed 's/CURRENT/current/g' | sed 's/build/BUILD/g' | sed 's/latest/LATEST/g') - NAME_RELEASE=$(echo "${NAME_VERIFY}" | sed 's/current-.*/current/g') - NAME_BUILD=$(echo "${NAME_VERIFY}" | sed 's/current-BUILD-//g') - UPSTREAM_URL="${bastille_url_hardenedbsd}${NAME_RELEASE}/${HW_MACHINE}/${HW_MACHINE_ARCH}/installer/${NAME_BUILD}" - PLATFORM_OS="HardenedBSD" - validate_release_url + NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]+)(-stable)$' | sed 's/STABLE/stable/g') + UPSTREAM_URL="${bastille_url_hardenedbsd}${NAME_VERIFY}/${HW_MACHINE}/${HW_MACHINE_ARCH}/installer/LATEST" ;; http?://*/*/*) BASTILLE_TEMPLATE_URL=${1} BASTILLE_TEMPLATE_USER=$(echo "${1}" | awk -F / '{ print $4 }') BASTILLE_TEMPLATE_REPO=$(echo "${1}" | awk -F / '{ print $5 }') bootstrap_template + exit 0 ;; git@*:*/*) BASTILLE_TEMPLATE_URL=${1} @@ -615,59 +648,90 @@ case "${1}" in BASTILLE_TEMPLATE_USER=$(echo "${git_repository}" | awk -F / '{ print $1 }') BASTILLE_TEMPLATE_REPO=$(echo "${git_repository}" | awk -F / '{ print $2 }') bootstrap_template + exit 0 ;; - #adding Ubuntu Bionic as valid "RELEASE" for POC @hackacad ubuntu_bionic|bionic|ubuntu-bionic) - PLATFORM_OS="Ubuntu/Linux" + PLATFORM_OS="Linux/Ubuntu" LINUX_FLAVOR="bionic" - DIR_BOOTSTRAP="Ubuntu_1804" + NAME_VERIFY="Ubuntu_1804" ARCH_BOOTSTRAP=${HW_MACHINE_ARCH_LINUX} - debootstrap_release ;; ubuntu_focal|focal|ubuntu-focal) - PLATFORM_OS="Ubuntu/Linux" + PLATFORM_OS="Linux/Ubuntu" LINUX_FLAVOR="focal" - DIR_BOOTSTRAP="Ubuntu_2004" + NAME_VERIFY="Ubuntu_2004" ARCH_BOOTSTRAP=${HW_MACHINE_ARCH_LINUX} - debootstrap_release ;; ubuntu_jammy|jammy|ubuntu-jammy) - PLATFORM_OS="Ubuntu/Linux" + PLATFORM_OS="Linux/Ubuntu" LINUX_FLAVOR="jammy" - DIR_BOOTSTRAP="Ubuntu_2204" + NAME_VERIFY="Ubuntu_2204" ARCH_BOOTSTRAP=${HW_MACHINE_ARCH_LINUX} - debootstrap_release ;; - debian_buster|buster|debian-buster) - PLATFORM_OS="Debian/Linux" + ubuntu_noble|noble|ubuntu-noble) + PLATFORM_OS="Linux/Ubuntu" + LINUX_FLAVOR="noble" + NAME_VERIFY="Ubuntu_2404" + ARCH_BOOTSTRAP=${HW_MACHINE_ARCH_LINUX} + ;; + debian_buster|buster|debian-buster|debian10|Debian10) + PLATFORM_OS="Linux/Debian" LINUX_FLAVOR="buster" - DIR_BOOTSTRAP="Debian10" + NAME_VERIFY="Debian10" ARCH_BOOTSTRAP=${HW_MACHINE_ARCH_LINUX} - debootstrap_release ;; - debian_bullseye|bullseye|debian-bullseye) - PLATFORM_OS="Debian/Linux" + debian_bullseye|bullseye|debian-bullseye|debian11|Debian11) + PLATFORM_OS="Linux/Debian" LINUX_FLAVOR="bullseye" - DIR_BOOTSTRAP="Debian11" + NAME_VERIFY="Debian11" ARCH_BOOTSTRAP=${HW_MACHINE_ARCH_LINUX} - debootstrap_release ;; - debian_bookworm|bookworm|debian-bookworm) - PLATFORM_OS="Debian/Linux" + debian_bookworm|bookworm|debian-bookworm|debian12|Debian12) + PLATFORM_OS="Linux/Debian" LINUX_FLAVOR="bookworm" - DIR_BOOTSTRAP="Debian12" + NAME_VERIFY="Debian12" ARCH_BOOTSTRAP=${HW_MACHINE_ARCH_LINUX} - debootstrap_release ;; *) usage ;; esac -case "${OPTION}" in - update) - bastille update "${RELEASE}" +# Bootstrap +case ${PLATFORM_OS} in + FreeBSD|HardenedBSD|MidnightBSD) + validate_release + bootstrap_directories + if [ "${PKGBASE}" -eq 1 ]; then + bootstrap_release_pkgbase || cleanup_directories + else + bootstrap_release_legacy || cleanup_directories + fi + ;; + Linux/Ubuntu|Linux/Debian) + validate_release + bootstrap_directories + bootstrap_release_linux || cleanup_directories + ;; + *) + error_exit "[ERROR]: Unsupported platform." ;; esac -echo +# Check for errors +if [ "${ERRORS}" -eq 0 ]; then + + # Check for OPTION=update + case "${OPTION}" in + update) + bastille update "${RELEASE}" + ;; + esac + + # Success + info "\nBootstrap successful." + echo "See 'bastille --help' for available commands." + echo +else + error_exit "[ERROR]: Bootstrap failed!" +fi diff --git a/usr/local/share/bastille/clone.sh b/usr/local/share/bastille/clone.sh index de2b21de..181bc3a3 100644 --- a/usr/local/share/bastille/clone.sh +++ b/usr/local/share/bastille/clone.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille clone [option(s)] TARGET NEW_NAME IP" cat << EOF - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. Cannot be used with [-l|--live]. @@ -70,7 +70,7 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; @@ -98,14 +98,16 @@ fi TARGET="${1}" NEWNAME="${2}" IP="${3}" +CLONE_INTERFACE_COUNT=0 bastille_root_check set_target_single "${TARGET}" -## don't allow for dots(.) in container names -if echo "${NEWNAME}" | grep -q "[.]"; then - error_exit "[ERROR]: Jail names may not contain a dot(.)!" -fi +clone_validate_jail_name() { + if echo "${NEWNAME}" | grep -q "[.]"; then + error_exit "[ERROR]: Jail names may not contain a dot(.)!" + fi +} validate_ip() { @@ -230,217 +232,222 @@ update_jailconf() { update_jailconf_vnet() { - local _jail_conf="${bastille_jailsdir}/${NEWNAME}/jail.conf" - local _rc_conf="${bastille_jailsdir}/${NEWNAME}/root/etc/rc.conf" + local jail_config="${bastille_jailsdir}/${NEWNAME}/jail.conf" + local jail_rc_config="${bastille_jailsdir}/${NEWNAME}/root/etc/rc.conf" # Determine number of interfaces if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then - local _if_list="$(grep -Eo 'e[0-9]+a_[^;" ]+' ${_jail_conf} | sort -u)" + local if_list="$(grep -Eo 'e[0-9]+a_[^;" ]+' ${jail_config} | sort -u)" elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then - local _if_list="$(grep -Eo 'ng[0-9]+_[^;" ]+' ${_jail_conf} | sort -u)" + local if_list="$(grep -Eo 'ng[0-9]+_[^;" ]+' ${jail_config} | sort -u)" fi - for _if in ${_if_list}; do + # We need to following to prevent incremental bastille1, bastille2 etc... + local reuse_new_suffix="" - local _old_if_prefix="$(echo ${_if} | awk -F'_' '{print $1}')" - local _old_if_suffix="$(echo ${_if} | awk -F'_' '{print $2}')" + for if in ${if_list}; do - # For if_bridge network type + CLONE_INTERFACE_COUNT=$((CLONE_INTERFACE_COUNT + 1)) + local old_if_prefix="$(echo ${if} | awk -F'_' '{print $1}')" + local old_if_suffix="$(echo ${if} | awk -F'_' '{print $2}')" + + # For if_bridge network type if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then - local _epair_num="$(echo "${_old_if_prefix}" | grep -Eo "[0-9]+")" - local _old_host_epair="${_if}" - local _old_jail_epair="${_old_if_prefix%a}b_${_old_if_suffix}" - - if [ "$(echo -n "e${_epair_num}a_${NEWNAME}" | awk '{print length}')" -lt 16 ]; then + local epair_num="$(echo "${old_if_prefix}" | grep -Eo "[0-9]+")" + local old_host_epair="${if}" + local old_jail_epair="${old_if_prefix%a}b_${old_if_suffix}" + + if [ "$(echo -n "e${epair_num}a_${NEWNAME}" | awk '{print length}')" -lt 16 ]; then # Generate new epair name - local _new_host_epair="e${_epair_num}a_${NEWNAME}" - local _new_jail_epair="e${_epair_num}b_${NEWNAME}" + local new_host_epair="e${epair_num}a_${NEWNAME}" + local new_jail_epair="e${epair_num}b_${NEWNAME}" else - name_prefix="$(echo ${NEWNAME} | cut -c1-7)" - name_suffix="$(echo ${NEWNAME} | rev | cut -c1-2 | rev)" - local _new_host_epair="e${_epair_num}a_${name_prefix}xx${name_suffix}" - local _new_jail_epair="e${_epair_num}b_${name_prefix}xx${name_suffix}" + if [ -z "${reuse_new_suffix}" ]; then + get_bastille_epair_count + local bastille_epair_num=1 + while echo "${BASTILLE_EPAIR_LIST}" | grep -oq "bastille${bastille_epair_num}"; do + bastille_epair_num=$((bastille_epair_num + 1)) + done + local new_host_epair="e${epair_num}a_bastille${bastille_epair_num}" + local new_jail_epair="e${epair_num}b_bastille${bastille_epair_num}" + local reuse_new_suffix="bastille${bastille_epair_num}" + else + local new_host_epair="e${epair_num}a_${reuse_new_suffix}" + local new_jail_epair="e${epair_num}b_${reuse_new_suffix}" + fi fi - local _new_if_prefix="$(echo ${_new_host_epair} | awk -F'_' '{print $1}')" - local _new_if_suffix="$(echo ${_new_host_epair} | awk -F'_' '{print $2}')" + local new_if_prefix="$(echo ${new_host_epair} | awk -F'_' '{print $1}')" + local new_if_suffix="$(echo ${new_host_epair} | awk -F'_' '{print $2}')" - if grep "${_old_if_suffix}" "${_jail_conf}" | grep -oq "jib addm"; then + if grep "${old_if_suffix}" "${jail_config}" | grep -oq "jib addm"; then # For -V jails - # Replace host epair name in jail.conf - sed -i '' "s|jib addm ${_old_if_suffix}|jib addm ${_new_if_suffix}|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} ether|${_new_host_epair} ether|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} destroy|${_new_host_epair} destroy|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} description|${_new_host_epair} description|g" "${_jail_conf}" + # Replace host epair name in jail.conf + sed -i '' "s|jib addm ${old_if_suffix}\>|jib addm ${new_if_suffix}|g" "${jail_config}" + sed -i '' "s|\<${old_host_epair} ether|${new_host_epair} ether|g" "${jail_config}" + sed -i '' "s|\<${old_host_epair} destroy|${new_host_epair} destroy|g" "${jail_config}" + sed -i '' "s|\<${old_host_epair} description|${new_host_epair} description|g" "${jail_config}" # Replace jail epair name in jail.conf - sed -i '' "s|= ${_old_jail_epair};|= ${_new_jail_epair};|g" "${_jail_conf}" - sed -i '' "s|${_old_jail_epair} ether|${_new_jail_epair} ether|g" "${_jail_conf}" + sed -i '' "s|= ${old_jail_epair};|= ${new_jail_epair};|g" "${jail_config}" + sed -i '' "s|\<${old_jail_epair} ether|${new_jail_epair} ether|g" "${jail_config}" # If jail had a static MAC, generate one for clone - if grep ether ${_jail_conf} | grep -qoc ${_new_jail_epair}; then - local external_interface="$(grep ${_new_if_suffix} ${_jail_conf} | grep -o 'addm.*' | awk '{print $3}' | sed 's/["|;]//g')" + if grep ether ${jail_config} | grep -qoc ${new_jail_epair}; then + local external_interface="$(grep ${new_if_suffix} ${jail_config} | grep -o 'addm.*' | awk '{print $3}' | sed 's/["|;]//g')" generate_static_mac "${NEWNAME}" "${external_interface}" - sed -i '' "s|${_new_jail_epair} ether.*:.*:.*:.*:.*:.*a\";|${_new_jail_epair} ether ${macaddr}a\";|" "${_jail_conf}" - sed -i '' "s|${_new_jail_epair} ether.*:.*:.*:.*:.*:.*b\";|${_new_jail_epair} ether ${macaddr}b\";|" "${_jail_conf}" + sed -i '' "s|\<${new_jail_epair} ether.*:.*:.*:.*:.*:.*a\";|${new_jail_epair} ether ${macaddr}a\";|" "${jail_config}" + sed -i '' "s|\<${new_jail_epair} ether.*:.*:.*:.*:.*:.*b\";|${new_jail_epair} ether ${macaddr}b\";|" "${jail_config}" fi # Replace epair description - sed -i '' "s|host interface for Bastille jail ${TARGET}|host interface for Bastille jail ${NEWNAME}|g" "${_jail_conf}" + sed -i '' "s|host interface for Bastille jail ${TARGET}\>|host interface for Bastille jail ${NEWNAME}|g" "${jail_config}" # Replace epair name in /etc/rc.conf - sed -i '' "/ifconfig/ s|${_old_jail_epair}|${_new_jail_epair}|g" "${_rc_conf}" + sed -i '' "s|ifconfig_${old_jail_epair}_name|ifconfig_${new_jail_epair}_name|g" "${jail_rc_config}" + else + # For -B jails - # Replace host epair name in jail.conf - sed -i '' "s|up name ${_old_host_epair}|up name ${_new_host_epair}|g" "${_jail_conf}" - sed -i '' "s|addm ${_old_host_epair}|addm ${_new_host_epair}|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} ether|${_new_host_epair} ether|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} destroy|${_new_host_epair} destroy|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} description|${_new_host_epair} description|g" "${_jail_conf}" + # Replace host epair name in jail.conf + sed -i '' "s|up name ${old_host_epair}\>|up name ${new_host_epair}|g" "${jail_config}" + sed -i '' "s|addm ${old_host_epair}\>|addm ${new_host_epair}|g" "${jail_config}" + sed -i '' "s|\<${old_host_epair} ether|${new_host_epair} ether|g" "${jail_config}" + sed -i '' "s|\<${old_host_epair} destroy|${new_host_epair} destroy|g" "${jail_config}" + sed -i '' "s|\<${old_host_epair} description|${new_host_epair} description|g" "${jail_config}" # Replace jail epair name in jail.conf - sed -i '' "s|= ${_old_jail_epair};|= ${_new_jail_epair};|g" "${_jail_conf}" - sed -i '' "s|up name ${_old_jail_epair}|up name ${_new_jail_epair}|g" "${_jail_conf}" - sed -i '' "s|${_old_jail_epair} ether|${_new_jail_epair} ether|g" "${_jail_conf}" + sed -i '' "s|= ${old_jail_epair};|= ${new_jail_epair};|g" "${jail_config}" + sed -i '' "s|up name ${old_jail_epair}\>|up name ${new_jail_epair}|g" "${jail_config}" + sed -i '' "s|\<${old_jail_epair} ether|${new_jail_epair} ether|g" "${jail_config}" # If jail had a static MAC, generate one for clone - if grep -q ether ${_jail_conf}; then - local external_interface="$(grep "e${_epair_num}a" ${_jail_conf} | grep -o '[^ ]* addm' | awk '{print $1}')" + if grep -q ether ${jail_config}; then + local external_interface="$(grep "e${epair_num}a" ${jail_config} | grep -o '[^ ]* addm' | awk '{print $1}')" generate_static_mac "${NEWNAME}" "${external_interface}" - sed -i '' "s|${_new_host_epair} ether.*:.*:.*:.*:.*:.*a\";|${_new_host_epair} ether ${macaddr}a\";|" "${_jail_conf}" - sed -i '' "s|${_new_jail_epair} ether.*:.*:.*:.*:.*:.*b\";|${_new_jail_epair} ether ${macaddr}b\";|" "${_jail_conf}" + sed -i '' "s|\<${new_host_epair} ether.*:.*:.*:.*:.*:.*a\";|${new_host_epair} ether ${macaddr}a\";|" "${jail_config}" + sed -i '' "s|\<${new_jail_epair} ether.*:.*:.*:.*:.*:.*b\";|${new_jail_epair} ether ${macaddr}b\";|" "${jail_config}" fi # Replace epair description - sed -i '' "s|host interface for Bastille jail ${TARGET}|host interface for Bastille jail ${NEWNAME}|g" "${_jail_conf}" + sed -i '' "s|host interface for Bastille jail ${TARGET}\>|host interface for Bastille jail ${NEWNAME}|g" "${jail_config}" # Replace epair name in /etc/rc.conf - sed -i '' "/ifconfig/ s|${_old_jail_epair}|${_new_jail_epair}|g" "${_rc_conf}" + sed -i '' "s|ifconfig_${old_jail_epair}_name|ifconfig_${new_jail_epair}_name|g" "${jail_rc_config}" + fi # Update /etc/rc.conf - local _jail_vnet="$(grep ${_old_jail_epair} "${_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" - local _jail_vnet_vlan="$(grep "vlans_${_jail_vnet}" "${_rc_conf}" | sed 's/.*=//g')" - sed -i '' "s|${_old_jail_epair}_name|${_new_jail_epair}_name|" "${_rc_conf}" + local jail_vnet="$(grep ${old_jail_epair} "${jail_rc_config}" | grep -Eo -m 1 "vnet[0-9]+")" + local jail_vnet_vlan="$(grep "vlans_${jail_vnet}" "${jail_rc_config}" | sed 's/.*=//g')" + # IP4 if [ -n "${IP4_ADDR}" ]; then - if grep "vnet0" "${_rc_conf}" | grep -q "${_new_jail_epair}_name"; then - if [ -n "${_jail_vnet_vlan}" ]; then + if grep "vnet0" "${jail_rc_config}" | grep -q "${new_jail_epair}_name"; then + if [ -n "${jail_vnet_vlan}" ]; then if [ "${IP4_ADDR}" = "0.0.0.0" ] || [ "${IP4_ADDR}" = "DHCP" ] || [ "${IP4_ADDR}" = "SYNCDHCP" ]; then - sysrc -f "${_rc_conf}" ifconfig_vnet0_${_jail_vnet_vlan}="SYNCDHCP" + sysrc -f "${jail_rc_config}" ifconfig_vnet0_${jail_vnet_vlan}="SYNCDHCP" else - sysrc -f "${_rc_conf}" ifconfig_vnet0_${_jail_vnet_vlan}="inet ${IP4_ADDR}" + sysrc -f "${jail_rc_config}" ifconfig_vnet0_${jail_vnet_vlan}="inet ${IP4_ADDR}" fi else if [ "${IP4_ADDR}" = "0.0.0.0" ] || [ "${IP4_ADDR}" = "DHCP" ] || [ "${IP4_ADDR}" = "SYNCDHCP" ]; then - sysrc -f "${_rc_conf}" ifconfig_vnet0="SYNCDHCP" + sysrc -f "${jail_rc_config}" ifconfig_vnet0="SYNCDHCP" else - sysrc -f "${_rc_conf}" ifconfig_vnet0="inet ${IP4_ADDR}" + sysrc -f "${jail_rc_config}" ifconfig_vnet0="inet ${IP4_ADDR}" fi fi else - if [ -n "${_jail_vnet_vlan}" ]; then - sysrc -f "${_rc_conf}" ifconfig_${_jail_vnet}_${_jail_vnet_vlan}="SYNCDHCP" + if [ -n "${jail_vnet_vlan}" ]; then + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}_${jail_vnet_vlan}="" else - sysrc -f "${_rc_conf}" ifconfig_${_jail_vnet}="SYNCDHCP" - fi - fi - fi - # IP6 - if [ -n "${IP6_ADDR}" ]; then - if grep "vnet0" "${_rc_conf}" | grep -q "${_new_jail_epair}_name"; then - if [ "${IP6_ADDR}" = "SLAAC" ]; then - sysrc -f "${_rc_conf}" ifconfig_vnet0_ipv6="inet6 -ifdisabled accept_rtadv" - else - sysrc -f "${_rc_conf}" ifconfig_vnet0_ipv6="inet6 -ifdisabled ${IP6_ADDR}" - fi - else - if [ "${IP6_ADDR}" = "SLAAC" ]; then - sysrc -f "${_rc_conf}" ifconfig_${_jail_vnet}_ipv6="inet6 -ifdisabled accept_rtadv" + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}="" fi fi fi - # Replace epair description - sed -i '' "/${_new_host_epair}/ s|${_jail_vnet} host interface for Bastille jail ${TARGET}|${_jail_vnet} host interface for Bastille jail ${NEWNAME}|g" "${_jail_conf}" + # IP6 + if [ -n "${IP6_ADDR}" ]; then + if grep "vnet0" "${jail_rc_config}" | grep -q "${new_jail_epair}_name"; then + if [ "${IP6_ADDR}" = "SLAAC" ]; then + sysrc -f "${jail_rc_config}" ifconfig_vnet0_ipv6="inet6 -ifdisabled accept_rtadv" + else + sysrc -f "${jail_rc_config}" ifconfig_vnet0_ipv6="inet6 -ifdisabled ${IP6_ADDR}" + fi + else + if [ "${IP6_ADDR}" = "SLAAC" ]; then + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}_ipv6="inet6 -ifdisabled accept_rtadv" + fi + fi + fi # Update netgraph VNET (non-bridged) config elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then - local _ngif_num="$(echo "${_old_if_prefix}" | grep -Eo "[0-9]+")" - local _old_ngif="${_if}" + local ngif_num="$(echo "${old_if_prefix}" | grep -Eo "[0-9]+")" + local old_ngif="${if}" + # Generate new netgraph interface name + local new_ngif="ng${ngif_num}_${NEWNAME}" + # shellcheck disable=SC2034 + local new_if_prefix="$(echo ${if} | awk -F'_' '{print $1}')" + local new_if_suffix="$(echo ${if} | awk -F'_' '{print $2}')" - if [ "$(echo -n "ng${_ngif_num}_${NEWNAME}" | awk '{print length}')" -lt 16 ]; then - # Generate new netgraph interface name - local _new_ngif="ng${_ngif_num}_${NEWNAME}" - else - name_prefix="$(echo ${NEWNAME} | cut -c1-7)" - name_suffix="$(echo ${NEWNAME} | rev | cut -c1-2 | rev)" - local _new_ngif="ng${_ngif_num}_${name_prefix}xx${name_suffix}" - fi - - local _new_if_prefix="$(echo ${_if} | awk -F'_' '{print $1}')" - local _new_if_suffix="$(echo ${_if} | awk -F'_' '{print $2}')" - - # Replace netgraph interface name - sed -i '' "s|jng bridge ${_old_if_suffix}|jng bridge ${_new_if_suffix}|g" "${_jail_conf}" - sed -i '' "s|${_old_ngif} ether|${_new_ngif} ether|g" "${_jail_conf}" - sed -i '' "s|jng shutdown ${_old_if_suffix}|jng shutdown ${_new_if_suffix}|g" "${_jail_conf}" + # Replace netgraph interface name + sed -i '' "s|jng bridge ${old_if_suffix}\>|jng bridge ${new_if_suffix}|g" "${jail_config}" + sed -i '' "s|\<${old_ngif} ether|${new_ngif} ether|g" "${jail_config}" + sed -i '' "s|jng shutdown ${old_if_suffix}\>|jng shutdown ${new_if_suffix}|g" "${jail_config}" # Replace jail epair name in jail.conf - sed -i '' "s|= ${_old_ngif};|= ${_new_ngif};|g" "${_jail_conf}" + sed -i '' "s|= ${old_ngif};|= ${new_ngif};|g" "${jail_config}" # Replace epair name in /etc/rc.conf - sed -i '' "/ifconfig/ s|${_old_ngif}|${_new_ngif}|g" "${_rc_conf}" + sed -i '' "s|ifconfig_${old_ngif}_name|ifconfig_${new_ngif}_name|g" "${jail_rc_config}" - local _jail_vnet="$(grep ${_if} "${_rc_conf}" | grep -Eo -m 1 "vnet[0-9]+")" - local _jail_vnet_vlan="$(grep "vlans_${_jail_vnet}" "${_rc_conf}" | sed 's/.*=//g')" + local jail_vnet="$(grep ${if} "${jail_rc_config}" | grep -Eo -m 1 "vnet[0-9]+")" + local jail_vnet_vlan="$(grep "vlans_${jail_vnet}" "${jail_rc_config}" | sed 's/.*=//g')" # If jail had a static MAC, generate one for clone - if grep ether ${_jail_conf} | grep -qoc ${_new_ngif}; then - local external_interface="$(grep ${_new_if_suffix} ${_jail_conf} | grep -o 'jng bridge.*' | awk '{print $4}' | sed 's/["|;]//g')" + if grep ether ${jail_config} | grep -qoc ${new_ngif}; then + local external_interface="$(grep ${new_if_suffix} ${jail_config} | grep -o 'jng bridge.*' | awk '{print $4}' | sed 's/["|;]//g')" generate_static_mac "${NEWNAME}" "${external_interface}" - sed -i '' "s|${_new_ngif} ether.*:.*:.*:.*:.*:.*a\";|${_new_ngif} ether ${macaddr}a\";|" "${_jail_conf}" + sed -i '' "s|\<${new_ngif} ether.*:.*:.*:.*:.*:.*a\";|${new_ngif} ether ${macaddr}a\";|" "${jail_config}" fi - # Update /etc/rc.conf - sed -i '' "s|ifconfig_${_old_ngif}_name|ifconfig_${_new_ngif}_name|" "${_rc_conf}" # IP4 if [ -n "${IP4_ADDR}" ]; then - if grep "vnet0" "${_rc_conf}" | grep -q "${_new_ngif}_name"; then - if [ -n "${_jail_vnet_vlan}" ]; then + if grep "vnet0" "${jail_rc_config}" | grep -q "${new_ngif}_name"; then + if [ -n "${jail_vnet_vlan}" ]; then if [ "${IP4_ADDR}" = "0.0.0.0" ] || [ "${IP4_ADDR}" = "DHCP" ] || [ "${IP4_ADDR}" = "SYNCDHCP" ]; then - sysrc -f "${_rc_conf}" ifconfig_vnet0_${_jail_vnet_vlan}="SYNCDHCP" + sysrc -f "${jail_rc_config}" ifconfig_vnet0_${jail_vnet_vlan}="SYNCDHCP" else - sysrc -f "${_rc_conf}" ifconfig_vnet0_${_jail_vnet_vlan}="inet ${IP4_ADDR}" + sysrc -f "${jail_rc_config}" ifconfig_vnet0_${jail_vnet_vlan}="inet ${IP4_ADDR}" fi else if [ "${IP4_ADDR}" = "0.0.0.0" ] || [ "${IP4_ADDR}" = "DHCP" ] || [ "${IP4_ADDR}" = "SYNCDHCP" ]; then - sysrc -f "${_rc_conf}" ifconfig_vnet0="SYNCDHCP" + sysrc -f "${jail_rc_config}" ifconfig_vnet0="SYNCDHCP" else - sysrc -f "${_rc_conf}" ifconfig_vnet0="inet ${IP4_ADDR}" + sysrc -f "${jail_rc_config}" ifconfig_vnet0="inet ${IP4_ADDR}" fi fi else - if [ -n "${_jail_vnet_vlan}" ]; then - sysrc -f "${_rc_conf}" ifconfig_${_jail_vnet}_${_jail_vnet_vlan}="SYNCDHCP" + if [ -n "${jail_vnet_vlan}" ]; then + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}_${jail_vnet_vlan}="SYNCDHCP" else - sysrc -f "${_rc_conf}" ifconfig_${_jail_vnet}="SYNCDHCP" + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}="SYNCDHCP" fi fi fi # IP6 if [ -n "${IP6_ADDR}" ]; then - if grep "vnet0" "${_rc_conf}" | grep -q "${_new_ngif}_name"; then + if grep "vnet0" "${jail_rc_config}" | grep -q "${new_ngif}_name"; then if [ "${IP6_ADDR}" = "SLAAC" ]; then - sysrc -f "${_rc_conf}" ifconfig_vnet0_ipv6="inet6 -ifdisabled accept_rtadv" + sysrc -f "${jail_rc_config}" ifconfig_vnet0_ipv6="inet6 -ifdisabled accept_rtadv" else - sysrc -f "${_rc_conf}" ifconfig_vnet0_ipv6="inet6 -ifdisabled ${IP6_ADDR}" + sysrc -f "${jail_rc_config}" ifconfig_vnet0_ipv6="inet6 -ifdisabled ${IP6_ADDR}" fi else - sysrc -f "${_rc_conf}" ifconfig_${_jail_vnet}_ipv6="inet6 -ifdisabled accept_rtadv" + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}_ipv6="inet6 -ifdisabled accept_rtadv" fi fi fi @@ -451,6 +458,37 @@ clone_jail() { if ! [ -d "${bastille_jailsdir}/${NEWNAME}" ]; then + if [ -n "${IP}" ]; then + validate_ips + else + usage + fi + + # Validate proper IP settings + if [ "$(bastille config ${TARGET} get vnet)" != "not set" ]; then + # VNET + if grep -Eoq "ifconfig_vnet0=" "${bastille_jailsdir}/${TARGET}/root/etc/rc.conf"; then + if [ -z "${IP4_ADDR}" ]; then + error_exit "[ERROR]: IPv4 not set. Retry with a proper IPv4 address." + fi + fi + if grep -Eoq "ifconfig_vnet0_ipv6=" "${bastille_jailsdir}/${TARGET}/root/etc/rc.conf"; then + if [ -z "${IP6_ADDR}" ]; then + error_exit "[ERROR]: IPv6 not set. Retry with a proper IPv6 address." + fi + fi + else + if [ "$(bastille config ${TARGET} get ip4.addr)" != "not set" ]; then + if [ -z "${IP4_ADDR}" ]; then + error_exit "[ERROR]: IPv4 not set. Retry with a proper IPv4 address." + fi + elif [ "$(bastille config ${TARGET} get ip6.addr)" != "not set" ]; then + if [ -z "${IP6_ADDR}" ]; then + error_exit "[ERROR]: IPv6 not set. Retry with a proper IPv6 address." + fi + fi + fi + if checkyesno bastille_zfs_enable; then # Validate jail state @@ -468,37 +506,6 @@ clone_jail() { fi fi - if [ -n "${IP}" ]; then - validate_ips - else - usage - fi - - # Validate proper IP settings - if [ "$(bastille config ${TARGET} get vnet)" != "not set" ]; then - # VNET - if grep -Eoq "ifconfig_vnet0=" "${bastille_jailsdir}/${TARGET}/root/etc/rc.conf"; then - if [ -z "${IP4_ADDR}" ]; then - error_exit "[ERROR]: IPv4 not set. Retry with a proper IPv4 address." - fi - fi - if grep -Eoq "ifconfig_vnet0_ipv6=" "${bastille_jailsdir}/${TARGET}/root/etc/rc.conf"; then - if [ -z "${IP6_ADDR}" ]; then - error_exit "[ERROR]: IPv6 not set. Retry with a proper IPv6 address." - fi - fi - else - if [ "$(bastille config ${TARGET} get ip4.addr)" != "not set" ]; then - if [ -z "${IP4_ADDR}" ]; then - error_exit "[ERROR]: IPv4 not set. Retry with a proper IPv4 address." - fi - elif [ "$(bastille config ${TARGET} get ip6.addr)" != "not set" ]; then - if [ -z "${IP6_ADDR}" ]; then - error_exit "[ERROR]: IPv6 not set. Retry with a proper IPv6 address." - fi - fi - fi - if [ -n "${bastille_zfs_zpool}" ]; then # Replicate the existing container DATE=$(date +%F-%H%M%S) @@ -515,7 +522,7 @@ clone_jail() { fi else - + check_target_is_stopped "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then bastille stop "${TARGET}" else @@ -541,6 +548,9 @@ clone_jail() { error_exit "[ERROR]: An error has occurred while attempting to clone '${TARGET}'." else info "\nCloned '${TARGET}' to '${NEWNAME}' successfully." + if [ "${CLONE_INTERFACE_COUNT}" -gt 1 ]; then + info "\nEdit 'rc.conf' to manually set network info for non-default interfaces." + fi fi # Start jails if AUTO=1 or LIVE=1 @@ -554,6 +564,6 @@ clone_jail() { info "\nAttempting to clone '${TARGET}' to '${NEWNAME}'..." -clone_jail +clone_validate_jail_name -echo +clone_jail diff --git a/usr/local/share/bastille/cmd.sh b/usr/local/share/bastille/cmd.sh index 10f15fb7..806f8235 100644 --- a/usr/local/share/bastille/cmd.sh +++ b/usr/local/share/bastille/cmd.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille cmd [option(s)] TARGET COMMAND" cat << EOF - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. @@ -60,12 +60,12 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -84,10 +84,7 @@ bastille_root_check TARGET="${1}" shift 1 - -# Use mktemp to store exit codes -export TMP_BASTILLE_EXIT_CODE="$(mktemp)" -echo 0 > "${TMP_BASTILLE_EXIT_CODE}" +ERRORS=0 set_target "${TARGET}" @@ -110,9 +107,13 @@ for _jail in ${JAILS}; do else jexec -l -U root "${_jail}" "$@" fi - - bastille_check_exit_code "${_jail}" "$?" - + + if [ "$?" -ne 0 ]; then + ERRORS=$((ERRORS + 1)) + fi + done -bastille_return_exit_code +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi \ No newline at end of file diff --git a/usr/local/share/bastille/common.sh b/usr/local/share/bastille/common.sh index 01960720..f56968d4 100644 --- a/usr/local/share/bastille/common.sh +++ b/usr/local/share/bastille/common.sh @@ -34,7 +34,7 @@ # because all commands load this file # shellcheck disable=SC1090 . ${BASTILLE_CONFIG} - + COLOR_RED= COLOR_GREEN= COLOR_YELLOW= @@ -56,7 +56,7 @@ enable_debug() { # Enable debug mode. warn "***DEBUG MODE***" set -x -} +} # If "NO_COLOR" environment variable is present, or we aren't speaking to a # tty, disable output colors. @@ -64,21 +64,17 @@ if [ -z "${NO_COLOR}" ] && [ -t 1 ]; then enable_color fi -# Notify message on error -# Do not echo blank line +# Error messages/functions +error_notify() { + echo -e "${COLOR_RED}$*${COLOR_RESET}" 1>&2 +} + error_continue() { error_notify "$@" # shellcheck disable=SC2104 continue } -# Notify message on error, but do not exit -error_notify() { - echo -e "${COLOR_RED}$*${COLOR_RESET}" 1>&2 -} - -# Notify message on error and exit -# Echo blank line when exiting error_exit() { error_notify "$@" echo @@ -93,54 +89,6 @@ warn() { echo -e "${COLOR_YELLOW}$*${COLOR_RESET}" } -# This function checks and adds any error code -# that is not "0" to the tmp file -bastille_check_exit_code() { - - local jail="${1}" - local exit_code="${2}" - - # Set exit code variable - if [ -z "${TMP_BASTILLE_EXIT_CODE}" ]; then - error_exit "[ERROR]: Exit code status not set." - else - local old_exit_code="$(cat ${TMP_BASTILLE_EXIT_CODE})" - fi - - if [ "${exit_code}" -ne 0 ]; then - local new_exit_code="$(( ${old_exit_code} + ${exit_code} ))" - echo "${new_exit_code}" > "${TMP_BASTILLE_EXIT_CODE}" - error_notify "[ERROR CODE]: ${exit_code}" - fi -} - -# This needs to be the last function called -# if used on any command -bastille_return_exit_code() { - - local exit_code="$(cat ${TMP_BASTILLE_EXIT_CODE})" - - rm -f ${TMP_BASTILLE_EXIT_CODE} - return "${exit_code}" -} - -# Parallel mode, don't exceed process limit -bastille_running_jobs() { - - _process_limit="${1}" - _running_jobs=$((_running_jobs + 1)) - - if [ "${_running_jobs}" -ge "${_process_limit}" ]; then - - # Wait for at least one process to finish - wait 2>/dev/null || wait - - _running_jobs=$((_running_jobs - 1)) - - fi - -} - check_target_exists() { local _TARGET="${1}" local _jaillist="$(bastille list jails)" @@ -169,6 +117,16 @@ check_target_is_stopped() { fi } +get_bastille_epair_count() { + for _config in /usr/local/etc/bastille/*.conf; do + local bastille_jailsdir="$(sysrc -f "${_config}" -n bastille_jailsdir)" + BASTILLE_EPAIR_LIST="$(printf '%s\n%s' "$( (grep -Ehos "bastille[0-9]+" ${bastille_jailsdir}/*/jail.conf; ifconfig -g epair | grep -Eos "e[0-9]+a_bastille[0-9]+$" | grep -Eos 'bastille[0-9]+') | sort -u)" "${_epair_list}")" + done + BASTILLE_EPAIR_COUNT=$(printf '%s' "${BASTILLE_EPAIR_LIST}" | sort -u | wc -l | awk '{print $1}') + export BASTILLE_EPAIR_LIST + export BASTILLE_EPAIR_COUNT +} + get_jail_name() { local _JID="${1}" local _jailname="$(jls -j ${_JID} name 2>/dev/null)" @@ -249,11 +207,11 @@ set_target() { if jail_autocomplete "${_jail}" > /dev/null; then _jail="$(jail_autocomplete ${_jail})" elif [ $? -eq 2 ]; then - if grep -Ehoqw ${_jail} ${bastille_jailsdir}/*/tags; then + if grep -Ehoqw ${_jail} ${bastille_jailsdir}/*/tags 2>/dev/null; then _jail="$(grep -Eow ${_jail} ${bastille_jailsdir}/*/tags | awk -F"/tags" '{print $1}' | sed "s#${bastille_jailsdir}/##g" | tr '\n' ' ')" else error_continue "Jail not found \"${_jail}\"" - fi + fi else echo exit 1 @@ -335,7 +293,7 @@ set_bastille_mountpoints() { bastille_logsdir_mountpoint="${bastille_logsdir}" # Add _altroot to *dir* if set - if [ "${_altroot}" != "-" ]; then + if [ "${_altroot}" != "-" ]; then # Set *dir* to include ALTROOT bastille_prefix="${_altroot}${bastille_prefix}" bastille_backupsdir="${_altroot}${bastille_backupsdir}" @@ -343,7 +301,7 @@ set_bastille_mountpoints() { bastille_jailsdir="${_altroot}${bastille_jailsdir}" bastille_releasesdir="${_altroot}${bastille_releasesdir}" bastille_templatesdir="${_altroot}${bastille_templatesdir}" - bastille_logsdir="${_altroot}${bastille_logsdir}" + bastille_logsdir="${_altroot}${bastille_logsdir}" fi fi } @@ -397,50 +355,54 @@ generate_static_mac() { generate_vnet_jail_netblock() { local jail_name="${1}" - local use_unique_bridge="${2}" + # interface_type can be "standard" "bridge" or "passthrough" + local interface_type="${2}" local external_interface="${3}" local static_mac="${4}" + # Set epair/interface values for host/jail if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then - if [ -n "${use_unique_bridge}" ]; then + if [ "${interface_type}" = "bridge" ]; then if [ "$(echo -n "e0a_${jail_name}" | awk '{print length}')" -lt 16 ]; then local host_epair=e0a_${jail_name} local jail_epair=e0b_${jail_name} else - name_prefix="$(echo ${jail_name} | cut -c1-7)" - name_suffix="$(echo ${jail_name} | rev | cut -c1-2 | rev)" - local host_epair="e0a_${name_prefix}xx${name_suffix}" - local jail_epair="e0b_${name_prefix}xx${name_suffix}" + get_bastille_epair_count + local epair_num=1 + while echo "${BASTILLE_EPAIR_LIST}" | grep -oq "bastille${epair_num}"; do + epair_num=$((epair_num + 1)) + done + local host_epair="e0a_bastille${epair_num}" + local jail_epair="e0b_bastille${epair_num}" fi - else + elif [ "${interface_type}" = "standard" ]; then if [ "$(echo -n "e0a_${jail_name}" | awk '{print length}')" -lt 16 ]; then local host_epair=e0a_${jail_name} local jail_epair=e0b_${jail_name} - local jib_epair=${jail_name} + local jib_epair=${jail_name} else - name_prefix="$(echo ${jail_name} | cut -c1-7)" - name_suffix="$(echo ${jail_name} | rev | cut -c1-2 | rev)" - local host_epair="e0a_${name_prefix}xx${name_suffix}" - local jail_epair="e0b_${name_prefix}xx${name_suffix}" - local jib_epair="${name_prefix}xx${name_suffix}" - fi + get_bastille_epair_count + local epair_num=1 + while echo "${BASTILLE_EPAIR_LIST}" | grep -oq "bastille${epair_num}"; do + epair_num=$((epair_num + 1)) + done + local host_epair="e0a_bastille${epair_num}" + local jail_epair="e0b_bastille${epair_num}" + local jib_epair="bastille${epair_num}" + fi + elif [ "${interface_type}" = "passthrough" ]; then + host_epair="${external_interface}" + jail_epair="${external_interface}" fi elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then - if [ "$(echo -n "ng0_${jail_name}" | awk '{print length}')" -lt 16 ]; then - local ng_if=ng0_${jail_name} - local jng_if=${jail_name} - else - name_prefix="$(echo ${jail_name} | cut -c1-7)" - name_suffix="$(echo ${jail_name} | rev | cut -c1-2 | rev)" - local ng_if="ng0_${name_prefix}xx${name_suffix}" - local jng_if="${name_prefix}xx${name_suffix}" - fi + local ng_if=ng0_${jail_name} + local jng_if=${jail_name} fi - ## If BRIDGE is enabled, generate bridge config, else generate VNET config - if [ -n "${use_unique_bridge}" ]; then - if [ -n "${static_mac}" ]; then - ## Generate bridged VNET config with static MAC address + # VNET_JAIL_BRIDGE + if [ "${interface_type}" = "bridge" ]; then + if [ "${static_mac}" -eq 1 ]; then + # Generate BRIDGE config with static MAC address generate_static_mac "${jail_name}" "${external_interface}" cat <<-EOF vnet; @@ -453,7 +415,7 @@ generate_vnet_jail_netblock() { exec.poststop += "ifconfig ${host_epair} destroy"; EOF else - ## Generate bridged VNET config without static MAC address + # Generate BRIDGE config without static MAC address cat <<-EOF vnet; vnet.interface = ${jail_epair}; @@ -463,10 +425,12 @@ EOF exec.poststop += "ifconfig ${host_epair} destroy"; EOF fi - else + + # VNET_JAIL_STANDARD + elif [ "${interface_type}" = "standard" ]; then if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then - if [ -n "${static_mac}" ]; then - ## Generate VNET config with static MAC address + if [ "${static_mac}" -eq 1 ]; then + # Generate VNET config with static MAC address generate_static_mac "${jail_name}" "${external_interface}" cat <<-EOF vnet; @@ -478,7 +442,7 @@ EOF exec.poststop += "ifconfig ${host_epair} destroy"; EOF else - ## Generate VNET config without static MAC address + # Generate VNET config without static MAC address cat <<-EOF vnet; vnet.interface = ${jail_epair}; @@ -488,8 +452,8 @@ EOF EOF fi elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then - if [ -n "${static_mac}" ]; then - ## Generate VNET config with static MAC address + if [ "${static_mac}" -eq 1 ]; then + # Generate VNET config with static MAC address generate_static_mac "${jail_name}" "${external_interface}" cat <<-EOF vnet; @@ -499,7 +463,7 @@ EOF exec.poststop += "jng shutdown ${jng_if}"; EOF else - ## Generate VNET config without static MAC address + # Generate VNET config without static MAC address cat <<-EOF vnet; vnet.interface = ${ng_if}; @@ -508,6 +472,14 @@ EOF EOF fi fi + + # VNET_JAIL_PASSTHROUGH + elif [ "${interface_type}" = "passthrough" ]; then + cat <<-EOF + vnet; + vnet.interface = ${external_interface}; + exec.prestop += "ifconfig ${external_interface} -vnet ${jail_name}"; +EOF fi } @@ -560,14 +532,22 @@ update_jail_syntax_v1() { # Only apply if old syntax is found if grep -Eoq "exec.prestart.*ifconfig epair[0-9]+ create.*" "${jail_config}"; then + warn "\n[WARNING]\n" + warn "Updating jail.conf file..." + warn "Please review your jail.conf file after completion." + warn "VNET jails created without -M will be assigned a new MAC address." + if [ "$(echo -n "e0a_${jail}" | awk '{print length}')" -lt 16 ]; then local new_host_epair=e0a_${jail} local new_jail_epair=e0b_${jail} else - name_prefix="$(echo ${jail} | cut -c1-7)" - name_suffix="$(echo ${jail} | rev | cut -c1-2 | rev)" - local new_host_epair="e0a_${name_prefix}xx${name_suffix}" - local new_jail_epair="e0b_${name_prefix}xx${name_suffix}" + get_bastille_epair_count + local epair_num=1 + while echo "${BASTILLE_EPAIR_LIST}" | grep -oq "bastille${epair_num}"; do + epair_num=$((epair_num + 1)) + done + local new_host_epair="e0a_bastille${epair_num}" + local new_jail_epair="e0b_bastille${epair_num}" fi # Delete unneeded lines @@ -588,6 +568,11 @@ update_jail_syntax_v1() { elif grep -Eoq "exec.poststop.*jib destroy.*" "${jail_config}"; then + warn "\n[WARNING]\n" + warn "Updating jail.conf file..." + warn "Please review your jail.conf file after completion." + warn "VNET jails created without -M will be assigned a new MAC address." + local external_interface="$(grep -Eo "jib addm.*" "${jail_config}" | awk '{print $4}')" if [ "$(echo -n "e0a_${jail}" | awk '{print length}')" -lt 16 ]; then @@ -595,11 +580,14 @@ update_jail_syntax_v1() { local new_jail_epair=e0b_${jail} local jib_epair="${jail}" else - name_prefix="$(echo ${jail} | cut -c1-7)" - name_suffix="$(echo ${jail} | rev | cut -c1-2 | rev)" - local new_host_epair="e0a_${name_prefix}xx${name_suffix}" - local new_jail_epair="e0b_${name_prefix}xx${name_suffix}" - local jib_epair="${name_prefix}xx${name_suffix}" + get_bastille_epair_count + local epair_num=1 + while echo "${BASTILLE_EPAIR_LIST}" | grep -oq "bastille${epair_num}"; do + epair_num=$((epair_num + 1)) + done + local new_host_epair="e0a_bastille${epair_num}" + local new_jail_epair="e0b_bastille${epair_num}" + local jib_epair="bastille${epair_num}" fi # Change jail.conf diff --git a/usr/local/share/bastille/config.sh b/usr/local/share/bastille/config.sh index ccffb3c5..a4d9f879 100644 --- a/usr/local/share/bastille/config.sh +++ b/usr/local/share/bastille/config.sh @@ -36,7 +36,7 @@ usage() { error_notify "Usage: bastille config [option(s)] TARGET [get|(set|add)|remove] PROPERTY [VALUE]" cat << EOF - + Options: -x | --debug Enable debug mode. @@ -52,7 +52,7 @@ print_jail_conf() { # line jail -f "$1" -e ' ' -} +} # Handle options. while [ "$#" -gt 0 ]; do @@ -88,13 +88,12 @@ shift 2 set_target "${TARGET}" case "${ACTION}" in - get) + get|remove) if [ "$#" -ne 1 ]; then - error_notify 'Too many parameters for [get|remove] operation.' - usage + error_exit "[ERROR]: Too many parameters for [get|remove] operation." fi ;; - add|set|remove) + add|set) ;; *) error_exit "[ERROR]: Only (add|set), get and remove are supported." @@ -122,12 +121,10 @@ print_jail_conf() { # line jail -f "${1}" -e ' ' -} +} for _jail in ${JAILS}; do - ( - # Backwards compatibility for specifying only an IP with ip[4|6].addr if [ "${ACTION}" = "set" ] && [ "${PROPERTY}" = "ip4.addr" ]; then if ! echo "${VALUE}" | grep -q "|"; then @@ -138,7 +135,7 @@ for _jail in ${JAILS}; do VALUE="$(bastille config ${_jail} get ip6.addr | awk -F"|" '{print $1}')|${VALUE}" fi fi - + # Handle Bastille specific properties # Currently only 'depend' 'priority' and 'boot' if [ "${PROPERTY}" = "priority" ] || [ "${PROPERTY}" = "prio" ]; then @@ -311,12 +308,7 @@ for _jail in ${JAILS}; do fi fi - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait # Only display this message once at the end (not for every jail). -- cwells if { [ "${ACTION}" = "set" ] || [ "${ACTION}" = "remove" ]; } && [ "${BASTILLE_PROPERTY}" -eq 0 ]; then diff --git a/usr/local/share/bastille/console.sh b/usr/local/share/bastille/console.sh index 7d4111d3..43bbbf8a 100644 --- a/usr/local/share/bastille/console.sh +++ b/usr/local/share/bastille/console.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille console [option(s)] TARGET [USER]" cat << EOF - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. @@ -65,7 +65,7 @@ while [ "$#" -gt 0 ]; do case ${_opt} in x) enable_debug ;; a) AUTO=1 ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -90,7 +90,7 @@ validate_user() { local _jail="${1}" local _user="${2}" - + if jexec -l "${_jail}" id "${_user}" >/dev/null 2>&1; then USER_SHELL="$(jexec -l "${_jail}" getent passwd "${_user}" | cut -d: -f7)" if [ -n "${USER_SHELL}" ]; then @@ -110,7 +110,7 @@ validate_user() { check_fib() { local _jail="${1}" - + fib=$(grep 'exec.fib' "${bastille_jailsdir}/${_jail}/jail.conf" | awk '{print $3}' | sed 's/\;//g') if [ -n "${fib}" ]; then @@ -132,7 +132,7 @@ for _jail in ${JAILS}; do fi info "\n[${_jail}]:" - + LOGIN="$(jexec -l "${_jail}" which login)" if [ -n "${USER}" ]; then @@ -140,7 +140,7 @@ for _jail in ${JAILS}; do else check_fib "${_jail}" LOGIN="$(jexec -l "${_jail}" which login)" - ${_setfib} jexec -l "${_jail}" $LOGIN -f root + ${_setfib} jexec -l "${_jail}" ${LOGIN} -f root fi - + done diff --git a/usr/local/share/bastille/convert.sh b/usr/local/share/bastille/convert.sh index 8c54f901..d96fd88a 100644 --- a/usr/local/share/bastille/convert.sh +++ b/usr/local/share/bastille/convert.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille convert [option(s)] TARGET [RELEASE]" cat << EOF - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. @@ -66,13 +66,13 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; y) AUTO_YES=1 ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -106,7 +106,7 @@ validate_release_name() { local _name=${1} local _sanity="$(echo "${_name}" | tr -c -d 'a-zA-Z0-9-_')" - + if [ -n "$(echo "${_sanity}" | awk "/^[-_].*$/" )" ]; then error_exit "[ERROR]: Release names may not begin with (-|_) characters!" elif [ "${_name}" != "${_sanity}" ]; then @@ -119,7 +119,7 @@ convert_jail_to_release() { _jailname="${1}" _release="${2}" - + info "\nAttempting to create '${_release}' from '${_jailname}'..." if checkyesno bastille_zfs_enable; then @@ -272,11 +272,11 @@ if [ "$#" -eq 1 ]; then elif ! grep -qw ".bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then error_exit "[ERROR]: ${TARGET} is not a thin container." fi - + # Ask if user is sure they want to convert the jail # but only if AUTO_YES=0 if [ "${AUTO_YES}" -ne 1 ]; then - warn "/n[WARNING]: Jail conversion from thin to thick can't be undone!\n" + warn "\n[WARNING]: Jail conversion from thin to thick can't be undone!\n" # shellcheck disable=SC3045 read -p "Are you sure you want to continue? [y|n]:" _answer case "${_answer}" in diff --git a/usr/local/share/bastille/cp.sh b/usr/local/share/bastille/cp.sh index 10d4760e..5aa724dd 100644 --- a/usr/local/share/bastille/cp.sh +++ b/usr/local/share/bastille/cp.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille cp [option(s)] TARGET HOST_PATH JAIL_PATH" cat << EOF - + Options: -q | --quiet Suppress output. @@ -65,7 +65,7 @@ while [ "$#" -gt 0 ]; do case ${_opt} in q) OPTION="-a" ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -83,26 +83,30 @@ fi TARGET="${1}" HOST_PATH="${2}" JAIL_PATH="${3}" +ERRORS=0 bastille_root_check set_target "${TARGET}" for _jail in ${JAILS}; do - ( - info "\n[${_jail}]:" - + host_path="${HOST_PATH}" jail_path="$(echo ${bastille_jailsdir}/${_jail}/root/${JAIL_PATH} | sed 's#//#/#g')" - + + # Workaround to properly copy host resolv.conf to jail if the host file is a symlink. + if [ "${host_path}" = "${bastille_resolv_conf}" ] && [ -L "${host_path}" ]; then + OPTION="${OPTION}L" + fi + if ! cp "${OPTION}" "${host_path}" "${jail_path}"; then + ERRORS=$((ERRORS + 1)) error_continue "[ERROR]: CP failed: ${host_path} -> ${jail_path}" fi - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait + +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi diff --git a/usr/local/share/bastille/create.sh b/usr/local/share/bastille/create.sh index c97a639e..109ed91e 100644 --- a/usr/local/share/bastille/create.sh +++ b/usr/local/share/bastille/create.sh @@ -34,28 +34,29 @@ usage() { # Build an independent usage for the create command - # If no option specified, will create a thin container by default + # If no option specified, will create a thin jail by default error_notify "Usage: bastille create [option(s)] NAME RELEASE IP [INTERFACE]" cat << EOF Options: - - -B | --bridge Enable VNET, and attach to a specified, already existing external bridge. - -C | --clone Create a clone jail. - -D | --dual Create jail with both IPv4 and IPv6 networking ('inherit' and 'ip_hostname' only). - -E | --empty Create an empty container, intended for custom jail builds (thin/thick/linux or unsupported). - -g | --gateway IP Specify a default router/gateway for the jail. - -L | --linux Create a Linux jail (experimental). - -M | --static-mac Generate a static MAC address for jail (VNET only). - -n | --nameserver IP,IP Specify nameserver(s) for the jail. Comma separated. - --no-validate Do not validate the release when creating the jail. - --no-boot Create jail with boot=off. - -p | --priority VALUE Set priority value for jail. - -T | --thick Creates a thick container, they consume more space as they are self contained and independent. - -V | --vnet Enable VNET, and attach to an existing, physical interface. - -v | --vlan VLANID Creates the jail with specified VLAN ID (VNET only). - -x | --debug Enable debug mode. - -Z | --zfs-opts zfs,options Comma separated list of ZFS options to create the jail with. This overrides the defaults. + + -B | --bridge Enable VNET, and attach to a specified, already existing bridge. + -C | --clone Create a clone jail. + -D | --dual Create jail with both IPv4 and IPv6 networking ('inherit' and 'ip_hostname' only). + -E | --empty Create an empty jail, intended for custom jail builds (thin/thick/linux or unsupported). + -g | --gateway IP Specify a default router/gateway for the jail. + -L | --linux Create a Linux jail (experimental). + -M | --static-mac Generate a static MAC address for jail (VNET only). + -n | --nameserver IP,IP Specify nameserver(s) for the jail. Comma separated. + --no-validate Do not validate the release when creating the jail. + --no-boot Create jail with boot=off. + -P | --passthrough Enable VNET, and pass the specified interface into the jail. + -p | --priority VALUE Set priority value for the jail. + -T | --thick Create a thick jail. This is an entirely self contained and independant jail. + -V | --vnet Enable VNET, and attach to an existing, physical interface. + -v | --vlan VLANID Creates the jail with specified VLAN ID (VNET only). + -x | --debug Enable debug mode. + -Z | --zfs-opts zfs,options Comma separated list of ZFS options to create the jail with. This overrides the defaults. EOF exit 1 @@ -65,11 +66,15 @@ validate_name() { local NAME_VERIFY=${NAME} local NAME_SANITY="$(echo "${NAME_VERIFY}" | tr -c -d 'a-zA-Z0-9-_')" - + + if check_target_exists "${NAME}"; then + error_exit "[ERROR]: Jail already exists: ${NAME}" + fi + # Make sure NAME has only allowed characters if [ -n "$(echo "${NAME_SANITY}" | awk "/^[-_].*$/" )" ]; then error_exit "[ERROR]: Jail names may not begin with (-|_) characters!" - elif [ -n "${VNET_JAIL}" ] && echo "${NAME_VERIFY}" | grep -qE '(-|_)'; then + elif [ "${VNET_JAIL}" -eq 1 ] && echo "${NAME_VERIFY}" | grep -qE '(-|_)'; then error_exit "[ERROR]: VNET jail names may not contain (-|_) characters." elif [ "${NAME_VERIFY}" != "${NAME_SANITY}" ]; then error_exit "[ERROR]: Jail names may not contain special characters!" @@ -78,32 +83,60 @@ validate_name() { fi } +validate_release() { + + # Validate sane release name + if [ -n "${NAME_VERIFY}" ]; then + RELEASE="${NAME_VERIFY}" + else + usage + fi + + # Validate Linux releases + if [ "${PLATFORM_OS}" = "Ubuntu" ] || [ "${PLATFORM_OS}" = "Debian" ]; then + if [ "${LINUX_JAIL}" -eq 0 ]; then + error_exit "[ERROR]: Linux releases can only be used with [-l|--linux]" + fi + elif [ "${PLATFORM_OS}" = "FreeBSD" ] || [ "${PLATFORM_OS}" = "HardenedBSD" ] || [ "${PLATFORM_OS}" = "MidnightBSD" ]; then + # Validate release existence + if [ ! -d "${bastille_releasesdir}/${RELEASE}" ]; then + error_notify "[ERROR]: Release must be bootstrapped first." + error_exit "See 'bastille bootstrap'." + fi + else + error_exit "[ERROR]: Unable to validate Platform OS." + fi + + # Set OS_RELEASE + OS_RELEASE="$( ${bastille_releasesdir}/${RELEASE}/bin/freebsd-version )" +} + validate_ip() { - local _ip="${1}" - local _ip6="$(echo ${_ip} | grep -E '^(([a-fA-F0-9:]+$)|([a-fA-F0-9:]+\/[0-9]{1,3}$)|SLAAC)')" + local ip="${1}" + local ip6="$(echo ${ip} | grep -E '^(([a-fA-F0-9:]+$)|([a-fA-F0-9:]+\/[0-9]{1,3}$)|SLAAC)')" - if [ -n "${_ip6}" ]; then - info "\nValid: (${_ip6})." - # This is only used in this function to set IPX_DEFINITION + if [ -n "${ip6}" ]; then + info "\nValid: (${ip6})." + # This is only used in this function to set IPX_DEFINITION local ipx_addr="ip6.addr" else - if [ "${_ip}" = "inherit" ] || [ "${_ip}" = "ip_hostname" ]; then - if [ -n "${VNET_JAIL}" ]; then - error_exit "[ERROR]: Unsupported IP option for VNET jail: (${_ip})." + if [ "${ip}" = "inherit" ] || [ "${ip}" = "ip_hostname" ]; then + if [ "${VNET_JAIL}" -eq 1 ]; then + error_exit "[ERROR]: Unsupported IP option for VNET jail: (${ip})." else - info "\nValid: (${_ip})." + info "\nValid: (${ip})." fi - elif [ "${_ip}" = "DHCP" ] || [ "${_ip}" = "SYNCDHCP" ] || [ "${_ip}" = "0.0.0.0" ]; then - if [ -z "${VNET_JAIL}" ]; then - error_exit "[ERROR]: Unsupported IP option for non-VNET jail: (${_ip})." + elif [ "${ip}" = "DHCP" ] || [ "${ip}" = "SYNCDHCP" ] || [ "${ip}" = "0.0.0.0" ]; then + if [ "${VNET_JAIL}" -eq 0 ]; then + error_exit "[ERROR]: Unsupported IP option for non-VNET jail: (${ip})." else - info "\nValid: (${_ip})." + info "\nValid: (${ip})." fi else local IFS - if echo "${_ip}" | grep -Eq '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))?$'; then - TEST_IP=$(echo "${_ip}" | cut -d / -f1) + if echo "${ip}" | grep -Eq '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))?$'; then + TEST_IP=$(echo "${ip}" | cut -d / -f1) IFS=. set ${TEST_IP} for quad in 1 2 3 4; do @@ -112,9 +145,9 @@ validate_ip() { fi done ipx_addr="ip4.addr" - info "\nValid: (${_ip})." + info "\nValid: (${ip})." else - error_continue "Invalid: (${_ip})." + error_continue "Invalid: (${ip})." fi fi fi @@ -138,45 +171,45 @@ validate_ip() { fi # Determine IP/Interface mode - if [ "${_ip}" = "inherit" ]; then - if [ -n "${DUAL_STACK}" ]; then - IP4_DEFINITION="ip4 = ${_ip};" - IP6_DEFINITION="ip6 = ${_ip};" + if [ "${ip}" = "inherit" ]; then + if [ "${DUAL_STACK}" -eq 1 ]; then + IP4_DEFINITION="ip4 = ${ip};" + IP6_DEFINITION="ip6 = ${ip};" IP6_MODE="new" else - IP4_DEFINITION="ip4 = ${_ip};" + IP4_DEFINITION="ip4 = ${ip};" IP6_DEFINITION="" IP6_MODE="disable" fi - elif [ "${_ip}" = "ip_hostname" ]; then - if [ -n "${DUAL_STACK}" ]; then - IP_HOSTNAME="${_ip}" + elif [ "${ip}" = "ip_hostname" ]; then + if [ "${DUAL_STACK}" -eq 1 ]; then + IP_HOSTNAME="${ip}" IP4_DEFINITION="${IP_HOSTNAME};" IP6_DEFINITION="${IP_HOSTNAME};" IP6_MODE="new" else - IP_HOSTNAME="${_ip}" + IP_HOSTNAME="${ip}" IP4_DEFINITION="${IP_HOSTNAME};" IP6_DEFINITION="" IP6_MODE="disable" fi - elif [ "${_ip}" = "DHCP" ] || [ "${_ip}" = "SLAAC" ] || [ "${_ip}" = "0.0.0.0" ]; then - if [ -n "${VNET_JAIL}" ]; then + elif [ "${ip}" = "DHCP" ] || [ "${ip}" = "SLAAC" ] || [ "${ip}" = "0.0.0.0" ]; then + if [ "${VNET_JAIL}" -eq 1 ]; then if [ "${ipx_addr}" = "ip4.addr" ]; then - IP4_ADDR="${_ip}" + IP4_ADDR="${ip}" elif [ "${ipx_addr}" = "ip6.addr" ]; then - IP6_ADDR="${_ip}" + IP6_ADDR="${ip}" fi else - error_exit "[ERROR]: Unsupported IP option for standard jail: (${_ip})." + error_exit "[ERROR]: Unsupported IP option for standard jail: (${ip})." fi else if [ "${ipx_addr}" = "ip4.addr" ]; then - IP4_ADDR="${_ip}" - IP4_DEFINITION="${ipx_addr} = ${bastille_jail_conf_interface}|${_ip};" + IP4_ADDR="${ip}" + IP4_DEFINITION="${ipx_addr} = ${bastille_jail_conf_interface}|${ip};" elif [ "${ipx_addr}" = "ip6.addr" ]; then - IP6_ADDR="${_ip}" - IP6_DEFINITION="${ipx_addr} = ${bastille_jail_conf_interface}|${_ip};" + IP6_ADDR="${ip}" + IP6_DEFINITION="${ipx_addr} = ${bastille_jail_conf_interface}|${ip};" IP6_MODE="new" fi fi @@ -202,7 +235,7 @@ validate_netif() { if ! echo "${LIST_INTERFACES} VNET" | grep -qwo "${INTERFACE}"; then error_exit "[ERROR]: Invalid: (${INTERFACE})." - elif [ -n "${VNET_JAIL}" ] && [ -z "${VNET_JAIL_BRIDGE}" ]; then + elif [ "${VNET_JAIL_STANDARD}" -eq 1 ]; then for _bridge in $(ifconfig -g bridge | grep -vw "${INTERFACE}bridge"); do if ifconfig ${_bridge} | grep "member" | grep -owq "${INTERFACE}"; then error_exit "[ERROR]: Interface (${INTERFACE}) is already a member of bridge: ${_bridge}" @@ -211,31 +244,15 @@ validate_netif() { else info "\nValid: (${INTERFACE})." fi - # Don't allow dots in INTERFACE if -V - if [ -n "${VNET_JAIL}" ] && [ -z "${VNET_JAIL_BRIDGE}" ]; then + + # Don't allow dots in INTERFACE for -V|--vnet jails + if [ "${VNET_JAIL_STANDARD}" -eq 1 ]; then if echo "${INTERFACE}" | grep -q "\."; then error_exit "[ERROR]: [-V|--vnet] does not support dots (.) in interface names." fi fi } -validate_release() { - - ## ensure the user set the Linux(experimental) option explicitly - if [ -n "${UBUNTU}" ]; then - if [ -z "${LINUX_JAIL}" ]; then - usage - fi - fi - - ## check release name match, else show usage - if [ -n "${NAME_VERIFY}" ]; then - RELEASE="${NAME_VERIFY}" - else - usage - fi -} - generate_minimal_conf() { cat << EOF > "${bastille_jail_conf}" @@ -268,7 +285,7 @@ ${NAME} { mount.fstab = ${bastille_jail_fstab}; path = ${bastille_jail_path}; securelevel = 2; - osrelease = ${RELEASE}; + osrelease = ${OS_RELEASE}; ${IP4_DEFINITION} ${IP6_DEFINITION} @@ -309,7 +326,7 @@ generate_vnet_jail_conf() { devfs_ruleset_value=13 fi - NETBLOCK=$(generate_vnet_jail_netblock "${NAME}" "${VNET_JAIL_BRIDGE}" "${bastille_jail_conf_interface}" "${STATIC_MAC}") + NETBLOCK=$(generate_vnet_jail_netblock "${NAME}" "${VNET_INTERFACE_TYPE}" "${bastille_jail_conf_interface}" "${STATIC_MAC}") cat << EOF > "${bastille_jail_conf}" ${NAME} { @@ -324,7 +341,7 @@ ${NAME} { mount.fstab = ${bastille_jail_fstab}; path = ${bastille_jail_path}; securelevel = 2; - osrelease = ${RELEASE}; + osrelease = ${OS_RELEASE}; ${NETBLOCK} } @@ -334,10 +351,9 @@ EOF post_create_jail() { # Common config checks and settings. - # Using relative paths here. # MAKE SURE WE'RE IN THE RIGHT PLACE. - cd "${bastille_jail_path}" || error_exit "Could not cd to ${bastille_jail_path}" + cd "${bastille_jail_path}" || error_exit "Could not access directory: ${bastille_jail_path}" if [ ! -f "${bastille_jail_conf}" ]; then if [ -z "${bastille_network_loopback}" ] && [ -n "${bastille_network_shared}" ]; then @@ -352,7 +368,7 @@ post_create_jail() { fi if [ ! -f "${bastille_jail_fstab}" ]; then - if [ -z "${THICK_JAIL}" ] && [ -z "${CLONE_JAIL}" ]; then + if [ "${THICK_JAIL}" -eq 0 ] && [ "${CLONE_JAIL}" -eq 0 ]; then echo -e "${bastille_releasesdir}/${RELEASE} ${bastille_jail_base} nullfs ro 0 0" > "${bastille_jail_fstab}" else touch "${bastille_jail_fstab}" @@ -360,7 +376,7 @@ post_create_jail() { fi # Generate the jail configuration file. - if [ -n "${VNET_JAIL}" ]; then + if [ "${VNET_JAIL}" -eq 1 ]; then generate_vnet_jail_conf else generate_jail_conf @@ -385,15 +401,21 @@ create_jail() { if checkyesno bastille_zfs_enable; then if [ -n "${bastille_zfs_zpool}" ]; then ## create required zfs datasets, mountpoint inherited from system - if [ -z "${CLONE_JAIL}" ]; then - zfs create ${bastille_zfs_options} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NAME}" + if [ "${CLONE_JAIL}" -eq 0 ]; then + if ! zfs create ${bastille_zfs_options} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NAME}"; then + error_exit "[ERROR]: Failed to create jail dataset: ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NAME}" + fi fi - if [ -z "${THICK_JAIL}" ] && [ -z "${CLONE_JAIL}" ]; then - zfs create ${bastille_zfs_options} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NAME}/root" + if [ "${THICK_JAIL}" -eq 0 ] && [ "${CLONE_JAIL}" -eq 0 ]; then + if ! zfs create ${bastille_zfs_options} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NAME}/root"; then + error_exit "[ERROR]: Failed to create jail root dataset: ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${NAME}/root" + fi fi fi else - mkdir -p "${bastille_jailsdir}/${NAME}/root" + if ! mkdir -p "${bastille_jailsdir}/${NAME}/root"; then + error_exit "[ERROR]: Failed to create jail directory: ${bastille_jailsdir}/${NAME}/root" + fi fi # Check if the jail directory has been mounted under UFS (not supported) elif [ ! -d "${bastille_jailsdir}/${NAME}/root" ] && ! checkyesno bastille_zfs_enable; then @@ -404,7 +426,7 @@ create_jail() { ## PoC for Linux jails @hackacad - if [ -n "${LINUX_JAIL}" ]; then + if [ "${LINUX_JAIL}" -eq 1 ]; then info "\nCreating a linuxjail. This may take a while...\n" if [ ! -d "${bastille_jail_base}" ]; then mkdir -p "${bastille_jail_base}" @@ -448,8 +470,8 @@ create_jail() { fi fi - if [ -z "${EMPTY_JAIL}" ] && [ -z "${LINUX_JAIL}" ]; then - if [ -z "${THICK_JAIL}" ] && [ -z "${CLONE_JAIL}" ]; then + if [ "${EMPTY_JAIL}" -eq 0 ] && [ "${LINUX_JAIL}" -eq 0 ]; then + if [ "${THICK_JAIL}" -eq 0 ] && [ "${CLONE_JAIL}" -eq 0 ]; then if [ ! -d "${bastille_jail_base}" ]; then mkdir -p "${bastille_jail_base}" fi @@ -465,7 +487,7 @@ create_jail() { # Check and apply required settings. post_create_jail - if [ -z "${THICK_JAIL}" ] && [ -z "${CLONE_JAIL}" ]; then + if [ "${THICK_JAIL}" -eq 0 ] && [ "${CLONE_JAIL}" -eq 0 ]; then LINK_LIST="bin boot lib libexec rescue sbin usr/bin usr/include usr/lib usr/lib32 usr/libdata usr/libexec usr/sbin usr/share usr/src" info "\nCreating a thinjail..." for _link in ${LINK_LIST}; do @@ -481,7 +503,7 @@ create_jail() { fi fi - if [ -z "${THICK_JAIL}" ] && [ -z "${CLONE_JAIL}" ]; then + if [ "${THICK_JAIL}" -eq 0 ] && [ "${CLONE_JAIL}" -eq 0 ]; then ## rw ## copy only required files for thin jails FILE_LIST=".cshrc .profile COPYRIGHT dev etc media mnt net proc root tmp var usr/obj usr/tests" @@ -497,7 +519,7 @@ create_jail() { else if checkyesno bastille_zfs_enable; then if [ -n "${bastille_zfs_zpool}" ]; then - if [ -n "${CLONE_JAIL}" ]; then + if [ "${CLONE_JAIL}" -eq 1 ]; then info "\nCreating a clonejail...\n" ## clone the release base to the new basejail SNAP_NAME="bastille-clone-$(date +%Y-%m-%d-%H%M%S)" @@ -509,7 +531,7 @@ create_jail() { # Check and apply required settings. post_create_jail - elif [ -n "${THICK_JAIL}" ]; then + elif [ "${THICK_JAIL}" -eq 1 ]; then info "\nCreating a thickjail. This may take a while..." @@ -559,7 +581,7 @@ create_jail() { fi fi - if [ -z "${LINUX_JAIL}" ]; then + if [ "${LINUX_JAIL}" -eq 0 ]; then ## create home directory if missing if [ ! -d "${bastille_jail_path}/usr/home" ]; then mkdir -p "${bastille_jail_path}/usr/home" @@ -587,9 +609,9 @@ create_jail() { sed -i '' 's|[0-9],[0-9]\{2\}.*[0-9]-[0-9].*root.*kerntz -a|#& # Disabled by bastille|' "etc/crontab" fi - ## VNET specific - if [ -n "${VNET_JAIL}" ]; then - ## VNET requires jib or jng script + # VNET specific + if [ "${VNET_JAIL}" -eq 1 ]; then + # VNET requires jib or jng script if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then if [ ! "$(command -v jib)" ]; then if [ -f /usr/share/examples/jails/jib ] && [ ! -f /usr/local/bin/jib ]; then @@ -601,13 +623,13 @@ create_jail() { if [ -f /usr/share/examples/jails/jng ] && [ ! -f /usr/local/bin/jng ]; then install -m 0544 /usr/share/examples/jails/jng /usr/local/bin/jng fi - fi + fi fi fi - elif [ -n "${LINUX_JAIL}" ]; then + elif [ "${LINUX_JAIL}" -eq 1 ]; then ## Generate configuration for Linux jail generate_linux_jail_conf - elif [ -n "${EMPTY_JAIL}" ]; then + elif [ "${EMPTY_JAIL}" -eq 1 ]; then ## Generate minimal configuration for empty jail generate_minimal_conf fi @@ -615,15 +637,15 @@ create_jail() { # Set strict permissions on the jail by default chmod 0700 "${bastille_jailsdir}/${NAME}" - # Apply boot, depends and priority settings before starting jail + # Apply boot, depend and priority settings before starting jail sysrc -f "${bastille_jailsdir}/${NAME}/settings.conf" boot=${BOOT} >/dev/null sysrc -f "${bastille_jailsdir}/${NAME}/settings.conf" depend="" >/dev/null sysrc -f "${bastille_jailsdir}/${NAME}/settings.conf" priority="${PRIORITY}" >/dev/null # Jail must be started before applying the default template. -- cwells - if [ -z "${EMPTY_JAIL}" ]; then + if [ "${EMPTY_JAIL}" -eq 0 ]; then bastille start "${NAME}" - elif [ -n "${EMPTY_JAIL}" ]; then + elif [ "${EMPTY_JAIL}" -eq 1 ]; then # Don't start empty jails unless a template defined. if [ -n "${bastille_template_empty}" ]; then bastille start "${NAME}" @@ -631,89 +653,110 @@ create_jail() { fi # Exit if jail was not started, except for empty jails - if [ -z "${EMPTY_JAIL}" ]; then + if [ "${EMPTY_JAIL}" -eq 0 ]; then if ! check_target_is_running "${NAME}"; then bastille destroy -afy "${NAME}" error_exit "[ERROR]: Failed to create jail: ${NAME}" fi fi - if [ -n "${VNET_JAIL}" ]; then - if [ -n "${bastille_template_vnet}" ]; then - - ## rename interface to generic vnet0 - uniq_epair=$(grep vnet.interface "${bastille_jailsdir}/${NAME}/jail.conf" | awk '{print $3}' | sed 's/;//; s/-/_/g') - _gateway='' - _gateway6='' - _ifconfig_inet='' - _ifconfig_inet6='' + if [ "${VNET_JAIL}" -eq 1 ]; then - # Determine default gateway option + if [ -n "${bastille_template_vnet}" ]; then + + # Retrieve epair name from jail.conf + uniq_epair=$(grep vnet.interface "${bastille_jailsdir}/${NAME}/jail.conf" | awk '{print $3}' | sed 's/;//; s/-/_/g') + gateway='' + gateway6='' + ifconfig_inet='' + ifconfig_inet6='' + + # Check for DHCP if echo "${IP}" | grep -qE '(0[.]0[.]0[.]0|DHCP|SYNCDHCP)'; then - # Enable DHCP if requested - _ifconfig_inet=SYNCDHCP + ifconfig_inet="SYNCDHCP" else - # Else apply the default gateway + # Set Gateway if [ -n "${OPT_GATEWAY}" ]; then - _gateway="${OPT_GATEWAY}" + gateway="${OPT_GATEWAY}" elif [ -n "${bastille_network_gateway}" ]; then - _gateway="${bastille_network_gateway}" + gateway="${bastille_network_gateway}" else - _gateway="$(netstat -4rn | awk '/default/ {print $2}')" + gateway="$(netstat -4rn | awk '/default/ {print $2}')" fi fi - + # Add IPv4 address (this is empty if DHCP is used) if [ -n "${IP4_ADDR}" ]; then - _ifconfig_inet="${_ifconfig_inet} inet ${IP4_ADDR}" + ifconfig_inet="inet ${IP4_ADDR}" fi - + # Enable IPv6 if used if [ -n "${IP6_ADDR}" ]; then - _ifconfig_inet6='inet6 -ifdisabled' + ifconfig_inet6='inet6 -ifdisabled' if echo "${IP}" | grep -qE 'SLAAC'; then # Enable SLAAC if requested - _ifconfig_inet6="${_ifconfig_inet6} accept_rtadv" + ifconfig_inet6="${ifconfig_inet6} accept_rtadv" else - # Else apply the default gateway + # Set Gateway if [ -n "${bastille_network_gateway6}" ]; then - _gateway6="${bastille_network_gateway6}" + gateway6="${bastille_network_gateway6}" else - _gateway6="$(netstat -6rn | awk '/default/ {print $2}')" + gateway6="$(netstat -6rn | awk '/default/ {print $2}')" fi fi fi - + # Add IPv6 address (this is empty if SLAAC is used) if [ -n "${IP6_ADDR}" ]; then - _ifconfig_inet6="${_ifconfig_inet6} ${IP6_ADDR}" + ifconfig_inet6="${ifconfig_inet6} ${IP6_ADDR}" fi - + # We need to pass IP4 and IP6 separately - _ifconfig="${_ifconfig_inet}" - _ifconfig6="${_ifconfig_inet6}" - bastille template "${NAME}" ${bastille_template_vnet} --arg EPAIR="${uniq_epair}" --arg GATEWAY="${_gateway}" --arg GATEWAY6="${_gateway6}" --arg IFCONFIG="${_ifconfig}" --arg IFCONFIG6="${_ifconfig6}" + ifconfig="${ifconfig_inet}" + ifconfig6="${ifconfig_inet6}" + + # Set jail interface description if "if_bridge" + if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then + # Use interface name as INTERFACE+VNET when PASSTHROUGH is selected + # Use default "vnet0" otherwise + if [ "${VNET_JAIL_PASSTHROUGH}" -eq 1 ]; then + bastille template "${NAME}" ${bastille_template_vnet} --arg INTERFACE="${uniq_epair}" --arg VNET="${INTERFACE}" --arg GATEWAY="${gateway}" --arg GATEWAY6="${gateway6}" --arg IFCONFIG="${ifconfig}" --arg IFCONFIG6="${ifconfig6}" + else + bastille template "${NAME}" ${bastille_template_vnet} --arg EXT_INTERFACE="${INTERFACE}" --arg INTERFACE="${uniq_epair}" --arg VNET="vnet0" --arg GATEWAY="${gateway}" --arg GATEWAY6="${gateway6}" --arg IFCONFIG="${ifconfig}" --arg IFCONFIG6="${ifconfig6}" + fi + elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then + # Use interface name as INTERFACE+VNET when PASSTHROUGH is selected + # Use default "vnet0" otherwise + if [ "${VNET_JAIL_PASSTHROUGH}" -eq 1 ]; then + bastille template "${NAME}" ${bastille_template_vnet} --arg INTERFACE="${uniq_epair}" --arg VNET="${INTERFACE}" --arg GATEWAY="${gateway}" --arg GATEWAY6="${gateway6}" --arg IFCONFIG="${ifconfig}" --arg IFCONFIG6="${ifconfig6}" + else + bastille template "${NAME}" ${bastille_template_vnet} --arg INTERFACE="${uniq_epair}" --arg VNET="vnet0" --arg GATEWAY="${gateway}" --arg GATEWAY6="${gateway6}" --arg IFCONFIG="${ifconfig}" --arg IFCONFIG6="${ifconfig6}" + fi + fi # Add VLAN ID if it was given - if [ -n "${VLAN_ID}" ]; then - bastille template "${NAME}" ${bastille_template_vlan} --arg VLANID="${VLAN_ID}" --arg IFCONFIG="${_ifconfig}" - fi + if [ -n "${VLAN_ID}" ]; then + bastille template "${NAME}" ${bastille_template_vlan} --arg VLANID="${VLAN_ID}" --arg IFCONFIG="${ifconfig}" + fi + fi fi - if [ -n "${THICK_JAIL}" ]; then + + # Apply thick/clone/empty/linux/thin template + if [ "${THICK_JAIL}" -eq 1 ]; then if [ -n "${bastille_template_thick}" ]; then bastille template "${NAME}" ${bastille_template_thick} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" fi - elif [ -n "${CLONE_JAIL}" ]; then + elif [ "${CLONE_JAIL}" -eq 1 ]; then if [ -n "${bastille_template_clone}" ]; then bastille template "${NAME}" ${bastille_template_clone} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" fi - elif [ -n "${EMPTY_JAIL}" ]; then + elif [ "${EMPTY_JAIL}" -eq 1 ]; then if [ -n "${bastille_template_empty}" ]; then bastille template "${NAME}" ${bastille_template_empty} --arg BASE_TEMPLATE="${bastille_template_base}" --arg HOST_RESOLV_CONF="${bastille_resolv_conf}" fi ## Using templating function to fetch necessary packges @hackacad - elif [ -n "${LINUX_JAIL}" ]; then + elif [ "${LINUX_JAIL}" -eq 1 ]; then info "\nFetching packages..." jexec -l "${NAME}" /bin/bash -c "DEBIAN_FRONTEND=noninteractive rm /var/cache/apt/archives/rsyslog*.deb" jexec -l "${NAME}" /bin/bash -c "DEBIAN_FRONTEND=noninteractive dpkg --force-depends --force-confdef --force-confold -i /var/cache/apt/archives/*.deb" @@ -730,15 +773,15 @@ create_jail() { # Apply nameserver (if set) if [ -n "${OPT_NAMESERVER}" ]; then sed -i '' "/^nameserver.*/d" "${bastille_jail_resolv_conf}" - for _ns in $(echo ${OPT_NAMESERVER} | sed 's/,/ /g'); do - echo "nameserver ${_ns}" >> "${bastille_jail_resolv_conf}" + for ns in $(echo ${OPT_NAMESERVER} | sed 's/,/ /g'); do + echo "nameserver ${ns}" >> "${bastille_jail_resolv_conf}" done fi # Apply values changed by the template. -- cwells - if [ -z "${EMPTY_JAIL}" ] && [ -z "${LINUX_JAIL}" ]; then + if [ "${EMPTY_JAIL}" -eq 0 ] && [ "${LINUX_JAIL}" -eq 0 ]; then bastille restart "${NAME}" - elif [ -n "${EMPTY_JAIL}" ]; then + elif [ "${EMPTY_JAIL}" -eq 1 ]; then # Don't restart empty jails unless a template defined. if [ -n "${bastille_template_empty}" ]; then bastille restart "${NAME}" @@ -748,25 +791,20 @@ create_jail() { bastille_root_check -if echo "${3}" | grep '@'; then - # shellcheck disable=SC2034 - BASTILLE_JAIL_IP=$(echo "$3" | awk -F@ '{print $2}') - # shellcheck disable=SC2034 - BASTILLE_JAIL_INTERFACES=$( echo "$3" | awk -F@ '{print $1}') -fi - # Handle options. BOOT="on" -EMPTY_JAIL="" -THICK_JAIL="" -CLONE_JAIL="" -VNET_JAIL="" -VNET_JAIL_BRIDGE="" +EMPTY_JAIL=0 +THICK_JAIL=0 +CLONE_JAIL=0 +VNET_JAIL=0 +VNET_JAIL_STANDARD=0 +VNET_JAIL_BRIDGE=0 +VNET_JAIL_PASSTHROUGH=0 VLAN_ID="" -LINUX_JAIL="" -STATIC_MAC="" -DUAL_STACK="" -VALIDATE_RELEASE="1" +LINUX_JAIL=0 +STATIC_MAC=0 +DUAL_STACK=0 +VALIDATE_RELEASE=1 PRIORITY="99" OPT_GATEWAY="" OPT_NAMESERVER="" @@ -776,25 +814,25 @@ while [ $# -gt 0 ]; do usage ;; -B|--bridge) - VNET_JAIL="1" - VNET_JAIL_BRIDGE="1" + VNET_JAIL=1 + VNET_JAIL_BRIDGE=1 shift ;; -C|--clone) - CLONE_JAIL="1" + CLONE_JAIL=1 shift ;; -D|--dual) - DUAL_STACK="1" + DUAL_STACK=1 shift ;; -E|--empty) - EMPTY_JAIL="1" + EMPTY_JAIL=1 shift ;; -g|--gateway|--defaultrouter) OPT_GATEWAY="${2}" - # Validate gateway + # Validate gateway if [ -n "${OPT_GATEWAY}" ]; then if ! validate_ip "${OPT_GATEWAY}" >/dev/null 2>/dev/null; then error_exit "[ERROR]: Not a valid gateway: ${OPT_GATEWAY}" @@ -803,16 +841,16 @@ while [ $# -gt 0 ]; do shift 2 ;; -L|--linux) - LINUX_JAIL="1" + LINUX_JAIL=1 shift ;; -M|--static-mac) - STATIC_MAC="1" + STATIC_MAC=1 shift ;; -n|--nameserver) OPT_NAMESERVER="${2}" - # Validate nameserver + # Validate nameserver if [ -n "${OPT_NAMESERVER}" ]; then for _nameserver in $(echo ${OPT_NAMESERVER} | sed 's/,/ /g'); do if ! validate_ip "${_nameserver}" >/dev/null 2>/dev/null; then @@ -822,28 +860,34 @@ while [ $# -gt 0 ]; do fi shift 2 ;; - -p|--priority) - if echo "${2}" | grep -Eoq "^[0-9]+$"; then - PRIORITY="${2}" - shift 2 - else - error_exit "Not a valid priority value: \"${2}\"" - fi - ;; --no-boot) BOOT="off" shift ;; --no-validate|no-validate) - VALIDATE_RELEASE="" + VALIDATE_RELEASE=0 shift ;; + -P|--passthrough) + VNET_JAIL=1 + VNET_JAIL_PASSTHROUGH=1 + shift + ;; + -p|--priority) + if echo "${2}" | grep -Eoq "^[0-9]+$"; then + PRIORITY="${2}" + shift 2 + else + error_exit "Not a valid priority value: \"${2}\"" + fi + ;; -T|--thick) - THICK_JAIL="1" + THICK_JAIL=1 shift ;; -V|--vnet) - VNET_JAIL="1" + VNET_JAIL=1 + VNET_JAIL_STANDARD=1 shift ;; -v|--vlan) @@ -862,7 +906,7 @@ while [ $# -gt 0 ]; do bastille_zfs_options="${2}" shift 2 ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in B) VNET_JAIL=1 VNET_JAIL_BRIDGE=1 ;; @@ -871,10 +915,11 @@ while [ $# -gt 0 ]; do E) EMPTY_JAIL=1 ;; L) LINUX_JAIL=1 ;; M) STATIC_MAC=1 ;; + P) VNET_JAIL=1 VNET_JAIL_PASSTHROUGH=1 ;; T) THICK_JAIL=1 ;; - V) VNET_JAIL=1 ;; + V) VNET_JAIL=1 VNET_JAIL_STANDARD=1 ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -886,18 +931,39 @@ while [ $# -gt 0 ]; do done # Validate options -if [ -n "${EMPTY_JAIL}" ]; then - if [ -n "${CLONE_JAIL}" ] || [ -n "${THICK_JAIL}" ] || [ -n "${VNET_JAIL}" ] || [ -n "${LINUX_JAIL}" ]; then +# Do not allow EMPTY_JAIL with any other jail type +if [ "${EMPTY_JAIL}" -eq 1 ]; then + if [ "${CLONE_JAIL}" -eq 1 ] || [ "${THICK_JAIL}" -eq 1 ] || [ "${VNET_JAIL}" -eq 1 ] || [ "${LINUX_JAIL}" -eq 1 ]; then error_exit "[ERROR]: Empty jail option can't be used with other options." fi -elif [ -n "${LINUX_JAIL}" ]; then - if [ -n "${EMPTY_JAIL}" ] || [ -n "${VNET_JAIL}" ] || [ -n "${THICK_JAIL}" ] || [ -n "${CLONE_JAIL}" ]; then +# Do not allow LINUX_JAIL with any other jail type +elif [ "${LINUX_JAIL}" -eq 1 ]; then + if [ "${EMPTY_JAIL}" -eq 1 ] || [ "${VNET_JAIL}" -eq 1 ] || [ "${THICK_JAIL}" -eq 1 ] || [ "${CLONE_JAIL}" -eq 1 ]; then error_exit "[ERROR]: Linux jail option can't be used with other options." fi -elif [ -n "${CLONE_JAIL}" ] && [ -n "${THICK_JAIL}" ]; then +# Do not allow CLONE_JAIL and THICK_JAIL together +elif [ "${CLONE_JAIL}" -eq 1 ] && [ "${THICK_JAIL}" -eq 1 ]; then error_exit "[ERROR]: Clonejail and Thickjail can't be used together." -elif [ -z "${VNET_JAIL}" ] && [ -z "${VNET_JAIL_BRIDGE}" ] && [ -n "${VLAN_ID}" ]; then - error_exit "[ERROR]: VLANs can only be used with VNET and bridged VNET jails." +# VLAN_ID can only be used with VNET jails +elif [ "${VNET_JAIL}" -eq 0 ] && [ -n "${VLAN_ID}" ]; then + error_exit "[ERROR]: VLANs can only be used with VNET jails." +# Don't allow multiple VNET jail types +elif { [ "${VNET_JAIL_STANDARD}" -eq 1 ] && [ "${VNET_JAIL_BRIDGE}" -eq 1 ]; } || \ + { [ "${VNET_JAIL_STANDARD}" -eq 1 ] && [ "${VNET_JAIL_PASSTHROUGH}" -eq 1 ]; } || \ + { [ "${VNET_JAIL_BRIDGE}" -eq 1 ] && [ "${VNET_JAIL_PASSTHROUGH}" -eq 1 ]; } then + error_exit "[ERROR]: Only one of [-V|--vnet], [-B|--bridge] or [-P|--passthrough] can be selected." +# Don't allow STATIC_MAC with VNET_JAIL_PASSTHROUGH +elif [ "${VNET_JAIL_PASSTHROUGH}" -eq 1 ] && [ "${STATIC_MAC}" -eq 1 ]; then + error_exit "[ERROR]: [-P|--passthrough] does not support [-M|--static-mac]." +fi + +# Set interface type for VNET jails +if [ "${VNET_JAIL_STANDARD}" -eq 1 ]; then + VNET_INTERFACE_TYPE="standard" +elif [ "${VNET_JAIL_BRIDGE}" -eq 1 ]; then + VNET_INTERFACE_TYPE="bridge" +elif [ "${VNET_JAIL_PASSTHROUGH}" -eq 1 ]; then + VNET_INTERFACE_TYPE="passthrough" fi NAME="$1" @@ -907,7 +973,7 @@ INTERFACE="$4" info "\nAttempting to create jail: ${NAME}" -if [ -n "${EMPTY_JAIL}" ]; then +if [ "${EMPTY_JAIL}" -eq 1 ]; then if [ $# -ne 1 ]; then usage fi @@ -923,143 +989,109 @@ if [ -n "${NAME}" ]; then fi # Validate interface type -if [ -n "${VNET_JAIL}" ] && [ -n "${VNET_JAIL_BRIDGE}" ]; then +if [ "${VNET_INTERFACE_TYPE}" = "bridge" ]; then if ! ifconfig -g bridge | grep -owq "${INTERFACE}"; then error_exit "[ERROR]: Interface is not a bridge: ${INTERFACE}" fi -elif [ -n "${VNET_JAIL}" ] && [ -z "${VNET_JAIL_BRIDGE}" ]; then +elif [ "${VNET_INTERFACE_TYPE}" = "standard" ]; then if ifconfig -g bridge | grep -owq "${INTERFACE}"; then error_exit "[ERROR]: Interface is a bridge: ${INTERFACE}" fi +elif [ "${VNET_INTERFACE_TYPE}" = "passthrough" ]; then + if ! ifconfig -l | grep -owq "${INTERFACE}"; then + error_exit "[ERROR]: Interface does not exist: ${INTERFACE}" + fi fi # Do not allow netgraph with -B|--bridge yet... -if [ "${bastille_network_vnet_type}" = "netgraph" ] && [ -n "${VNET_JAIL_BRIDGE}" ]; then - error_exit "[ERROR]: Netgraph does not support the [-B|--bridge] option." +if { [ "${bastille_network_vnet_type}" = "netgraph" ] && [ "${VNET_INTERFACE_TYPE}" = "bridge" ]; } || \ + { [ "${bastille_network_vnet_type}" = "netgraph" ] && [ "${VNET_INTERFACE_TYPE}" = "bridge" ]; } then + error_exit "[ERROR]: Netgraph does not support the [-B|--bridge] or [-P|--passthrough] option." fi -if [ -n "${LINUX_JAIL}" ] && [ -n "${VALIDATE_RELEASE}" ]; then - case "${RELEASE}" in - bionic|ubuntu_bionic|ubuntu|ubuntu-bionic) - ## check for FreeBSD releases name - NAME_VERIFY=ubuntu_bionic - ;; - focal|ubuntu_focal|ubuntu-focal) - ## check for FreeBSD releases name - NAME_VERIFY=ubuntu_focal - ;; - jammy|ubuntu_jammy|ubuntu-jammy) - ## check for FreeBSD releases name - NAME_VERIFY=ubuntu_jammy - ;; - debian_buster|buster|debian-buster) - ## check for FreeBSD releases name - NAME_VERIFY=buster - ;; - debian_bullseye|bullseye|debian-bullseye) - ## check for FreeBSD releases name - NAME_VERIFY=bullseye - ;; - debian_bookworm|bookworm|debian-bookworm) - ## check for FreeBSD releases name - NAME_VERIFY=bookworm - ;; - *) - error_notify "[ERROR]: Unknown linux release." - usage - ;; - esac -fi - -if [ -z "${EMPTY_JAIL}" ]; then - if [ -n "${VALIDATE_RELEASE}" ]; then - ## verify release +# Filter sane release names +if [ "${EMPTY_JAIL}" -eq 0 ]; then + if [ "${VALIDATE_RELEASE}" -eq 1 ]; then + # Verify release case "${RELEASE}" in - [2-4].[0-9]*) - ## check for MidnightBSD releases name - NAME_VERIFY=$(echo "${RELEASE}") - validate_release - ;; - *-CURRENT|*-CURRENT-I386|*-CURRENT-i386|*-current) - ## check for FreeBSD releases name - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]{2,2})\.[0-9](-CURRENT|-CURRENT-i386)$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') - validate_release - ;; - *-RELEASE|*-RELEASE-I386|*-RELEASE-i386|*-release|*-RC[1-9]|*-rc[1-9]|*-BETA[1-9]) - ## check for FreeBSD releases name - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]{2,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-9]|-BETA[1-9])$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') - validate_release - ;; - *-stable-LAST|*-STABLE-last|*-stable-last|*-STABLE-LAST) - ## check for HardenedBSD releases name(previous infrastructure) - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]{2,2})(-stable-last)$' | sed 's/STABLE/stable/g' | sed 's/last/LAST/g') - validate_release - ;; - *-stable-build-[0-9]*|*-STABLE-BUILD-[0-9]*) - ## check for HardenedBSD(specific stable build releases) - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '([0-9]{1,2})(-stable-build)-([0-9]{1,3})$' | sed 's/BUILD/build/g' | sed 's/STABLE/stable/g') - validate_release - ;; - *-stable-build-latest|*-stable-BUILD-LATEST|*-STABLE-BUILD-LATEST) - ## check for HardenedBSD(latest stable build release) - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '([0-9]{1,2})(-stable-build-latest)$' | sed 's/STABLE/stable/g' | sed 's/build/BUILD/g' | sed 's/latest/LATEST/g') - validate_release - ;; - current-build-[0-9]*|CURRENT-BUILD-[0-9]*) - ## check for HardenedBSD(specific current build releases) - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '(current-build)-([0-9]{1,3})' | sed 's/BUILD/build/g' | sed 's/CURRENT/current/g') - validate_release - ;; - current-build-latest|current-BUILD-LATEST|CURRENT-BUILD-LATEST) - ## check for HardenedBSD(latest current build release) - NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '(current-build-latest)' | sed 's/CURRENT/current/g' | sed 's/build/BUILD/g' | sed 's/latest/LATEST/g') - validate_release - ;; - ubuntu_bionic|bionic|ubuntu-bionic) - UBUNTU="1" - NAME_VERIFY=Ubuntu_1804 - validate_release - ;; - ubuntu_focal|focal|ubuntu-focal) - UBUNTU="1" - NAME_VERIFY=Ubuntu_2004 - validate_release - ;; - ubuntu_jammy|jammy|ubuntu-jammy) - UBUNTU="1" - NAME_VERIFY=Ubuntu_2204 - validate_release - ;; - debian_buster|buster|debian-buster) - NAME_VERIFY=Debian10 - validate_release - ;; - debian_bullseye|bullseye|debian-bullseye) - NAME_VERIFY=Debian11 - validate_release - ;; - debian_bookworm|bookworm|debian-bookworm) - NAME_VERIFY=Debian12 - validate_release - ;; - *) - error_notify "Unknown Release." - usage - ;; + [2-4].[0-9]*) + ### MidnightBSD ## + PLATFORM_OS="MidnightBSD" + NAME_VERIFY=$(echo "${RELEASE}") + validate_release + ;; + *-current|*-CURRENT|*-current-I386|*-CURRENT-i386) + ### FreeBSD ### + PLATFORM_OS="FreeBSD" + NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]+)\.[0-9](-CURRENT|-CURRENT-i386)$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') + validate_release + ;; + *-release|*-RELEASE|*-release-I386|*-RELEASE-i386|*-rc[1-9]|*-RC[1-9]|*-beta[1-9]|*-BETA[1-9]) + ### FreeBSD ### + PLATFORM_OS="FreeBSD" + NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]+)\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-9]|-BETA[1-9])$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') + validate_release + ;; + *\.*-stable|*\.*-STABLE) + ### FreeBSD ### + PLATFORM_OS="FreeBSD" + NAME_VERIFY=$(echo "${RELEASE}" | grep -iwE '^([1-9]+)\.[0-9](-STABLE)$' | tr '[:lower:]' '[:upper:]') + validate_release + ;; + current|CURRENT) + ### HardenedBSD ### + PLATFORM_OS="HardenedBSD" + NAME_VERIFY=$(echo "${RELEASE}" | sed 's/CURRENT/current/g') + validate_release + ;; + [1-9]*-stable|[1-9]*-STABLE) + ### HardenedBSD ### + PLATFORM_OS="HardenedBSD" + NAME_VERIFY=$(echo "${RELEASE}" | sed 's/STABLE/stable/g') + validate_release + ;; + ubuntu_bionic|bionic|ubuntu-bionic) + PLATFORM_OS="Ubuntu" + NAME_VERIFY=Ubuntu_1804 + validate_release + ;; + ubuntu_focal|focal|ubuntu-focal) + PLATFORM_OS="Ubuntu" + NAME_VERIFY=Ubuntu_2004 + validate_release + ;; + ubuntu_jammy|jammy|ubuntu-jammy) + PLATFORM_OS="Ubuntu" + NAME_VERIFY=Ubuntu_2204 + validate_release + ;; + ubuntu_noble|noble|ubuntu-noble) + PLATFORM_OS="Ubuntu" + NAME_VERIFY=Ubuntu_2404 + validate_release + ;; + debian_buster|buster|debian-buster) + PLATFORM_OS="Debian" + NAME_VERIFY=Debian10 + validate_release + ;; + debian_bullseye|bullseye|debian-bullseye) + PLATFORM_OS="Debian" + NAME_VERIFY=Debian11 + validate_release + ;; + debian_bookworm|bookworm|debian-bookworm) + PLATFORM_OS="Debian" + NAME_VERIFY=Debian12 + validate_release + ;; + *) + error_notify "Unknown release: ${RELEASE}" + usage + ;; esac fi - # Check for name/root/.bastille - if [ -d "${bastille_jailsdir}/${NAME}/root/.bastille" ]; then - error_exit "[ERROR]: ${NAME} already exists. ${NAME}/root/.bastille exists." - fi - - # Check for required release - if [ ! -d "${bastille_releasesdir}/${RELEASE}" ]; then - error_notify "[ERROR]: Release must be bootstrapped first." - error_exit "See 'bastille bootstrap'." - fi - # Validate IP address if [ -n "${IP}" ]; then validate_ips @@ -1068,14 +1100,14 @@ if [ -z "${EMPTY_JAIL}" ]; then fi # Validate interface + # Interface must be set with vnet jails if [ -n "${INTERFACE}" ]; then validate_netif validate_netconf - elif [ -n "${VNET_JAIL}" ]; then + elif [ "${VNET_JAIL}" -eq 1 ]; then if [ -z "${INTERFACE}" ]; then if [ -z "${bastille_network_shared}" ]; then - # User must specify interface on vnet jails. - error_exit "[ERROR]: Network interface not defined." + error_exit "[ERROR]: Network interface not set." else validate_netconf fi @@ -1115,11 +1147,8 @@ fi if [ -z ${bastille_template_vnet+x} ]; then bastille_template_vnet='default/vnet' fi - -if check_target_exists "${NAME}"; then - error_exit "[ERROR]: Jail already exists: ${NAME}" +if [ -z ${bastille_template_vlan+x} ]; then + bastille_template_vnet='default/vlan' fi create_jail "${NAME}" "${RELEASE}" "${IP}" "${INTERFACE}" - -echo diff --git a/usr/local/share/bastille/destroy.sh b/usr/local/share/bastille/destroy.sh index 56081e10..a2f32031 100644 --- a/usr/local/share/bastille/destroy.sh +++ b/usr/local/share/bastille/destroy.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille destroy [option(s)] JAIL|RELEASE" cat << EOF - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. @@ -137,7 +137,7 @@ destroy_jail() { fi } -destroy_rel() { +destroy_release() { local OPTIONS @@ -156,7 +156,7 @@ destroy_rel() { BASE_HASCHILD="0" if [ -d "${bastille_jailsdir}" ]; then - JAIL_LIST=$(ls "${bastille_jailsdir}" | sed "s/\n//g") + JAIL_LIST=$(ls -v --color=never "${bastille_jailsdir}" | sed "s/\n//g") for _jail in ${JAIL_LIST}; do @@ -256,7 +256,7 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; @@ -288,53 +288,58 @@ case "${TARGET}" in *-CURRENT|*-CURRENT-I386|*-CURRENT-i386|*-current) ## check for FreeBSD releases name NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})\.[0-9](-CURRENT|-CURRENT-i386)$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') - destroy_rel + destroy_release ;; *-RELEASE|*-RELEASE-I386|*-RELEASE-i386|*-release|*-RC[1-9]|*-rc[1-9]|*-BETA[1-9]) ## check for FreeBSD releases name - NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-9]|-BETA[1-9])$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') - destroy_rel + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([0-9]{1,2})\.[0-9](-RELEASE|-RELEASE-i386|-RC[1-9]|-BETA[1-9])$' | tr '[:lower:]' '[:upper:]' | sed 's/I/i/g') + destroy_release ;; *-stable-LAST|*-STABLE-last|*-stable-last|*-STABLE-LAST) ## check for HardenedBSD releases name NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]{2,2})(-stable-last)$' | sed 's/STABLE/stable/g;s/last/LAST/g') - destroy_rel + destroy_release ;; *-stable-build-[0-9]*|*-STABLE-BUILD-[0-9]*) ## check for HardenedBSD(specific stable build releases) NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '([0-9]{1,2})(-stable-build)-([0-9]{1,3})$' | sed 's/BUILD/build/g;s/STABLE/stable/g') - destroy_rel + destroy_release ;; *-stable-build-latest|*-stable-BUILD-LATEST|*-STABLE-BUILD-LATEST) ## check for HardenedBSD(latest stable build release) NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '([0-9]{1,2})(-stable-build-latest)$' | sed 's/STABLE/stable/;s/build/BUILD/g;s/latest/LATEST/g') - destroy_rel + destroy_release ;; current-build-[0-9]*|CURRENT-BUILD-[0-9]*) ## check for HardenedBSD(specific current build releases) NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(current-build)-([0-9]{1,3})' | sed 's/BUILD/build/g;s/CURRENT/current/g') - destroy_rel + destroy_release ;; current-build-latest|current-BUILD-LATEST|CURRENT-BUILD-LATEST) ## check for HardenedBSD(latest current build release) NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(current-build-latest)$' | sed 's/CURRENT/current/;s/build/BUILD/g;s/latest/LATEST/g') - destroy_rel + destroy_release ;; Ubuntu_1804|Ubuntu_2004|Ubuntu_2204|UBUNTU_1804|UBUNTU_2004|UBUNTU_2204) ## check for Linux releases NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(Ubuntu_1804)$|(Ubuntu_2004)$|(Ubuntu_2204)$' | sed 's/UBUNTU/Ubuntu/g;s/ubuntu/Ubuntu/g') - destroy_rel + destroy_release ;; Debian10|Debian11|Debian12|DEBIAN10|DEBIAN11|DEBIAN12) ## check for Linux releases NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '(Debian10)$|(Debian11)$|(Debian12)$' | sed 's/DEBIAN/Debian/g') - destroy_rel + destroy_release ;; *) - # Destroy targeted jail(s) - set_target "${TARGET}" "reverse" - for _jail in ${JAILS}; do - destroy_jail "${_jail}" - done + if [ -d "${bastille_releasesdir}/${TARGET}" ]; then + NAME_VERIFY="${TARGET}" + destroy_release + else + # Destroy targeted jail(s) + set_target "${TARGET}" "reverse" + for _jail in ${JAILS}; do + destroy_jail "${_jail}" + done + fi ;; esac diff --git a/usr/local/share/bastille/edit.sh b/usr/local/share/bastille/edit.sh index 0f657e1f..83dfcc11 100644 --- a/usr/local/share/bastille/edit.sh +++ b/usr/local/share/bastille/edit.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille edit [option(s)] TARGET [FILE]" cat << EOF - + Options: -x | --debug Enable debug mode. @@ -71,7 +71,7 @@ fi TARGET="${1}" if [ "$#" -eq 2 ]; then TARGET_FILENAME="${2}" -else +else TARGET_FILENAME="jail.conf" fi diff --git a/usr/local/share/bastille/etcupdate.sh b/usr/local/share/bastille/etcupdate.sh index 7a2f0f9d..fb5b50df 100644 --- a/usr/local/share/bastille/etcupdate.sh +++ b/usr/local/share/bastille/etcupdate.sh @@ -32,7 +32,7 @@ usage() { error_notify "Usage: bastille etcupdate [option(s)] [bootstrap|TARGET] [diff|resolve|update RELEASE]" cat << EOF - + Options: -d | --dry-run Show output, but do not apply. @@ -43,84 +43,124 @@ EOF exit 1 } +bootstrap_etc_release_pkgbase() { + + local release="${1}" + local release_dir="${bastille_releasesdir}/${release}" + local abi="FreeBSD:${MAJOR_VERSION}:${HW_MACHINE_ARCH}" + local fingerprints="${release_dir}/usr/share/keys/pkg" + if [ "${FREEBSD_BRANCH}" = "release" ]; then + local repo_name="FreeBSD-base-release-${MINOR_VERSION}" + elif [ "${FREEBSD_BRANCH}" = "current" ]; then + local repo_name="FreeBSD-base-latest" + fi + local repo_dir="${bastille_sharedir}/pkgbase" + + if [ -d "${release_dir}" ]; then + # Update repo (pkgbase) + if ! pkg --rootdir "${release_dir}" \ + --repo-conf-dir "${repo_dir}" \ + -o IGNORE_OSVERSION="yes" \ + -o ABI="${abi}" \ + -o ASSUME_ALWAYS_YES="yes" \ + -o FINGERPRINTS="${fingerprints}" \ + update -r "${repo_name}"; then + error_exit "[ERROR]: Failed to update pkg repo: ${repo_name}" + fi + # Install FreeBSD-set-src + if ! pkg --rootdir "${release_dir}" \ + --repo-conf-dir "${repo_dir}" \ + -o IGNORE_OSVERSION="yes" \ + -o ABI="${abi}" \ + -o ASSUME_ALWAYS_YES="yes" \ + -o FINGERPRINTS="${fingerprints}" \ + install -r "${repo_name}" \ + FreeBSD-set-src; then + error_exit "[ERROR]: Failed to install package set: FreeBSD-set-src" + fi + else + error_exit "[ERROR]: Release not found: ${release}" + fi +} + bootstrap_etc_release() { - local _release="${1}" - local _current="$(sysrc -f /usr/local/etc/bastille/bastille.conf bastille_bootstrap_archives | awk -F': ' '{print $2}')" + local release="${1}" + local current="$(sysrc -f /usr/local/etc/bastille/bastille.conf bastille_bootstrap_archives | awk -F': ' '{print $2}')" - if [ ! -f "${bastille_cachedir}/${_release}/src.txz" ]; then - sysrc -f /usr/local/etc/bastille/bastille.conf bastille_bootstrap_archives=src - if ! bastille bootstrap "${_release}" > /dev/null; then - sysrc -f /usr/local/etc/bastille/bastille.conf bastille_bootstrap_archives="${_current}" - error_exit "[ERROR]: Failed to bootstrap etcupdate: ${_release}" + if [ ! -f "${bastille_cachedir}/${release}/src.txz" ]; then + sysrc -f /usr/local/etc/bastille/bastille.conf bastille_bootstrap_archives="src" + if ! bastille bootstrap "${release}" > /dev/null; then + sysrc -f /usr/local/etc/bastille/bastille.conf bastille_bootstrap_archives="${current}" + error_exit "[ERROR]: Failed to bootstrap etcupdate: ${release}" else - sysrc -f /usr/local/etc/bastille/bastille.conf bastille_bootstrap_archives="${_current}" + sysrc -f /usr/local/etc/bastille/bastille.conf bastille_bootstrap_archives="${current}" fi fi } bootstrap_etc_tarball() { - local _release="${1}" + local release="${1}" - if [ ! -f ${bastille_cachedir}/${_release}.tbz2 ]; then + if [ ! -f ${bastille_cachedir}/${release}.tbz2 ]; then info "\nBuilding tarball, please wait..." - if ! etcupdate build -d /tmp/etcupdate -s ${bastille_releasesdir}/${_release}/usr/src ${bastille_cachedir}/${_release}.tbz2; then - error_exit "[ERROR]: Failed to build etcupdate tarball \"${_release}.tbz2\"" + if ! etcupdate build -d /tmp/etcupdate -s ${bastille_releasesdir}/${release}/usr/src ${bastille_cachedir}/${release}.tbz2; then + error_exit "[ERROR]: Failed to build etcupdate tarball \"${release}.tbz2\"" else - info "\nEtcupdate bootstrap complete: ${_release}" + info "\nEtcupdate bootstrap complete: ${release}" fi - elif [ -f ${bastille_cachedir}/${_release}.tbz2 ] && [ "${FORCE}" -eq 1 ]; then - rm -f "${bastille_cachedir}/${_release}.tbz2" + elif [ -f ${bastille_cachedir}/${release}.tbz2 ] && [ "${FORCE}" -eq 1 ]; then + rm -f "${bastille_cachedir}/${release}.tbz2" info "\nBuilding tarball, please wait..." - if ! etcupdate build -d /tmp/etcupdate -s ${bastille_releasesdir}/${_release}/usr/src ${bastille_cachedir}/${_release}.tbz2; then - error_exit "[ERROR]: Failed to build etcupdate tarball: ${_release}.tbz2" + if ! etcupdate build -d /tmp/etcupdate -s ${bastille_releasesdir}/${release}/usr/src ${bastille_cachedir}/${release}.tbz2; then + error_exit "[ERROR]: Failed to build etcupdate tarball: ${release}.tbz2" else - info "\nEtcupdate bootstrap complete: ${_release}" + info "\nEtcupdate bootstrap complete: ${release}" fi else - info "\nEtcupdate release has already been prepared for application: ${_release}" + info "\nEtcupdate release has already been prepared for application: ${release}" fi } diff_review() { - local _jail="${1}" + local jail="${1}" if [ "${DRY_RUN}" -eq 1 ]; then error_exit "[ERROR]: diff mode does not support [-d|--dryrun]" fi echo "Running: etcupdate --diff mode" - etcupdate diff -D "${bastille_jailsdir}/${_jail}/root" + etcupdate diff -D "${bastille_jailsdir}/${jail}/root" } resolve_conflicts() { - local _jail="${1}" + local jail="${1}" if [ "${DRY_RUN}" -eq 1 ]; then error_exit "[ERROR]: resolve mode does not support [-d|--dryrun]" fi echo "Running: etcupdate resolve" - etcupdate resolve -D "${bastille_jailsdir}/${_jail}/root" + etcupdate resolve -D "${bastille_jailsdir}/${jail}/root" } update_jail_etc() { - local _jail="${1}" - local _release="${2}" + local jail="${1}" + local release="${2}" - if [ ! -f ${bastille_cachedir}/${_release}.tbz2 ]; then + if [ ! -f ${bastille_cachedir}/${release}.tbz2 ]; then error_exit "[ERROR]: Please run 'bastille etcupdate bootstrap RELEASE' first." fi if [ "${DRY_RUN}" -eq 1 ]; then echo "Running: etcupdate update --dry-run" - etcupdate -n -D "${bastille_jailsdir}/${_jail}/root" -t ${bastille_cachedir}/${_release}.tbz2 + etcupdate -n -D "${bastille_jailsdir}/${jail}/root" -t ${bastille_cachedir}/${release}.tbz2 else echo "Running: etcupdate update" - etcupdate -D "${bastille_jailsdir}/${_jail}/root" -t ${bastille_cachedir}/${_release}.tbz2 + etcupdate -D "${bastille_jailsdir}/${jail}/root" -t ${bastille_cachedir}/${release}.tbz2 fi } @@ -144,13 +184,13 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in d) DRY_RUN=1 ;; f) FORCE=1 ;; x) enable_debug ;; - *) error_exit "Unknown Option: \"${1}\"" ;; + *) error_exit "Unknown Option: \"${1}\"" ;; esac done shift @@ -173,9 +213,28 @@ while [ "$#" -gt 0 ]; do usage else RELEASE="${2}" + # Validate PKGBASE or non-PKGBASE + HW_MACHINE_ARCH=$(sysctl hw.machine_arch | awk '{ print $2 }') + MINOR_VERSION=$(echo ${RELEASE} | sed -E 's/^[0-9]+\.([0-9]+)-.*$/\1/') + MAJOR_VERSION=$(echo ${RELEASE} | grep -Eo '^[0-9]+') + if echo "${NEW_RELEASE}" | grep -oq "\-CURRENT"; then + FREEBSD_BRANCH="current" + else + FREEBSD_BRANCH="release" + fi info "\nAttempting to bootstrap etcupdate release: ${RELEASE}..." - bootstrap_etc_release "${RELEASE}" - bootstrap_etc_tarball "${RELEASE}" + if [ "${MAJOR_VERSION}" -ge 16 ] || pkg -r "${bastille_releasesdir}/${RELEASE}" which /usr/bin/uname >/dev/null 2>&1; then + PKGBASE=1 + else + PKGBASE=0 + fi + if [ "${PKGBASE}" -eq 1 ]; then + bootstrap_etc_release_pkgbase "${RELEASE}" + bootstrap_etc_tarball "${RELEASE}" + else + bootstrap_etc_release "${RELEASE}" + bootstrap_etc_tarball "${RELEASE}" + fi shift "$#" fi ;; @@ -212,5 +271,3 @@ while [ "$#" -gt 0 ]; do ;; esac done - -echo \ No newline at end of file diff --git a/usr/local/share/bastille/export.sh b/usr/local/share/bastille/export.sh index 44bcd0b9..614f8cf8 100644 --- a/usr/local/share/bastille/export.sh +++ b/usr/local/share/bastille/export.sh @@ -39,18 +39,20 @@ usage() { # If no compression option specified, user must redirect standard output error_notify "Usage: bastille export [option(s)] TARGET PATH" cat << EOF - + Options: - -a | --auto Auto mode. Start/stop jail(s) if required. - --gz Export a ZFS jail using GZIP(.gz) compressed image. - -r | --raw Export a ZFS jail to an uncompressed RAW image. - -s | --safe Safely stop and start a ZFS jail before the exporting process. - --tgz Export a jail using simple .tgz compressed archive instead. - --txz Export a jail using simple .txz compressed archive instead. - -v | --verbose Be more verbose during the ZFS send operation. - --xz Export a ZFS jail using XZ(.xz) compressed image. - -x | --debug Enable debug mode. + -a | --auto Auto mode. Start/stop jail(s) if required. + -l | --live Export a running jail (ZFS only). + --gz Export to '.gz' compressed image (ZFS only). + --xz Export to a '.xz' compressed image (ZFS only). + --zst Export to a .zst compressed image (ZFS only). + --raw Export to an uncompressed RAW image (ZFS only). + --tgz Export to a '.tgz' compressed archive. + --txz Export to a '.txz' compressed archive. + --tzst Export to a '.tzst' compressed archive. + -v | --verbose Enable verbose mode (ZFS only). + -x | --debug Enable debug mode. Note: If no export option specified, the jail should be redirected to standard output. @@ -72,17 +74,18 @@ opt_count() { # Reset export options AUTO=0 -GZIP_EXPORT= -XZ_EXPORT= -SAFE_EXPORT= -USER_EXPORT= -RAW_EXPORT= -DIR_EXPORT= -TXZ_EXPORT= -TGZ_EXPORT= +LIVE=0 +GZIP_EXPORT=0 +XZ_EXPORT=0 +ZST_EXPORT=0 +RAW_EXPORT=0 OPT_ZSEND="-R" -COMP_OPTION="0" - +TXZ_EXPORT=0 +TGZ_EXPORT=0 +TZST_EXPORT=0 +USER_EXPORT=0 +DIR_EXPORT="" +COMP_OPTION=0 if [ -n "${bastille_export_options}" ]; then # Overrides the case options by the user defined option(s) automatically. # Add bastille_export_options="--optionA --optionB" to bastille.conf, or simply `export bastille_export_options="--optionA --optionB"` environment variable. @@ -99,6 +102,9 @@ if [ -n "${bastille_export_options}" ]; then -a|--auto) AUTO="1" ;; + -l|--live) + LIVE="1" + ;; --gz) GZIP_EXPORT="1" opt_count @@ -107,6 +113,14 @@ if [ -n "${bastille_export_options}" ]; then XZ_EXPORT="1" opt_count ;; + --zst) + ZST_EXPORT="1" + opt_count + ;; + -r|--raw) + RAW_EXPORT="1" + opt_count + ;; --tgz) TGZ_EXPORT="1" opt_count @@ -117,21 +131,21 @@ if [ -n "${bastille_export_options}" ]; then opt_count zfs_enable_check ;; - -s|--safe) - SAFE_EXPORT="1" - ;; - -r|--raw) - RAW_EXPORT="1" + --tzst) + TZST_EXPORT="1" opt_count + zfs_enable_check ;; -v|--verbose) OPT_ZSEND="-Rv" ;; -x) - enable_debug - ;; - -*) error_notify "[ERROR]: Unknown Option: \"${1}\"" - usage;; + enable_debug + ;; + -*) + error_notify "[ERROR]: Unknown Option: \"${1}\"" + usage + ;; esac done @@ -147,6 +161,10 @@ else AUTO=1 shift ;; + -l|--live) + LIVE="1" + shift + ;; --gz) GZIP_EXPORT="1" opt_count @@ -157,6 +175,16 @@ else opt_count shift ;; + --zst) + ZST_EXPORT="1" + opt_count + shift + ;; + -r|--raw) + RAW_EXPORT="1" + opt_count + shift + ;; --tgz) TGZ_EXPORT="1" opt_count @@ -169,13 +197,10 @@ else zfs_enable_check shift ;; - -s|--safe) - SAFE_EXPORT="1" - shift - ;; - -r|--raw) - RAW_EXPORT="1" + --tzst) + TZST_EXPORT="1" opt_count + zfs_enable_check shift ;; -v|--verbose) @@ -183,13 +208,14 @@ else shift ;; -x) - enable_debug - shift - ;; + enable_debug + shift + ;; -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; + l) LIVE=1 ;; x) enable_debug ;; *) error_exit "[ERROR]: Unknown Option: \"${1}\"" esac @@ -203,12 +229,11 @@ else done fi -if [ $# -gt 2 ] || [ $# -lt 1 ]; then +if [ $# -lt 1 ] || [ $# -gt 2 ]; then usage fi TARGET="${1}" - # Check for directory export if echo "${2}" | grep -q "\/"; then DIR_EXPORT="${2}" @@ -217,39 +242,30 @@ fi bastille_root_check set_target_single "${TARGET}" -# Validate for combined options +# Only allow a single compression option if [ "${COMP_OPTION}" -gt "1" ]; then error_exit "[ERROR]: Only one compression format can be used during export." fi -if { [ -n "${TXZ_EXPORT}" ] || [ -n "${TGZ_EXPORT}" ]; } && [ -n "${SAFE_EXPORT}" ]; then - error_exit "[ERROR]: Simple archive modes with safe ZFS export can't be used together." +# Validate AUTO and LIVE +if [ "${AUTO}" -eq 1 ] && [ "${LIVE}" -eq 1 ]; then + error_exit "[ERROR]: [-a|--auto] cannot be used with [-l|--live]." fi +# Don't allow LIVE with T*_EXPORT +if { [ "${TXZ_EXPORT}" -eq 1 ] || [ "${TGZ_EXPORT}" -eq 1 ] || [ "${TZST_EXPORT}" -eq 1 ]; } && [ "${LIVE}" -eq 1 ]; then + error_exit "[ERROR]: [-l|--live] cannot be used with simple archive modes." +fi + +# Don't allow ZFS specific options if not enabled if ! checkyesno bastille_zfs_enable; then - if [ -n "${XZ_EXPORT}" ] || - [ -n "${GZIP_EXPORT}" ] || - [ -n "${RAW_EXPORT}" ] || - [ -n "${SAFE_EXPORT}" ] || + if [ "${XZ_EXPORT}" -eq 1 ] || + [ "${GZIP_EXPORT}" -eq 1 ] || + [ "${RAW_EXPORT}" -eq 1 ] || + [ "${LIVE}" -eq 1 ] || + [ "${ZST_EXPORT}" -eq 1 ] || [ "${OPT_ZSEND}" = "-Rv" ]; then - error_exit "[ERROR]: Options --xz, --gz, --raw, --safe, and --verbose are valid for ZFS configured systems only." - fi -fi - -if [ -n "${SAFE_EXPORT}" ]; then - # Check if container is running, otherwise just ignore - if [ -z "$(/usr/sbin/jls name | awk "/^${TARGET}$/")" ]; then - SAFE_EXPORT= - fi -fi - -# Export directory check -if [ -n "${DIR_EXPORT}" ]; then - if [ -d "${DIR_EXPORT}" ]; then - # Set the user defined export directory - bastille_backupsdir="${DIR_EXPORT}" - else - error_exit "[ERROR]: Path not found." + error_exit "[ERROR]: Options --xz, --gz, --raw, -l|--live, --zst and --verbose are only valid for ZFS configured systems." fi fi @@ -260,10 +276,50 @@ fi if [ -z "${bastille_compress_gz_options}" ]; then bastille_compress_gz_options="-1 -v" fi +if [ -z "${bastille_compress_zst_options}" ]; then + bastille_compress_zst_options="-3 -v" +fi + +# Export directory check +if [ -n "${DIR_EXPORT}" ]; then + if [ -d "${DIR_EXPORT}" ]; then + # Set the user defined export directory + bastille_backupsdir="${DIR_EXPORT}" + else + error_exit "[ERROR]: Path not found." + fi +elif [ ! -d "${bastille_backupsdir}" ]; then + error_exit "[ERROR]: Backups directory/dataset does not exist. See 'bastille bootstrap'." +fi + +# Validate jail state +if checkyesno bastille_zfs_enable; then + if [ "${LIVE}" -eq 1 ]; then + if ! check_target_is_running "${TARGET}"; then + error_exit "[ERROR]: [-l|--live] can only be used with a running jail." + fi + elif check_target_is_running "${TARGET}"; then + if [ "${AUTO}" -eq 1 ]; then + bastille stop "${TARGET}" + else + info "\n[${TARGET}]:" + error_notify "[ERROR]: Jail is running." + error_exit "Use [-a|--auto] to auto-stop the jail, or [-l|--live] (ZFS only) to migrate a running jail." + fi + fi +else + check_target_is_stopped "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then + bastille stop "${TARGET}" + else + info "\n[${TARGET}]:" + error_notify "Jail is running." + error_exit "Use [-a|--auto] to auto-stop the jail." + fi +fi create_zfs_snap() { # Take a recursive temporary snapshot - if [ -z "${USER_EXPORT}" ]; then + if [ "${USER_EXPORT}" -eq 0 ]; then info "\nCreating temporary ZFS snapshot for export..." fi zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_${TARGET}_${DATE}" @@ -275,20 +331,21 @@ clean_zfs_snap() { zfs destroy "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_${TARGET}_${DATE}" } -export_check() { +export_check() { + # Inform the user about the exporting method - if [ -z "${USER_EXPORT}" ]; then - if [ -n "$(/usr/sbin/jls name | awk "/^${TARGET}$/")" ]; then - if [ -n "${SAFE_EXPORT}" ]; then - EXPORT_AS="Safely exporting" - else + if [ "${USER_EXPORT}" -eq 0 ]; then + if check_target_is_running "${TARGET}" 2>/dev/null; then + if [ "${LIVE}" -eq 1 ]; then EXPORT_AS="Hot exporting" + else + EXPORT_AS="Safely exporting" fi else EXPORT_AS="Exporting" fi - if [ "${FILE_EXT}" = ".xz" ] || [ "${FILE_EXT}" = ".gz" ] || [ "${FILE_EXT}" = "" ]; then + if [ "${FILE_EXT}" = ".xz" ] || [ "${FILE_EXT}" = ".gz" ] || [ "${FILE_EXT}" = ".zst" ] || [ "${FILE_EXT}" = "" ]; then EXPORT_TYPE="image" else EXPORT_TYPE="archive" @@ -303,19 +360,15 @@ export_check() { info "\n${EXPORT_AS} '${TARGET}' ${EXPORT_INFO}..." fi - # Safely stop and snapshot the jail - if [ -n "${SAFE_EXPORT}" ]; then - bastille stop ${TARGET} - create_zfs_snap - bastille start ${TARGET} - else - create_zfs_snap - fi - if checkyesno bastille_zfs_enable; then - if [ -z "${USER_EXPORT}" ]; then + + # Create snapshot + create_zfs_snap + + if [ "${USER_EXPORT}" -eq 0 ]; then info "\nSending ZFS data stream..." fi + fi } @@ -331,7 +384,8 @@ jail_export() { if [ "$(zfs get -H -o value encryption ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET})" = "on" ]; then error_exit "[ERROR]: Exporting jails in encryoted datasets is not supported." fi - if [ -n "${RAW_EXPORT}" ]; then + + if [ "${RAW_EXPORT}" -eq 1 ]; then FILE_EXT="" @@ -345,7 +399,7 @@ jail_export() { clean_zfs_snap fi - elif [ -n "${GZIP_EXPORT}" ]; then + elif [ "${GZIP_EXPORT}" -eq 1 ]; then FILE_EXT=".gz" @@ -359,7 +413,7 @@ jail_export() { clean_zfs_snap fi - elif [ -n "${XZ_EXPORT}" ]; then + elif [ "${XZ_EXPORT}" -eq 1 ]; then FILE_EXT=".xz" @@ -373,6 +427,20 @@ jail_export() { clean_zfs_snap fi + elif [ "${ZST_EXPORT}" -eq 1 ]; then + + FILE_EXT=".zst" + + export_check + + # Export the container recursively and cleanup temporary snapshots + if ! zfs send ${OPT_ZSEND} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET}@bastille_${TARGET}_${DATE}" | zstd ${bastille_compress_zst_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}"; then + clean_zfs_snap + error_exit "[ERROR]: Failed to export jail: ${TARGET}" + else + clean_zfs_snap + fi + else FILE_EXT="" @@ -390,7 +458,7 @@ jail_export() { fi fi else - if [ -n "${TGZ_EXPORT}" ]; then + if [ "${TGZ_EXPORT}" -eq 1 ]; then FILE_EXT=".tgz" @@ -402,7 +470,7 @@ jail_export() { error_exit "[ERROR]: Failed to export jail: ${TARGET}" fi - elif [ -n "${TXZ_EXPORT}" ]; then + elif [ "${TXZ_EXPORT}" -eq 1 ]; then FILE_EXT=".txz" @@ -414,6 +482,18 @@ jail_export() { error_exit "[ERROR]: Failed to export jail: ${TARGET}" fi + elif [ "${TZST_EXPORT}" -eq 1 ]; then + + FILE_EXT=".tzst" + + # Create standard txz backup archive + info "\nExporting '${TARGET}' to a compressed ${FILE_EXT} archive..." + + cd "${bastille_jailsdir}" || error_exit "[ERROR]: Failed to change to directory: ${bastille_jailssdir}" + if ! tar -cf - "${TARGET}" | zstd ${bastille_compress_zst_options} > "${bastille_backupsdir}/${TARGET}_${DATE}${FILE_EXT}"; then + error_exit "[ERROR]: Failed to export jail: ${TARGET}" + fi + else error_exit "[ERROR]: export option required" fi @@ -423,7 +503,7 @@ jail_export() { if [ "$?" -ne 0 ]; then error_exit "[ERROR]: Failed to export jail: ${TARGET}" else - if [ -z "${USER_EXPORT}" ]; then + if [ "${USER_EXPORT}" -eq 0 ]; then # Generate container checksum file cd "${bastille_backupsdir}" || error_exit "[ERROR]: Failed to change to directory: ${bastille_backupsdir}" if ! sha256 -q "${TARGET}_${DATE}${FILE_EXT}" > "${TARGET}_${DATE}.sha256"; then @@ -435,29 +515,4 @@ jail_export() { fi } -# Check if backups directory/dataset exist -if [ ! -d "${bastille_backupsdir}" ]; then - error_exit "[ERROR]: Backups directory/dataset does not exist. See 'bastille bootstrap'." -fi - -if [ -n "${TARGET}" ]; then - - # Validate jail existence - if [ ! -d "${bastille_jailsdir}/${TARGET}" ]; then - error_exit "[ERROR]: Jail not found: ${TARGET}" - fi - - # Jail needs to be stopped on non-ZFS systems - if ! checkyesno bastille_zfs_enable; then - # Validate jail state - check_target_is_stopped "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then - bastille stop "${TARGET}" - else - info "\n[${TARGET}]:" - error_notify "Jail is running." - error_exit "Use [-a|--auto] to auto-stop the jail." - fi - fi - - jail_export -fi +jail_export diff --git a/usr/local/share/bastille/import.sh b/usr/local/share/bastille/import.sh index ce6d795f..95ff5d76 100644 --- a/usr/local/share/bastille/import.sh +++ b/usr/local/share/bastille/import.sh @@ -37,15 +37,15 @@ usage() { # If no file/extension specified, will import from standard input error_notify "Usage: bastille import [option(s)] FILE [RELEASE]" cat << EOF - + Options: - -f | --force Force an archive import regardless if the checksum file does not match or missing. - -M | --static-mac Generate static MAC for jail when importing foreign jails like iocage. - -v | --verbose Be more verbose during the ZFS receive operation. - -x | --debug Enable debug mode. + -f | --force Force an archive import regardless if the checksum file does not match or missing. + -M | --static-mac Generate static MAC for jail when importing foreign jails like iocage. + -v | --verbose Enable verbose mode (ZFS only). + -x | --debug Enable debug mode. -Tip: If no option specified, container should be imported from standard input. + Tip: If no option specified, container should be imported from standard input. EOF exit 1 @@ -58,9 +58,9 @@ OPT_STATIC_MAC="" USER_IMPORT= while [ "$#" -gt 0 ]; do case "${1}" in - -h|--help|help) + -h|--help|help) usage - ;; + ;; -f|--force) OPT_FORCE="1" shift @@ -77,14 +77,14 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in f) OPT_FORCE=1 ;; - M) OPT_STATIC_MAC=1 ;; + M) OPT_STATIC_MAC=1 ;; v) OPT_ZRECV="-u -v" ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -111,8 +111,12 @@ fi if [ -z "${bastille_decompress_gz_options}" ]; then bastille_decompress_gz_options="-k -d -c -v" fi +if [ -z "${bastille_decompress_zst_options}" ]; then + bastille_decompress_zst_options="-k -d -c -v" +fi validate_archive() { + # Compare checksums on the target archive # Skip validation for unsupported archive if [ -f "${bastille_backupsdir}/${TARGET}" ]; then @@ -137,7 +141,7 @@ validate_archive() { } update_zfsmount() { - + # Update the mountpoint property on the received ZFS data stream OLD_ZFS_MOUNTPOINT=$(zfs get -H mountpoint "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}/root" | awk '{print $3}') NEW_ZFS_MOUNTPOINT="${bastille_jailsdir}/${TARGET_TRIM}/root" @@ -232,7 +236,7 @@ generate_config() { IPVX_CONFIG=$(grep -wo "jail_${TARGET_TRIM}_ip=.*" ${PROP_CONFIG} | tr -d '" ' | sed "s/jail_${TARGET_TRIM}_ip=//") if [ -z "${RELEASE}" ]; then CONFIG_RELEASE=$(echo ${PROP_CONFIG} | grep -o '[0-9]\{2\}\.[0-9]_RELEASE' | sed 's/_/-/g') - else + else CONFIG_RELEASE="${RELEASE}" fi fi @@ -438,6 +442,7 @@ update_config() { } workout_components() { + if [ "${FILE_EXT}" = ".tar" ]; then # Workaround to determine the tarball path/components before extract(assumes path/jails/target) JAIL_PATH=$(tar -tvf ${bastille_backupsdir}/${TARGET} | grep -wo "/.*/jails/${TARGET_TRIM}" | tail -n1) @@ -451,6 +456,7 @@ workout_components() { } vnet_requirements() { + # VNET jib script requirement if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then if [ ! "$(command -v jib)" ]; then @@ -472,6 +478,7 @@ vnet_requirements() { } config_netif() { + # Get interface from bastille configuration if [ -n "${bastille_network_loopback}" ]; then NETIF_CONFIG="${bastille_network_loopback}" @@ -509,8 +516,9 @@ update_symlinks() { } create_zfs_datasets() { + # Prepare the ZFS environment and restore from file - info "\nImporting '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive." + info "\nImporting '${TARGET_TRIM}' from compressed ${FILE_EXT} archive." echo "Preparing ZFS environment..." # Create required ZFS datasets, mountpoint inherited from system @@ -526,12 +534,14 @@ remove_zfs_datasets() { } jail_import() { + # Attempt to import container from file - FILE_TRIM=$(echo "${TARGET}" | sed 's/\.xz//g;s/\.gz//g;s/\.tgz//g;s/\.txz//g;s/\.zip//g;s/\.tar\.gz//g;s/\.tar//g') + FILE_TRIM=$(echo "${TARGET}" | sed 's/\.xz//g;s/\.gz//g;s/\.zst//g;s/\.tgz//g;s/\.txz//g;s/\.tzst//g;s/\.zip//g;s/\.tar\.gz//g;s/\.tar//g') FILE_EXT=$(echo "${TARGET}" | sed "s/${FILE_TRIM}//g") if [ -d "${bastille_jailsdir}" ]; then if checkyesno bastille_zfs_enable; then if [ -n "${bastille_zfs_zpool}" ]; then + if [ "${FILE_EXT}" = ".xz" ]; then validate_archive # Import from compressed xz on ZFS systems @@ -539,9 +549,9 @@ jail_import() { echo "Receiving ZFS data stream..." xz ${bastille_decompress_xz_options} "${bastille_backupsdir}/${TARGET}" | \ zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" - # Update ZFS mountpoint property if required update_zfsmount + elif [ "${FILE_EXT}" = ".gz" ]; then validate_archive # Import from compressed xz on ZFS systems @@ -549,7 +559,16 @@ jail_import() { echo "Receiving ZFS data stream..." gzip ${bastille_decompress_gz_options} "${bastille_backupsdir}/${TARGET}" | \ zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" + # Update ZFS mountpoint property if required + update_zfsmount + elif [ "${FILE_EXT}" = ".zst" ]; then + validate_archive + # Import from compressed zst on ZFS systems + info "\nImporting '${TARGET_TRIM}' from compressed ${FILE_EXT} image." + echo "Receiving ZFS data stream..." + zstd ${bastille_decompress_zst_options} "${bastille_backupsdir}/${TARGET}" | \ + zfs receive ${OPT_ZRECV} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${TARGET_TRIM}" # Update ZFS mountpoint property if required update_zfsmount @@ -557,7 +576,6 @@ jail_import() { validate_archive # Prepare the ZFS environment and restore from existing .txz file create_zfs_datasets - # Extract required files to the new datasets info "\nExtracting files from '${TARGET}' archive..." tar --exclude='root' -Jxf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}" @@ -565,11 +583,11 @@ jail_import() { if [ "$?" -ne 0 ]; then remove_zfs_datasets fi + elif [ "${FILE_EXT}" = ".tgz" ]; then validate_archive # Prepare the ZFS environment and restore from existing .tgz file create_zfs_datasets - # Extract required files to the new datasets info "\nExtracting files from '${TARGET}' archive..." tar --exclude='root' -xf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}" @@ -577,7 +595,21 @@ jail_import() { if [ "$?" -ne 0 ]; then remove_zfs_datasets fi + + elif [ "${FILE_EXT}" = ".tzst" ]; then + validate_archive + # Prepare the ZFS environment and restore from existing .tgz file + create_zfs_datasets + # Extract required files to the new datasets + info "\nExtracting files from '${TARGET}' archive..." + tar --exclude='root' -xf "${bastille_backupsdir}/${TARGET}" --strip-components 1 -C "${bastille_jailsdir}/${TARGET_TRIM}" + tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components 2 -C "${bastille_jailsdir}/${TARGET_TRIM}/root" "${TARGET_TRIM}/root" + if [ "$?" -ne 0 ]; then + remove_zfs_datasets + fi + elif [ "${FILE_EXT}" = ".zip" ]; then + validate_archive # Attempt to import a foreign/iocage container info "\nImporting '${TARGET_TRIM}' from foreign compressed ${FILE_EXT} archive." @@ -608,7 +640,9 @@ jail_import() { # Generate fstab and jail.conf files generate_config + elif [ "${FILE_EXT}" = ".tar.gz" ]; then + # Attempt to import a foreign/ezjail container # Prepare the ZFS environment and restore from existing .tar.gz file create_zfs_datasets @@ -622,12 +656,13 @@ jail_import() { else generate_config fi + elif [ "${FILE_EXT}" = ".tar" ]; then + # Attempt to import a foreign/qjail container # Prepare the ZFS environment and restore from existing .tar file create_zfs_datasets workout_components - # Extract required files to the new datasets info "\nExtracting files from '${TARGET}' archive..." tar -xf "${bastille_backupsdir}/${TARGET}" --strip-components "${CONF_TRIM}" -C "${bastille_jailsdir}/${TARGET_TRIM}" "${JAIL_CONF}" @@ -641,7 +676,9 @@ jail_import() { else update_config fi + elif [ -z "${FILE_EXT}" ]; then + if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$'; then validate_archive # Based on the file name, looks like we are importing a raw bastille image @@ -669,19 +706,31 @@ jail_import() { else # Import from standard supported archives on UFS systems if [ "${FILE_EXT}" = ".txz" ]; then + info "\nExtracting files from '${TARGET}' archive..." - tar -Jxf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" + tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" + elif [ "${FILE_EXT}" = ".tgz" ]; then + info "\nExtracting files from '${TARGET}' archive..." - tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" + tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" + + elif [ "${FILE_EXT}" = ".tzst" ]; then + + info "\nExtracting files from '${TARGET}' archive..." + tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}" + elif [ "${FILE_EXT}" = ".tar.gz" ]; then + # Attempt to import/configure foreign/ezjail container info "\nExtracting files from '${TARGET}' archive..." mkdir "${bastille_jailsdir}/${TARGET_TRIM}" tar -xf "${bastille_backupsdir}/${TARGET}" -C "${bastille_jailsdir}/${TARGET_TRIM}" mv "${bastille_jailsdir}/${TARGET_TRIM}/ezjail" "${bastille_jailsdir}/${TARGET_TRIM}/root" generate_config + elif [ "${FILE_EXT}" = ".tar" ]; then + # Attempt to import/configure foreign/qjail container info "\nExtracting files from '${TARGET}' archive..." mkdir -p "${bastille_jailsdir}/${TARGET_TRIM}/root" @@ -729,9 +778,9 @@ fi # Check if archive exist then trim archive name if [ -f "${bastille_backupsdir}/${TARGET}" ]; then # Filter unsupported/unknown archives - if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.xz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.gz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.tgz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.txz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}.zip$\|-[0-9]\{12\}.[0-9]\{2\}.tar.gz$\|@[0-9]\{12\}.[0-9]\{2\}.tar$'; then + if echo "${TARGET}" | grep -q '_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.xz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.gz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.zst$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.tgz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.txz$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.tzst$\|_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}.zip$\|-[0-9]\{12\}.[0-9]\{2\}.tar.gz$\|@[0-9]\{12\}.[0-9]\{2\}.tar$'; then if ls "${bastille_backupsdir}" | awk "/^${TARGET}$/" >/dev/null; then - TARGET_TRIM=$(echo "${TARGET}" | sed "s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.xz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.gz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.tgz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.txz//;s/_[0-9]*-[0-9]*-[0-9]*.zip//;s/-[0-9]\{12\}.[0-9]\{2\}.tar.gz//;s/@[0-9]\{12\}.[0-9]\{2\}.tar//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*//") + TARGET_TRIM=$(echo "${TARGET}" | sed "s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.xz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.gz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.zst//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.tgz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.txz//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*.tzst//;s/_[0-9]*-[0-9]*-[0-9]*.zip//;s/-[0-9]\{12\}.[0-9]\{2\}.tar.gz//;s/@[0-9]\{12\}.[0-9]\{2\}.tar//;s/_[0-9]*-[0-9]*-[0-9]*-[0-9]*//") fi else error_exit "[ERROR]: Unrecognized archive name." @@ -754,4 +803,4 @@ fi if [ -n "${TARGET}" ]; then info "\nAttempting to import jail: ${TARGET_TRIM}..." jail_import -fi +fi \ No newline at end of file diff --git a/usr/local/share/bastille/jcp.sh b/usr/local/share/bastille/jcp.sh index 0e2c736a..fb7a2370 100644 --- a/usr/local/share/bastille/jcp.sh +++ b/usr/local/share/bastille/jcp.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille jcp [option(s)] SOURCE_JAIL JAIL_PATH DEST_JAIL JAIL_PATH" cat << EOF - + Options: -q | --quiet Suppress output. @@ -65,7 +65,7 @@ while [ "$#" -gt 0 ]; do case ${_opt} in q) OPTION="-a" ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -84,6 +84,7 @@ SOURCE_TARGET="${1}" SOURCE_PATH="${2}" DEST_TARGET="${3}" DEST_PATH="${4}" +ERRORS=0 bastille_root_check set_target_single "${SOURCE_TARGET}" && SOURCE_TARGET="${TARGET}" @@ -91,8 +92,6 @@ set_target "${DEST_TARGET}" && DEST_TARGET="${JAILS}" for _jail in ${DEST_TARGET}; do - ( - if [ "${_jail}" = "${SOURCE_TARGET}" ]; then continue else @@ -101,16 +100,16 @@ for _jail in ${DEST_TARGET}; do source_path="$(echo ${bastille_jailsdir}/${SOURCE_TARGET}/root/${SOURCE_PATH} | sed 's#//#/#g')" dest_path="$(echo ${bastille_jailsdir}/${_jail}/root/${DEST_PATH} | sed 's#//#/#g')" - + if ! cp "${OPTION}" "${source_path}" "${dest_path}"; then + ERRORS=$((ERRORS + 1)) error_continue "[ERROR]: JCP failed: ${source_path} -> ${dest_path}" fi - + fi - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait \ No newline at end of file + +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi \ No newline at end of file diff --git a/usr/local/share/bastille/limits.sh b/usr/local/share/bastille/limits.sh index 472f3ef6..9d2e7121 100644 --- a/usr/local/share/bastille/limits.sh +++ b/usr/local/share/bastille/limits.sh @@ -36,10 +36,10 @@ usage() { error_notify "Usage: bastille limits [option(s)] TARGET [add|remove|clear|reset|(list|show [active])|stats] OPTION [VALUE]" cat << EOF - + Example: bastille limits TARGET add memoryuse 1G Example: bastille limits TARGET add cpu 0,1,2 - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. @@ -70,13 +70,13 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; l) OPT_LOG=1 ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -93,7 +93,7 @@ fi TARGET="${1}" ACTION="${2}" -# Retain support for no action (will default to add) +# Retain support for no action (will default to add) if [ "${ACTION}" != "add" ] && [ "${ACTION}" != "remove" ] && [ "${ACTION}" != "clear" ] && [ "${ACTION}" != "list" ] && [ "${ACTION}" != "show" ] && [ "${ACTION}" != "reset" ] && [ "${ACTION}" != "stats" ]; then ACTION="add" shift 1 @@ -139,8 +139,6 @@ add_cpuset() { for _jail in ${JAILS}; do - ( - check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then bastille start "${_jail}" else @@ -150,7 +148,7 @@ for _jail in ${JAILS}; do fi info "\n[${_jail}]:" - + case "${ACTION}" in add) @@ -302,9 +300,4 @@ for _jail in ${JAILS}; do esac - ) & - - bastille_running_jobs "${bastille_process_limit}" - -done -wait +done \ No newline at end of file diff --git a/usr/local/share/bastille/list.sh b/usr/local/share/bastille/list.sh index d02d78f5..c9024df6 100644 --- a/usr/local/share/bastille/list.sh +++ b/usr/local/share/bastille/list.sh @@ -71,7 +71,7 @@ get_jail_list() { if [ -n "${TARGET}" ]; then JAIL_LIST="${TARGET}" else - JAIL_LIST="$(ls --color=never "${bastille_jailsdir}" | sed "s/\n//g")" + JAIL_LIST="$(ls -v --color=never "${bastille_jailsdir}" | sed "s/\n//g")" fi } @@ -100,14 +100,17 @@ get_max_lengths() { # Set max length for VNET jail IPs # shellcheck disable=SC2046 - MAX_LENGTH_JAIL_VNET_IP6="$(find ${bastille_jailsdir}/*/jail.conf -maxdepth 1 -type f -print0 2> /dev/null | xargs -r0 -P0 grep -l "vnet;" | grep -Eho '\b(([0-9a-fA-F]{1,4}:){1,7}|:):([0-9a-fA-F]{1,4}:?){0,6}[0-9a-fA-F]{1,4}\b' $(sed -n "s/\(.*\)jail.conf$/\1root\/etc\/rc.conf/p") | awk '{print length}' | sort -nr | head -n 1)" + MAX_LENGTH_JAIL_VNET_IP6="$(find ${bastille_jailsdir}/*/jail.conf -maxdepth 1 -type f -print0 2> /dev/null | xargs -r0 -P0 grep -l "vnet;" | grep -h "ifconfig_vnet.*=.*inet6" $(sed -n "s/\(.*\)jail.conf$/\1root\/etc\/rc.conf/p") | grep -Eho "(::)?[0-9a-fA-F]{1,4}(::?[0-9a-fA-F]{1,4}){1,7}(::)?" | sed "s/\// /g" | awk '{print length}' | sort -nr | head -n 1)" MAX_LENGTH_JAIL_VNET_IP6=${MAX_LENGTH_JAIL_VNET_IP6:-10} # shellcheck disable=SC2046 - MAX_LENGTH_JAIL_VNET_IP="$(find ${bastille_jailsdir}/*/jail.conf -maxdepth 1 -type f -print0 2> /dev/null | xargs -r0 -P0 grep -l "vnet;" | grep -h "ifconfig_vnet.*=" $(sed -n "s/\(.*\)jail.conf$/\1root\/etc\/rc.conf/p") | sed -n "s/^ifconfig_vnet.*=\"\(.*\)\"$/\1/p"| sed "s/\// /g" | awk '{ if ($1 == "inet ") print length($2); else if ($1 == "inet6") print length($3); else print 15 }' | sort -nr | head -n 1)" + MAX_LENGTH_JAIL_VNET_IP="$(find ${bastille_jailsdir}/*/jail.conf -maxdepth 1 -type f -print0 2> /dev/null | xargs -r0 -P0 grep -l "vnet;" | grep -h "ifconfig_vnet.*=.*inet " $(sed -n "s/\(.*\)jail.conf$/\1root\/etc\/rc.conf/p") | grep -o "inet .*" | sed -e 's/"//' -e 's#/.*##g' | awk '{print length($2)}' | sort -nr | head -n 1)" MAX_LENGTH_JAIL_VNET_IP=${MAX_LENGTH_JAIL_VNET_IP:-10} - if [ "${MAX_LENGTH_JAIL_VNET_IP}" -gt "${MAX_LENGTH_JAIL_VNET_IP6}" ] && [ "${MAX_LENGTH_JAIL_VNET_IP}" -gt "${MAX_LENGTH_JAIL_IP}" ]; then MAX_LENGTH_JAIL_IP=${MAX_LENGTH_JAIL_VNET_IP}; fi - if [ "${MAX_LENGTH_JAIL_VNET_IP6}" -gt "${MAX_LENGTH_JAIL_VNET_IP}" ] && [ "${MAX_LENGTH_JAIL_VNET_IP6}" -gt "${MAX_LENGTH_JAIL_IP}" ]; then MAX_LENGTH_JAIL_IP=${MAX_LENGTH_JAIL_VNET_IP6}; fi - + # shellcheck disable=SC2046 + MAX_LENGTH_JAIL_VNET_IP_DHCP="$(find ${bastille_jailsdir}/*/root/etc/rc.conf -maxdepth 1 -type f -print0 2> /dev/null | xargs -r0 grep -lE "ifconfig_vnet.*DHCP.*" | sed -E 's|.*/([^/]+)/root/etc/rc.conf|\1|' | xargs -r -P0 -I{} jexec -l {} ifconfig -an 2>&1 | grep "^[[:space:]]*inet " | grep -v "127.0.0.1" | awk '{print $2}' | sed "s/\// /g" | awk '{print length}' | sort -nr | head -n 1)" + MAX_LENGTH_JAIL_VNET_IP_DHCP=${MAX_LENGTH_JAIL_VNET_IP_DHCP:-10} + if [ "${MAX_LENGTH_JAIL_VNET_IP_DHCP}" -gt "${MAX_LENGTH_JAIL_IP}" ] && [ "${MAX_LENGTH_JAIL_VNET_IP_DHCP}" -gt "${MAX_LENGTH_JAIL_VNET_IP}" ] && [ "${MAX_LENGTH_JAIL_VNET_IP_DHCP}" -gt "${MAX_LENGTH_JAIL_VNET_IP6}" ]; then MAX_LENGTH_JAIL_IP=${MAX_LENGTH_JAIL_VNET_IP_DHCP} + elif [ "${MAX_LENGTH_JAIL_VNET_IP}" -gt "${MAX_LENGTH_JAIL_IP}" ] && [ "${MAX_LENGTH_JAIL_VNET_IP}" -gt "${MAX_LENGTH_JAIL_VNET_IP_DHCP}" ] && [ "${MAX_LENGTH_JAIL_VNET_IP}" -gt "${MAX_LENGTH_JAIL_VNET_IP6}" ]; then MAX_LENGTH_JAIL_IP=${MAX_LENGTH_JAIL_VNET_IP} + elif [ "${MAX_LENGTH_JAIL_VNET_IP6}" -gt "${MAX_LENGTH_JAIL_IP}" ] && [ "${MAX_LENGTH_JAIL_VNET_IP6}" -gt "${MAX_LENGTH_JAIL_VNET_IP}" ] && [ "${MAX_LENGTH_JAIL_VNET_IP6}" -gt "${MAX_LENGTH_JAIL_VNET_IP_DHCP}" ]; then MAX_LENGTH_JAIL_IP=${MAX_LENGTH_JAIL_VNET_IP6}; fi if [ "${MAX_LENGTH_JAIL_IP}" -lt 10 ]; then MAX_LENGTH_JAIL_IP=10; fi # Set max length for jail hostname @@ -156,17 +159,6 @@ get_jail_info() { # Get JID value JID="$(jls -j ${JAIL_NAME} jid 2>/dev/null)" - # Get jail type - if grep -qw "${bastille_jailsdir}/${JAIL_NAME}/root/.bastille" "${bastille_jailsdir}/${JAIL_NAME}/fstab"; then - JAIL_TYPE="thin" - elif [ "$(zfs get -H -o value origin ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${JAIL_NAME}/root)" != "-" ]; then - JAIL_TYPE="clone" - elif [ "$(grep -c "^linprocfs" "${bastille_jailsdir}/${JAIL_NAME}/fstab" 2> /dev/null)" -gt 0 ]; then - JAIL_TYPE="linux" - else - JAIL_TYPE="thick" - fi - # Get jail tags JAIL_TAGS="" if [ -f "${bastille_jailsdir}/${JAIL_NAME}/tags" ]; then @@ -182,9 +174,24 @@ get_jail_info() { if [ -f "${bastille_jailsdir}/${JAIL_NAME}/root/bin/freebsd-version" ] || [ -f "${bastille_jailsdir}/${JAIL_NAME}/root/.bastille/bin/freebsd-version" ] || [ "$(grep -c "/releases/.*/root/.bastille.*nullfs" "${bastille_jailsdir}/${JAIL_NAME}/fstab" 2> /dev/null)" -gt 0 ]; then IS_FREEBSD_JAIL=1; fi IS_FREEBSD_JAIL=${IS_FREEBSD_JAIL:-0} IS_LINUX_JAIL=0 - if [ "$(grep -c "^linprocfs" "${bastille_jailsdir}/${JAIL_NAME}/fstab" 2> /dev/null)" -gt 0 ]; then IS_LINUX_JAIL=1; fi + if [ "$(grep -c "^linprocfs.*${bastille_jailsdir}/${JAIL_NAME}/proc.*linprocfs" "${bastille_jailsdir}/${JAIL_NAME}/fstab" 2> /dev/null)" -gt 0 ]; then IS_LINUX_JAIL=1; fi IS_LINUX_JAIL=${IS_LINUX_JAIL:-0} + # Get jail type + if grep -qw "${bastille_jailsdir}/${JAIL_NAME}/root/.bastille" "${bastille_jailsdir}/${JAIL_NAME}/fstab"; then + JAIL_TYPE="thin" + elif [ "${IS_LINUX_JAIL}" -eq 1 ] && [ "${IS_FREEBSD_JAIL}" -eq 0 ]; then + JAIL_TYPE="linux" + elif checkyesno bastille_zfs_enable; then + if [ "$(zfs get -H -o value origin ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${JAIL_NAME}/root)" != "-" ]; then + JAIL_TYPE="clone" + else + JAIL_TYPE="thick" + fi + else + JAIL_TYPE="thick" + fi + # Gather variable that depend on jail being UP or DOWN if [ "$(/usr/sbin/jls name | awk "/^${JAIL_NAME}$/")" ]; then @@ -218,20 +225,19 @@ get_jail_info() { # Get release (FreeBSD or Linux) if [ "${IS_FREEBSD_JAIL}" -eq 1 ]; then JAIL_RELEASE=$(jexec -l ${JAIL_NAME} freebsd-version -u 2> /dev/null) - fi - if [ "${IS_LINUX_JAIL}" -eq 1 ]; then + elif [ "${IS_LINUX_JAIL}" -eq 1 ]; then JAIL_RELEASE=$(grep -hE "^NAME=.*$|^VERSION_ID=.*$|^VERSION_CODENAME=.*$" "${JAIL_PATH}/etc/os-release" 2> /dev/null | sed "s/\"//g" | sed "s/ GNU\/Linux//g" | awk -F'=' '{ a[$1] = $2; o++ } o%3 == 0 { print a["VERSION_CODENAME"] " (" a["NAME"] " " a["VERSION_ID"] ")" }') fi else # Set state to Down or n/a - JAIL_STATE=$(if [ "$(sed -n "/^${JAIL_NAME} {$/,/^}$/p" "${bastille_jailsdir}/${JAIL_NAME}/jail.conf" 2> /dev/null | awk '$0 ~ /^'${JAIL_NAME}' \{|\}/ { printf "%s",$0 }')" = "${JAIL_NAME} {}" ]; then echo "Down"; else echo "n/a"; fi) + JAIL_STATE=$(if [ "$(sed -n "/^${JAIL_NAME} {$/,/^}$/p" "${bastille_jailsdir}/${JAIL_NAME}/jail.conf" 2> /dev/null | awk '$0 ~ /^'"${JAIL_NAME}"' \{$/ || $0 ~ /^\}$/ { printf "%s", $0 }')" = "${JAIL_NAME} {}" ]; then echo "Down"; else echo "n/a"; fi) # Get info if jail is DOWN if [ "$(awk '$1 == "vnet;" { print $1 }' "${bastille_jailsdir}/${JAIL_NAME}/jail.conf" 2> /dev/null)" ]; then - JAIL_IP4=$(grep -E "^ifconfig_vnet.*inet.*" "${bastille_jailsdir}/${JAIL_NAME}/root/etc/rc.conf" 2> /dev/null | grep -o "inet .*" | awk '{print $2}' | sed -E 's#/[0-9]+.*##g' | sed 's/"//g') - JAIL_IP6=$(grep -E "^ifconfig_vnet.*inet6.*" "${bastille_jailsdir}/${JAIL_NAME}/root/etc/rc.conf" 2> /dev/null | grep -o "inet6.*" | awk '{print $3}' | sed -E 's#/[0-9]+.*##g' | sed 's/"//g') + JAIL_IP4=$(grep -E "^ifconfig_vnet.*inet .*" "${bastille_jailsdir}/${JAIL_NAME}/root/etc/rc.conf" 2> /dev/null | grep -o "inet .*" | awk '{print $2}' | sed -E 's#/[0-9]+.*##g' | sed 's/"//g') + JAIL_IP6=$(grep -E "^ifconfig_vnet.*inet6.*" "${bastille_jailsdir}/${JAIL_NAME}/root/etc/rc.conf" 2> /dev/null | grep -Eow "(::)?[0-9a-fA-F]{1,4}(::?[0-9a-fA-F]{1,4}){1,7}(::)?" | sed -E 's#/[0-9]+.*##g' | sed 's/"//g') else JAIL_IP4=$(sed -n "s/^[ ].*ip4.addr[ ].*=[ ]\(.*\);$/\1/p" "${bastille_jailsdir}/${JAIL_NAME}/jail.conf" 2> /dev/null | sed -e 's#/.*##g' -e 's#.*|##g') JAIL_IP6=$(sed -n "s/^[ ].*ip6.addr[ ].*=[ ]\(.*\);$/\1/p" "${bastille_jailsdir}/${JAIL_NAME}/jail.conf" 2> /dev/null | sed -e 's#/.*##g' -e 's#.*|##g') @@ -271,7 +277,7 @@ get_jail_info() { if [ "${OPT_STATE}" != "all" ] && [ "${JAIL_STATE}" != "${OPT_STATE}" ]; then # shellcheck disable=SC2104 continue - fi + fi # Add ... if JAIL_PORTS is too long JAIL_PORTS_FULL="${JAIL_PORTS}" @@ -296,7 +302,7 @@ get_jail_info() { list_bastille(){ _tmp_list= - + get_max_lengths get_jail_list @@ -313,13 +319,13 @@ list_bastille(){ fi ( - + get_jail_info "${_jail}" # Get JAIL_IP count JAIL_IP_COUNT=$(echo "${JAIL_IP}" | wc -l) - # Print JAIL_IP in columns if -gt 1 + # Print JAIL_IP in columns if -gt 1 if [ ${JAIL_IP_COUNT} -gt 1 ]; then # vnet0 has more than one IPs assigned. # Put each IP in its own line below the jails first address. For instance: @@ -576,19 +582,20 @@ list_type() { # TODO: Check the correct usage or arguments here. See SC2120. # shellcheck disable=SC2120 -list_release(){ +list_release() { + if [ -d "${bastille_releasesdir}" ]; then # TODO: Check if this can be changed to `find` as SC2012 suggests. # shellcheck disable=SC2012 - REL_LIST="$(ls "${bastille_releasesdir}" | sed "s/\n//g")" - for _REL in ${REL_LIST}; do - if [ -f "${bastille_releasesdir}/${_REL}/root/.profile" ] || [ -d "${bastille_releasesdir}/${_REL}/debootstrap" ]; then - if [ "${1}" = "-p" ] && [ -f "${bastille_releasesdir}/${_REL}/bin/freebsd-version" ]; then - REL_PATCH_LEVEL=$(sed -n "s/^USERLAND_VERSION=\"\(.*\)\"$/\1/p" "${bastille_releasesdir}/${_REL}/bin/freebsd-version" 2> /dev/null) - REL_PATCH_LEVEL=${REL_PATCH_LEVEL:-${_REL}} - echo "${REL_PATCH_LEVEL}" + release_list="$(ls -v --color=never "${bastille_releasesdir}" | sed "s/\n//g")" + for release in ${release_list}; do + if [ -f "${bastille_releasesdir}/${release}/root/.profile" ] || [ -d "${bastille_releasesdir}/${release}/debootstrap" ]; then + if [ "${1}" = "-p" ] && [ -f "${bastille_releasesdir}/${release}/bin/freebsd-version" ]; then + release_patch=$(sed -n "s/^USERLAND_VERSION=\"\(.*\)\"$/\1/p" "${bastille_releasesdir}/${release}/bin/freebsd-version" 2> /dev/null) + release_patch=${release_patch:-${release}} + echo "${release_patch}" else - echo "${_REL}" + echo "${release}" fi fi done @@ -599,7 +606,7 @@ list_snapshot(){ # TODO: Ability to list snapshot data for a single target. # List snapshots with its usage data for valid bastille jails only. if [ -d "${bastille_jailsdir}" ]; then - JAIL_LIST=$(ls --color=never "${bastille_jailsdir}" | sed "s/\n//g") + JAIL_LIST=$(ls -v --color=never "${bastille_jailsdir}" | sed "s/\n//g") for _JAIL in ${JAIL_LIST}; do if [ -f "${bastille_jailsdir}/${_JAIL}/jail.conf" ]; then info "\n[${_JAIL}]:" @@ -615,7 +622,7 @@ list_template(){ list_jail(){ if [ -d "${bastille_jailsdir}" ]; then - JAIL_LIST=$(ls --color=never "${bastille_jailsdir}" | sed "s/\n//g") + JAIL_LIST=$(ls -v --color=never "${bastille_jailsdir}" | sed "s/\n//g") for _JAIL in ${JAIL_LIST}; do if [ -f "${bastille_jailsdir}/${_JAIL}/jail.conf" ]; then echo "${_JAIL}" @@ -634,7 +641,7 @@ list_limit(){ list_import(){ # shellcheck disable=SC2010 - ls "${bastille_backupsdir}" | grep -v ".sha256$" + ls -v "${bastille_backupsdir}" | grep -v ".sha256$" } bastille_root_check diff --git a/usr/local/share/bastille/migrate.sh b/usr/local/share/bastille/migrate.sh index eacaa753..e324555c 100644 --- a/usr/local/share/bastille/migrate.sh +++ b/usr/local/share/bastille/migrate.sh @@ -40,16 +40,18 @@ usage() { bastille migrate attica migrate@192.168.10.100 bastille migrate attica migrate@192.168.1.10:20022 + bastille migrate --keyfile id_rsa attica migrate@192.168.1.10 Options: - -a | --auto Auto mode. Start/stop jail(s) if required. - -b | --backup Retain archives on remote system. - -d | --destroy Destroy local jail after migration. - | --doas Use 'doas' instead of 'sudo'. - -l | --live Migrate a running jail (ZFS only). - -p | --password Use password based authentication. - -x | --debug Enable debug mode. + -a | --auto Auto mode. Start/stop jail(s) if required. + -b | --backup Retain archives on remote system. + -d | --destroy Destroy local jail after migration. + | --doas Use 'doas' instead of 'sudo'. + -k | --keyfile Specify an alternative private keyfile name. Must be in '~/.ssh' + -l | --live Migrate a running jail (ZFS only). + -p | --password Use password based authentication. + -x | --debug Enable debug mode. EOF exit 1 @@ -60,6 +62,7 @@ AUTO=0 LIVE=0 OPT_BACKUP=0 OPT_DESTROY=0 +OPT_KEYFILE="" OPT_PASSWORD=0 OPT_SU="sudo" while [ "$#" -gt 0 ]; do @@ -83,6 +86,10 @@ while [ "$#" -gt 0 ]; do OPT_SU="doas" shift ;; + -k|--keyfile) + OPT_KEYFILE="${2}" + shift 2 + ;; -l|--live) LIVE=1 shift @@ -95,7 +102,7 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; @@ -104,7 +111,7 @@ while [ "$#" -gt 0 ]; do l) LIVE=1 ;; p) OPT_PASSWORD=1 ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -144,7 +151,7 @@ validate_host_status() { local _user="${1}" local _host="${2}" local _port="${3}" - + info "\nChecking remote host status..." # Host uptime @@ -333,13 +340,29 @@ fi if [ "${OPT_PASSWORD}" -eq 1 ]; then _opt_ssh_key= else + _migrate_user_home="$(getent passwd ${USER} | cut -d: -f6)" - _migrate_user_ssh_key="${_migrate_user_home}/.ssh/id_rsa" + + # Validate custom keyfile + if [ -n "${OPT_KEYFILE}" ]; then + if ! [ -f "${_migrate_user_home}/.ssh/${OPT_KEYFILE}" ]; then + error_exit "[ERROR]: Keyfile not found: ${_migrate_user_home}/.ssh/${OPT_KEYFILE}" + else + _migrate_user_ssh_key="${_migrate_user_home}/.ssh/${OPT_KEYFILE}" + fi + else + _migrate_user_ssh_key="find ${_migrate_user_home}/.ssh -maxdepth 1 -type f ! -name '*.pub' | grep -Eos 'id_.*'" + fi + _opt_ssh_key="-i ${_migrate_user_ssh_key}" # Exit if no keys found if [ -z "${_migrate_user_home}" ] || [ -z "${_migrate_user_ssh_key}" ]; then error_exit "[ERROR]: Could not find keys for user: ${USER}" + # Exit if multiple keys + elif [ "$(echo "${_migrate_user_ssh_key}" | wc -l)" -ne 1 ]; then + error_notify "[ERROR]: Multiple ssh keys found:\n${_migrate_user_ssh_key}" + error_exit "Please use -k|--keyfile to specify one." fi fi @@ -364,10 +387,9 @@ for _jail in ${JAILS}; do fi info "\nAttempting to migrate '${_jail}' to '${HOST}'..." - + migrate_jail "${_jail}" "${USER}" "${HOST}" "${PORT}" info "\nSuccessfully migrated '${_jail}' to '${HOST}'.\n" done -echo diff --git a/usr/local/share/bastille/mount.sh b/usr/local/share/bastille/mount.sh index 6b0d6d40..9870d08d 100644 --- a/usr/local/share/bastille/mount.sh +++ b/usr/local/share/bastille/mount.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille mount [option(s)] TARGET HOST_PATH JAIL_PATH [filesystem_type options dump pass_number]" cat << EOF - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. @@ -144,8 +144,6 @@ fi for _jail in ${JAILS}; do - ( - check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then bastille start "${_jail}" else @@ -196,16 +194,11 @@ for _jail in ${JAILS}; do continue fi fi - fi - + fi + # Add entry to fstab and mount echo "${_fstab_entry}" >> "${bastille_jailsdir}/${_jail}/fstab" || error_continue "Failed to create fstab entry: ${_fstab_entry}" mount -F "${bastille_jailsdir}/${_jail}/fstab" -a || error_continue "Failed to mount volume: ${_fullpath}" echo "Added: ${_fstab_entry}" - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait diff --git a/usr/local/share/bastille/network.sh b/usr/local/share/bastille/network.sh index ead1018f..0161e58c 100644 --- a/usr/local/share/bastille/network.sh +++ b/usr/local/share/bastille/network.sh @@ -34,20 +34,20 @@ . /usr/local/etc/bastille/bastille.conf usage() { - error_notify "Usage: bastille network [option(s)] TARGET [remove|add] INTERFACE [IP]" + error_notify "Usage: bastille network [option(s)] TARGET remove|add INTERFACE [IP]" cat << EOF - + Options: - -a | --auto Start/stop jail(s) if required. - -B | --bridge Add a bridge VNET interface. - -M | --static-mac Generate a static MAC address for the interface (VNET only). - -n | --no-ip Create interface without an IP (VNET only). - -P | --passthrough Add a raw interface. - -V | --vnet Add a VNET interface. - -v | --vlan VLANID Assign VLAN ID to interface (VNET only). - -x | --debug Enable debug mode. - + -a | --auto Start/stop jail(s) if required. + -B | --bridge Add a bridge VNET interface. + -M | --static-mac Generate a static MAC address for the interface (VNET only). + -n | --no-ip Create interface without an IP (VNET only). + -P | --passthrough Add a raw interface. + -V | --vnet Add a VNET interface. + -v | --vlan VLANID Assign VLAN ID to interface (VNET only). + -x | --debug Enable debug mode. + EOF exit 1 } @@ -101,7 +101,7 @@ while [ "$#" -gt 0 ]; do -x|--debug) enable_debug shift - ;; + ;; -*) for _o in $(echo ${1} 2>/dev/null | sed 's/-//g' | fold -w1); do case ${_o} in @@ -112,7 +112,7 @@ while [ "$#" -gt 0 ]; do P) PASSTHROUGH=1 ;; V) VNET=1 ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -126,6 +126,8 @@ done TARGET="${1}" ACTION="${2}" INTERFACE="${3}" + +# Validate options if [ "${ACTION}" = "add" ] && [ "${NO_IP}" -eq 0 ] && [ -n "${4}" ]; then IP="${4}" elif [ "${NO_IP}" -eq 1 ] && [ -n "${4}" ]; then @@ -135,7 +137,7 @@ else fi # Default is standard interface -if [ "${VNET}" -eq 0 ] && [ "${BRIDGE}" -eq 0 ] && [ "${PASSTHROUGH}" -eq 0 ]; then +if [ "${VNET}" -eq 0 ] && [ "${BRIDGE}" -eq 0 ] && [ "${PASSTHROUGH}" -eq 0 ]; then STANDARD=1 fi @@ -167,7 +169,7 @@ set_target_single "${TARGET}" check_target_is_stopped "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then bastille stop "${TARGET}" else - info "\n[${_jail}]:" + info "\n[${TARGET}]:" error_notify "Jail is running." error_exit "Use [-a|--auto] to auto-stop the jail." fi @@ -204,422 +206,433 @@ validate_ip() { validate_netif() { - local _interface="${1}" + local interface="${1}" - if ifconfig -l | grep -qwo ${_interface}; then - info "\nValid: (${_interface})." + if ifconfig -l | grep -qwo ${interface}; then + info "\nValid: (${interface})." else - error_exit "Invalid: (${_interface})." + error_exit "Invalid: (${interface})." + fi + + # Don't allow dots in INTERFACE if -V + if [ "${VNET}" -eq 1 ] && [ "${BRIDGE}" -eq 0 ]; then + if echo "${INTERFACE}" | grep -q "\."; then + error_exit "[ERROR]: [-V|--vnet] does not support dots (.) in interface names." + fi fi } check_interface_added() { - local _jailname="${1}" - local _if="${2}" - local _jail_config="${bastille_jailsdir}/${_jailname}/jail.conf" + local jailname="${1}" + local if="${2}" + local jail_config="${bastille_jailsdir}/${jailname}/jail.conf" - if grep -qo "${_if}" "${_jail_config}"; then + if grep -qo "${if}" "${jail_config}"; then return 0 - else + else return 1 fi } add_interface() { - local _jailname="${1}" - local _if="${2}" - local _ip="${3}" - local _jail_config="${bastille_jailsdir}/${_jailname}/jail.conf" - local _jail_rc_config="${bastille_jailsdir}/${_jailname}/root/etc/rc.conf" - local _jail_vnet_count="$(grep -Eo 'vnet[1-9]+' ${_jail_rc_config} | sort -u | wc -l)" - local _jail_vnet="vnet$((_jail_vnet_count + 1))" + local jailname="${1}" + local if="${2}" + local ip="${3}" + local jail_config="${bastille_jailsdir}/${jailname}/jail.conf" + local jail_rc_config="${bastille_jailsdir}/${jailname}/root/etc/rc.conf" + local jail_vnet_list="$(grep -Eo 'vnet[0-9]+' ${jail_rc_config})" + # Set vnetX number + local jail_vnet_num="0" + while echo "${jail_vnet_list}" | grep -Eosq "vnet${jail_vnet_num}"; do + jail_vnet_num=$((jail_vnet_num + 1)) + done + local jail_vnet="vnet${jail_vnet_num}" # Determine number of interfaces if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then - local _if_list="$(grep -Eo 'e[0-9]+a_[^;" ]+' ${_jail_config} | sort -u)" - local _epair_count="$(echo "${_if_list}" | grep -Eo "[0-9]+" | wc -l)" - local _epair_num_range=$((_epair_count + 1)) + local epair_list="$(grep -Eo 'e[0-9]+a_[^;" ]+' ${jail_config} | sort -u)" + local epair_suffix="$(grep -m 1 -Eo 'e[0-9]+a_[^;" ]+' ${jail_config} | awk -F"_" '{print $2}')" + local epair_num="0" + while echo "${epair_list}" | grep -Eosq "e${epair_num}a_"; do + epair_num=$((epair_num + 1)) + done + if [ "${jail_vnet_num}" -ne "${epair_num}" ]; then + error_exit "[ERROR]: Jail vnet+epair interface numbers do not match." + fi elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then - local _if_list="$(grep -Eo 'ng[0-9]+_[^;" ]+' ${_jail_config} | sort -u)" - local _ngif_count="$(echo "${_if_list}" | grep -Eo "[0-9]+" | wc -l)" - local _ngif_num_range=$((_ngif_count + 1)) + local ng_list="$(grep -Eo 'ng[0-9]+_[^;" ]+' ${jail_config} | sort -u)" + local ng_suffix="$(grep -m 1 -Eo 'ng[0-9]+_[^;" ]+' ${jail_config} | awk -F"_" '{print $2}')" + local ng_num="0" + while echo "${ng_list}" | grep -Eosq "ng${ng_num}_"; do + ng_num=$((ng_num + 1)) + done + if [ "${jail_vnet_num}" -ne "${ng_num}" ]; then + error_exit "[ERROR]: Jail vnet+netgraph interface numbers do not match." + fi fi + # BRIDGE interface if [ "${BRIDGE}" -eq 1 ]; then - for _epair_num in $(seq 0 ${_epair_num_range}); do - if ! grep -Eoqs "e${_epair_num}a_" "${_jail_config}"; then - if [ "$(echo -n "e${_epair_num}a_${_jailname}" | awk '{print length}')" -lt 16 ]; then - local host_epair=e${_epair_num}a_${_jailname} - local jail_epair=e${_epair_num}b_${_jailname} - else - name_prefix="$(echo ${_jailname} | cut -c1-7)" - name_suffix="$(echo ${_jailname} | rev | cut -c1-2 | rev)" - local host_epair="e${_epair_num}a_${name_prefix}xx${name_suffix}" - local jail_epair="e${_epair_num}b_${name_prefix}xx${name_suffix}" - fi - # Remove ending brace (it is added again with the netblock) - sed -i '' '/}/d' "${_jail_config}" - if [ "${STATIC_MAC}" -eq 1 ]; then - # Generate NETBLOCK with static MAC - generate_static_mac "${_jailname}" "${_if}" - cat << EOF >> "${_jail_config}" + + local host_epair=e${epair_num}a_${epair_suffix} + local jail_epair=e${epair_num}b_${epair_suffix} + + # Remove ending brace (it is added again with the netblock) + sed -i '' '/^}$/d' "${jail_config}" + + # Generate NETBLOCK with static MAC + if [ "${STATIC_MAC}" -eq 1 ]; then + generate_static_mac "${jailname}" "${if}" + cat << EOF >> "${jail_config}" ## ${host_epair} interface vnet.interface += ${jail_epair}; - exec.prestart += "epair${_epair_num}=\\\$(ifconfig epair create) && ifconfig \\\${epair${_epair_num}} up name ${host_epair} && ifconfig \\\${epair${_epair_num}%a}b up name ${jail_epair}"; - exec.prestart += "ifconfig ${_if} addm ${host_epair}"; + exec.prestart += "epair${epair_num}=\\\$(ifconfig epair create) && ifconfig \\\${epair${epair_num}} up name ${host_epair} && ifconfig \\\${epair${epair_num}%a}b up name ${jail_epair}"; + exec.prestart += "ifconfig ${if} addm ${host_epair}"; exec.prestart += "ifconfig ${host_epair} ether ${macaddr}a"; exec.prestart += "ifconfig ${jail_epair} ether ${macaddr}b"; - exec.prestart += "ifconfig ${host_epair} description \"${_jail_vnet} host interface for Bastille jail ${_jailname}\""; + exec.prestart += "ifconfig ${host_epair} description \"${jail_vnet} host interface for Bastille jail ${jailname}\""; exec.poststop += "ifconfig ${host_epair} destroy"; } EOF - else - # Generate NETBLOCK without static MAC - cat << EOF >> "${_jail_config}" + else + # Generate NETBLOCK without static MAC + cat << EOF >> "${jail_config}" ## ${host_epair} interface vnet.interface += ${jail_epair}; - exec.prestart += "epair${_epair_num}=\\\$(ifconfig epair create) && ifconfig \\\${epair${_epair_num}} up name ${host_epair} && ifconfig \\\${epair${_epair_num}%a}b up name ${jail_epair}"; - exec.prestart += "ifconfig ${_if} addm ${host_epair}"; - exec.prestart += "ifconfig ${host_epair} description \"${_jail_vnet} host interface for Bastille jail ${_jailname}\""; + exec.prestart += "epair${epair_num}=\\\$(ifconfig epair create) && ifconfig \\\${epair${epair_num}} up name ${host_epair} && ifconfig \\\${epair${epair_num}%a}b up name ${jail_epair}"; + exec.prestart += "ifconfig ${if} addm ${host_epair}"; + exec.prestart += "ifconfig ${host_epair} description \"${jail_vnet} host interface for Bastille jail ${jailname}\""; exec.poststop += "ifconfig ${host_epair} destroy"; } EOF - fi - - # Add config to /etc/rc.conf - sysrc -f "${_jail_rc_config}" ifconfig_${jail_epair}_name="${_jail_vnet}" - if [ -n "${IP6_ADDR}" ]; then - if [ "${IP6_ADDR}" = "SLAAC" ]; then - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}_ipv6="inet6 -ifdisabled accept_rtadv" - else - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}_ipv6="inet6 -ifdisabled ${IP6_ADDR}" - fi - elif [ -n "${IP4_ADDR}" ]; then - # If 0.0.0.0 set DHCP, else set static IP address - if [ "${_ip}" = "0.0.0.0" ] || [ "${_ip}" = "DHCP" ] || [ "${_ip}" = "SYNCDHCP" ]; then - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}="SYNCDHCP" - else - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}="inet ${IP4_ADDR}" - fi - fi - break - fi - done - - echo "Added bridge interface: \"${_if}\"" - - elif [ "${VNET}" -eq 1 ]; then - if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then - for _epair_num in $(seq 0 ${_epair_num_range}); do - if ! grep -Eoqs "e${_epair_num}a_" "${_jail_config}"; then - if [ "$(echo -n "e${_epair_num}a_${_jailname}" | awk '{print length}')" -lt 16 ]; then - local host_epair=e${_epair_num}a_${_jailname} - local jail_epair=e${_epair_num}b_${_jailname} - local jib_epair=${_jailname} - else - name_prefix="$(echo ${_jailname} | cut -c1-7)" - name_suffix="$(echo ${_jailname} | rev | cut -c1-2 | rev)" - local host_epair="e${_epair_num}a_${name_prefix}xx${name_suffix}" - local jail_epair="e${_epair_num}b_${name_prefix}xx${name_suffix}" - local jib_epair="${name_prefix}xx${name_suffix}" - fi - # Remove ending brace (it is added again with the netblock) - sed -i '' '/}/d' "${_jail_config}" - if [ "${STATIC_MAC}" -eq 1 ]; then - # Generate NETBLOCK with static MAC - generate_static_mac "${_jailname}" "${_if}" - cat << EOF >> "${_jail_config}" - ## ${host_epair} interface - vnet.interface += ${jail_epair}; - exec.prestart += "jib addm ${jib_epair} ${_if}"; - exec.prestart += "ifconfig ${host_epair} ether ${macaddr}a"; - exec.prestart += "ifconfig ${jail_epair} ether ${macaddr}b"; - exec.prestart += "ifconfig ${host_epair} description \"${_jail_vnet} host interface for Bastille jail ${_jailname}\""; - exec.poststop += "ifconfig ${host_epair} destroy"; -} -EOF - else - # Generate NETBLOCK without static MAC - cat << EOF >> "${_jail_config}" - ## ${host_epair} interface - vnet.interface += ${jail_epair}; - exec.prestart += "jib addm ${jib_epair} ${_if}"; - exec.prestart += "ifconfig ${host_epair} description \"${_jail_vnet} host interface for Bastille jail ${_jailname}\""; - exec.poststop += "ifconfig ${host_epair} destroy"; -} -EOF - fi - # Add config to /etc/rc.conf - sysrc -f "${_jail_rc_config}" ifconfig_${jail_epair}_name="${_jail_vnet}" - if [ -n "${IP6_ADDR}" ]; then - if [ "${IP6_ADDR}" = "SLAAC" ]; then - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}_ipv6="inet6 -ifdisabled accept_rtadv" - else - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}_ipv6="inet6 -ifdisabled ${IP6_ADDR}" - fi - elif [ -n "${IP4_ADDR}" ]; then - # If 0.0.0.0 set DHCP, else set static IP address - if [ "${_ip}" = "0.0.0.0" ] || [ "${_ip}" = "DHCP" ] || [ "${_ip}" = "SYNCDHCP" ]; then - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}="SYNCDHCP" - else - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}="inet ${IP4_ADDR}" - fi - fi - break - fi - done - - echo "Added VNET interface: \"${_if}\"" - - elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then - for _ngif_num in $(seq 0 ${_ngif_num_range}); do - if ! grep -Eoqs "e${_ngif_num}a_" "${_jail_config}"; then - if [ "$(echo -n "ng${_ngif_num}_${_jailname}" | awk '{print length}')" -lt 16 ]; then - # Generate new netgraph interface name - local _ngif="ng${_ngif_num}_${_jailname}" - local jng_if="${_jailname}" - else - name_prefix="$(echo ${_jailname} | cut -c1-7)" - name_suffix="$(echo ${_jailname} | rev | cut -c1-2 | rev)" - local _ngif="ng${_ngif_num}_${name_prefix}xx${name_suffix}" - local jng_if="${name_prefix}xx${name_suffix}" - fi - # Remove ending brace (it is added again with the netblock) - sed -i '' '/}/d' "${_jail_config}" - if [ "${STATIC_MAC}" -eq 1 ]; then - # Generate NETBLOCK with static MAC - generate_static_mac "${_jailname}" "${_if}" - cat << EOF >> "${_jail_config}" - ## ${_ngif} interface - vnet.interface += ${_ngif}; - exec.prestart += "jng bridge ${jng_if} ${_if}"; - exec.prestart += "ifconfig ${_ngif} ether ${macaddr}b"; - exec.poststop += "jng shutdown ${jng_if}"; -} -EOF - else - # Generate NETBLOCK without static MAC - cat << EOF >> "${_jail_config}" - ## ${_ngif} interface - vnet.interface += ${_ngif}; - exec.prestart += "jng bridge ${jng_if} ${_if}"; - exec.poststop += "jng shutdown ${jng_if}"; -} -EOF - fi - # Add config to /etc/rc.conf - sysrc -f "${_jail_rc_config}" ifconfig_${_ngif}_name="${_jail_vnet}" - if [ -n "${_ip}" ]; then - # If 0.0.0.0 set DHCP, else set static IP address - if [ "${_ip}" = "0.0.0.0" ] || [ "${_ip}" = "DHCP" ]; then - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}="SYNCDHCP" - else - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}="inet ${_ip}" - fi - fi - break - fi - done - echo "Added VNET interface: \"${_if}\"" fi + # Add config to /etc/rc.conf + sysrc -f "${jail_rc_config}" ifconfig_${jail_epair}_name="${jail_vnet}" + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}_descr="jail interface for ${if}" + + if [ -n "${IP6_ADDR}" ]; then + if [ "${IP6_ADDR}" = "SLAAC" ]; then + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}_ipv6="inet6 -ifdisabled accept_rtadv" + else + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}_ipv6="inet6 -ifdisabled ${IP6_ADDR}" + fi + elif [ -n "${IP4_ADDR}" ]; then + # If 0.0.0.0 set DHCP, else set static IP address + if [ "${ip}" = "0.0.0.0" ] || [ "${ip}" = "DHCP" ] || [ "${ip}" = "SYNCDHCP" ]; then + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}="SYNCDHCP" + else + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}="inet ${IP4_ADDR}" + fi + fi + echo "Added bridge interface: \"${if}\"" + + # VNET interface + elif [ "${VNET}" -eq 1 ]; then + + # if_bridge + if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then + + local host_epair=e${epair_num}a_${epair_suffix} + local jail_epair=e${epair_num}b_${epair_suffix} + local jib_epair=${epair_suffix} + + # Remove ending brace (it is added again with the netblock) + sed -i '' '/^}$/d' "${jail_config}" + + if [ "${STATIC_MAC}" -eq 1 ]; then + # Generate NETBLOCK with static MAC + generate_static_mac "${jailname}" "${if}" + cat << EOF >> "${jail_config}" + ## ${host_epair} interface + vnet.interface += ${jail_epair}; + exec.prestart += "jib addm ${jib_epair} ${if}"; + exec.prestart += "ifconfig ${host_epair} ether ${macaddr}a"; + exec.prestart += "ifconfig ${jail_epair} ether ${macaddr}b"; + exec.prestart += "ifconfig ${host_epair} description \"${jail_vnet} host interface for Bastille jail ${jailname}\""; + exec.poststop += "ifconfig ${host_epair} destroy"; +} +EOF + else + # Generate NETBLOCK without static MAC + cat << EOF >> "${jail_config}" + ## ${host_epair} interface + vnet.interface += ${jail_epair}; + exec.prestart += "jib addm ${jib_epair} ${if}"; + exec.prestart += "ifconfig ${host_epair} description \"${jail_vnet} host interface for Bastille jail ${jailname}\""; + exec.poststop += "ifconfig ${host_epair} destroy"; +} +EOF + fi + + # Add config to /etc/rc.conf + sysrc -f "${jail_rc_config}" ifconfig_${jail_epair}_name="${jail_vnet}" + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}_descr="jail interface for ${if}" + + if [ -n "${IP6_ADDR}" ]; then + if [ "${IP6_ADDR}" = "SLAAC" ]; then + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}_ipv6="inet6 -ifdisabled accept_rtadv" + else + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}_ipv6="inet6 -ifdisabled ${IP6_ADDR}" + fi + elif [ -n "${IP4_ADDR}" ]; then + # If 0.0.0.0 set DHCP, else set static IP address + if [ "${ip}" = "0.0.0.0" ] || [ "${ip}" = "DHCP" ] || [ "${ip}" = "SYNCDHCP" ]; then + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}="SYNCDHCP" + else + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}="inet ${IP4_ADDR}" + fi + fi + echo "Added VNET interface: \"${if}\"" + + # netgraph + elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then + + local ng_if=ng${ng_num}_${ng_suffix} + local jng_if=${ng_suffix} + + # Remove ending brace (it is added again with the netblock) + sed -i '' '/^}$/d' "${jail_config}" + + if [ "${STATIC_MAC}" -eq 1 ]; then + # Generate NETBLOCK with static MAC + generate_static_mac "${jailname}" "${if}" + cat << EOF >> "${jail_config}" + ## ${ng_if} interface + vnet.interface += ${ng_if}; + exec.prestart += "jng bridge ${jng_if} ${if}"; + exec.prestart += "ifconfig ${ng_if} ether ${macaddr}b"; + exec.poststop += "jng shutdown ${jng_if}"; +} +EOF + else + # Generate NETBLOCK without static MAC + cat << EOF >> "${jail_config}" + ## ${ng_if} interface + vnet.interface += ${ng_if}; + exec.prestart += "jng bridge ${jng_if} ${if}"; + exec.poststop += "jng shutdown ${jng_if}"; +} +EOF + fi + + # Add config to /etc/rc.conf + sysrc -f "${jail_rc_config}" ifconfig_${ng_if}_name="${jail_vnet}" + + if [ -n "${ip}" ]; then + # If 0.0.0.0 set DHCP, else set static IP address + if [ "${ip}" = "0.0.0.0" ] || [ "${ip}" = "DHCP" ]; then + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}="SYNCDHCP" + else + sysrc -f "${jail_rc_config}" ifconfig_${jail_vnet}="inet ${ip}" + fi + fi + echo "Added VNET interface: \"${if}\"" + + fi + + # PASSTHROUGH elif [ "${PASSTHROUGH}" -eq 1 ]; then + # Remove ending brace (it is added again with the netblock) - sed -i '' '/}/d' "${_jail_config}" + sed -i '' '/^}$/d' "${jail_config}" + # Generate NETBLOCK (static MAC not used on passthrough) - cat << EOF >> "${_jail_config}" - ## ${_if} interface - vnet.interface += ${_if}; - exec.prestop += "ifconfig ${_if} -vnet ${_jailname}"; + cat << EOF >> "${jail_config}" + ## ${if} interface + vnet.interface += ${if}; + exec.prestop += "ifconfig ${if} -vnet ${jailname}"; } EOF # Add config to /etc/rc.conf if [ -n "${IP6_ADDR}" ]; then if [ "${IP6_ADDR}" = "SLAAC" ]; then - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}_ipv6="inet6 -ifdisabled accept_rtadv" + sysrc -f "${jail_rc_config}" ifconfig_${if}_ipv6="inet6 -ifdisabled accept_rtadv" else - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}_ipv6="inet6 -ifdisabled ${IP6_ADDR}" + sysrc -f "${jail_rc_config}" ifconfig_${if}_ipv6="inet6 -ifdisabled ${IP6_ADDR}" fi elif [ -n "${IP4_ADDR}" ]; then # If 0.0.0.0 set DHCP, else set static IP address - if [ "${_ip}" = "0.0.0.0" ] || [ "${_ip}" = "DHCP" ] || [ "${_ip}" = "SYNCDHCP" ]; then - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}="SYNCDHCP" + if [ "${ip}" = "0.0.0.0" ] || [ "${ip}" = "DHCP" ] || [ "${ip}" = "SYNCDHCP" ]; then + sysrc -f "${jail_rc_config}" ifconfig_${if}="SYNCDHCP" else - sysrc -f "${_jail_rc_config}" ifconfig_${_jail_vnet}="inet ${IP4_ADDR}" + sysrc -f "${jail_rc_config}" ifconfig_${if}="inet ${IP4_ADDR}" fi fi - echo "Added Passthrough interface: \"${_if}\"" - + echo "Added Passthrough interface: \"${if}\"" + elif [ "${STANDARD}" -eq 1 ]; then if [ -n "${IP6_ADDR}" ]; then - sed -i '' "s/interface = .*/&\n ip6.addr += ${_if}|${_ip};/" ${_jail_config} + sed -i '' "s/interface = .*/&\n ip6.addr += ${if}|${ip};/" ${jail_config} else - sed -i '' "s/interface = .*/&\n ip4.addr += ${_if}|${_ip};/" ${_jail_config} + sed -i '' "s/interface = .*/&\n ip4.addr += ${if}|${ip};/" ${jail_config} fi fi } remove_interface() { - local _jailname="${1}" - local _if="${2}" - local _jail_config="${bastille_jailsdir}/${_jailname}/jail.conf" - local _jail_rc_config="${bastille_jailsdir}/${_jailname}/root/etc/rc.conf" + local jailname="${1}" + local if="${2}" + local jail_config="${bastille_jailsdir}/${jailname}/jail.conf" + local jail_rc_config="${bastille_jailsdir}/${jailname}/root/etc/rc.conf" # Skip next block in case of standard jail if [ "$(bastille config ${TARGET} get vnet)" != "not set" ]; then - if grep -q "vnet.interface.*${_if};" ${_jail_config}; then + if grep -q "vnet.interface.*${if};" ${jail_config}; then - local _if_jail="${_if}" - local _if_type="passthrough" + local if_jail="${if}" + local if_type="passthrough" elif [ "${bastille_network_vnet_type}" = "if_bridge" ]; then - local _jib_epair="$(grep "jib addm.*${_if}" ${_jail_config} | awk '{print $3}')" - local _if_type="if_bridge" + local jib_epair="$(grep "jib addm.*${if}" ${jail_config} | awk '{print $3}')" + local if_type="if_bridge" - if [ -n "${_jib_epair}" ]; then - local _epaira="$(grep -m 1 -A 1 "${_if}" ${_jail_config} | grep -Eo "e[0-9]+a_${_jib_epair}")" - local _epairb="$(echo ${_epaira} | sed 's/a_/b_/')" - local _if_jail="${_epairb}" + if [ -n "${jib_epair}" ]; then + local epaira="$(grep -m 1 -A 1 "${if}" ${jail_config} | grep -Eo "e[0-9]+a_${jib_epair}")" + local epairb="$(echo ${epaira} | sed 's/a_/b_/')" + local if_jail="${epairb}" else - local _epaira="$(grep -m 1 "${_if}" ${_jail_config} | grep -Eo 'e[0-9]+a_[^;" ]+')" - local _epairb="$(echo ${_epaira} | sed 's/a_/b_/')" - local _if_jail="${_epairb}" + local epaira="$(grep -m 1 "${if}" ${jail_config} | grep -Eo 'e[0-9]+a_[^;" ]+')" + local epairb="$(echo ${epaira} | sed 's/a_/b_/')" + local if_jail="${epairb}" fi elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then - local _jng_if="$(grep "jng bridge.*${_if}" ${_jail_config} | awk '{print $3}')" - local _if_jail="$(grep "ng[0-9]+_${_jng_if}" ${_jail_config})" - local _if_type="netgraph" + local jng_if="$(grep "jng bridge.*${if}" ${jail_config} | awk '{print $3}')" + local if_jail="$(grep "ng[0-9]+_${jng_if}" ${jail_config})" + local if_type="netgraph" else - error_exit "[ERROR]: Could not find interface inside jail: \"${_if_jail}\"" + error_exit "[ERROR]: Could not find interface inside jail: \"${if_jail}\"" fi - + # Get vnetX value from rc.conf - if [ "${_if_type}" = "if_bridge" ]; then - if grep -oq "${_if_jail}" ${_jail_config}; then - local _if_vnet="$(grep "${_if_jail}" ${_jail_rc_config} | grep -Eo 'vnet[0-9]+')" + if [ "${if_type}" = "if_bridge" ]; then + if grep -oq "${if_jail}" ${jail_config}; then + local if_vnet="$(grep "${if_jail}" ${jail_rc_config} | grep -Eo 'vnet[0-9]+')" else - error_exit "[ERROR]: Interface not found: ${_if_jail}" + error_exit "[ERROR]: Interface not found: ${if_jail}" fi - elif [ "${_if_type}" = "netgraph" ]; then - if grep -oq "${_if_jail}" ${_jail_config}; then - local _if_vnet="${_if_jail}" + elif [ "${if_type}" = "netgraph" ]; then + if grep -oq "${if_jail}" ${jail_config}; then + local if_vnet="${if_jail}" else - error_exit "[ERROR]: Interface not found: ${_if_jail}" + error_exit "[ERROR]: Interface not found: ${if_jail}" fi - elif [ "${_if_type}" = "passthrough" ]; then - if grep -oq "${_if_jail}" ${_jail_config}; then - local _if_vnet="${_if_jail}" + elif [ "${if_type}" = "passthrough" ]; then + if grep -oq "${if_jail}" ${jail_config}; then + local if_vnet="${if_jail}" else - error_exit "[ERROR]: Interface not found: ${_if_jail}" + error_exit "[ERROR]: Interface not found: ${if_jail}" fi fi - + # Do not allow removing default vnet0 interface - if [ "${_if_vnet}" = "vnet0" ]; then + if [ "${if_vnet}" = "vnet0" ]; then error_exit "[ERROR]: Default interface cannot be removed." fi # Avoid removing entire file contents if variables aren't set for some reason - if [ -z "${_if_jail}" ]; then + if [ -z "${if_jail}" ]; then error_exit "[ERROR]: Could not find specifed interface." fi - + # Remove interface from /etc/rc.conf - if [ "${_if_type}" = "if_bridge" ]; then - if [ -n "${_if_vnet}" ] && echo ${_if_vnet} | grep -Eoq 'vnet[0-9]+'; then - sed -i '' "/.*${_if_vnet}.*/d" "${_jail_rc_config}" + if [ "${if_type}" = "if_bridge" ]; then + if [ -n "${if_vnet}" ] && echo ${if_vnet} | grep -Eoq 'vnet[0-9]+'; then + sed -i '' "/.*${if_vnet}.*/d" "${jail_rc_config}" else error_exit "[ERROR]: Failed to remove interface from /etc/rc.conf" fi - elif [ "${_if_type}" = "netgraph" ]; then - if [ -n "${_if_vnet}" ] && echo ${_if_vnet} | grep -Eoq 'vnet[0-9]+'; then - sed -i '' "/.*${_if_vnet}.*/d" "${_jail_rc_config}" + elif [ "${if_type}" = "netgraph" ]; then + if [ -n "${if_vnet}" ] && echo ${if_vnet} | grep -Eoq 'vnet[0-9]+'; then + sed -i '' "/.*${if_vnet}.*/d" "${jail_rc_config}" else error_exit "[ERROR]: Failed to remove interface from /etc/rc.conf" fi - elif [ "${_if_type}" = "passthrough" ]; then - if [ -n "${_if_vnet}" ]; then - sed -i '' "/.*${_if_vnet}.*/d" "${_jail_rc_config}" + elif [ "${if_type}" = "passthrough" ]; then + if [ -n "${if_vnet}" ]; then + sed -i '' "/.*${if_vnet}.*/d" "${jail_rc_config}" else error_exit "[ERROR]: Failed to remove interface from /etc/rc.conf" fi fi # Remove VNET interface from jail.conf (VNET) - if [ -n "${_if_jail}" ]; then - if [ "${_if_type}" = "if_bridge" ]; then - sed -i '' "/.*${_epaira}.*/d" "${_jail_config}" - sed -i '' "/.*${_epairb}.*/d" "${_jail_config}" - sed -i '' "/.*${_if}.*/d" "${_jail_config}" - elif [ "${_if_type}" = "netgraph" ]; then - sed -i '' "/.*${_if_jail}.*/d" "${_jail_config}" - sed -i '' "/.*${_if}.*/d" "${_jail_config}" - elif [ "${_if_type}" = "passthrough" ]; then - sed -i '' "/.*${_if_jail}.*/d" "${_jail_config}" + if [ -n "${if_jail}" ]; then + if [ "${if_type}" = "if_bridge" ]; then + sed -i '' "/.*${epaira}.*/d" "${jail_config}" + sed -i '' "/.*${epairb}.*/d" "${jail_config}" + sed -i '' "/.*${if}.*/d" "${jail_config}" + elif [ "${if_type}" = "netgraph" ]; then + sed -i '' "/.*${if_jail}.*/d" "${jail_config}" + sed -i '' "/.*${if}.*/d" "${jail_config}" + elif [ "${if_type}" = "passthrough" ]; then + sed -i '' "/.*${if_jail}.*/d" "${jail_config}" fi else error_exit "[ERROR]: Failed to remove interface from jail.conf" fi else # Remove interface from jail.conf (non-VNET) - if [ -n "${_if}" ]; then - if grep ${_if} ${_jail_config} 2>/dev/null | grep -qo " = "; then + if [ -n "${if}" ]; then + if grep ${if} ${jail_config} 2>/dev/null | grep -qo " = "; then error_exit "[ERROR]: Default interface cannot be removed." else - sed -i '' "/.*${_if}.*/d" "${_jail_config}" + sed -i '' "/.*${if}.*/d" "${jail_config}" fi else error_exit "[ERROR]: Failed to remove interface from jail.conf" fi fi - - echo "Removed interface: \"${_if}\"" + echo "Removed interface: \"${if}\"" } add_vlan() { - local _jailname="${1}" - local _interface="${2}" - local _ip="${3}" - local _vlan_id="${4}" - local _jail_config="${bastille_jailsdir}/${_jailname}/jail.conf" - local _jail_rc_config="${bastille_jailsdir}/${_jailname}/root/etc/rc.conf" + local jailname="${1}" + local interface="${2}" + local ip="${3}" + local vlan_id="${4}" + local jail_config="${bastille_jailsdir}/${jailname}/jail.conf" + local jail_rc_config="${bastille_jailsdir}/${jailname}/root/etc/rc.conf" if [ "${VNET}" -eq 1 ]; then - local _jib_epair="$(grep "jib addm.*${_if}" ${_jail_config} | awk '{print $3}')" - local _jail_epair="$(grep "e[0-9]+b_${_jib_epair}" ${_jail_config})" - local _jail_vnet="$(grep "${_jail_epair}_name" ${_jail_rc_config} | grep -Eo "vnet[0-9]+")" + local jib_epair="$(grep "jib addm.*${if}" ${jail_config} | awk '{print $3}')" + local jail_epair="$(grep "e[0-9]+b_${jib_epair}" ${jail_config})" + local jail_vnet="$(grep "${jail_epair}_name" ${jail_rc_config} | grep -Eo "vnet[0-9]+")" elif [ "${BRIDGE}" -eq 1 ]; then - local _jail_epair="$(grep 'e[0-9]+b_[^;" ]+' ${_jail_config})" - local _jail_vnet="$(grep "${_jail_epair}_name" ${_jail_rc_config} | grep -Eo "vnet[0-9]+")" + local jail_epair="$(grep 'e[0-9]+b_[^;" ]+' ${jail_config})" + local jail_vnet="$(grep "${jail_epair}_name" ${jail_rc_config} | grep -Eo "vnet[0-9]+")" elif [ "${PASSTHROUGH}" -eq 1 ]; then - local _jail_vnet="${_interface}" + local _jail_vnet="${interface}" fi - if grep -Eq "ifconfig_${_jail_vnet}_${_vlan_id}" "${bastille_jailsdir}/${_jailname}/root/etc/rc.conf"; then - error_exit "[ERROR]: VLAN has already been added: VLAN ${_vlan_id}" + if grep -Eq "ifconfig_${jail_vnet}_${vlan_id}" "${bastille_jailsdir}/${jailname}/root/etc/rc.conf"; then + error_exit "[ERROR]: VLAN has already been added: VLAN ${vlan_id}" else - bastille start "${_jailname}" - bastille template "${_jailname}" ${bastille_template_vlan} --arg VLANID="${_vlan_id}" --arg IFCONFIG="inet ${_ip}" --arg JAIL_VNET="${_jail_vnet}" - bastille restart "${_jailname}" + bastille start "${jailname}" + bastille template "${jailname}" ${bastille_template_vlan} --arg VLANID="${vlan_id}" --arg IFCONFIG="inet ${ip}" --arg JAIL_VNET="${jail_vnet}" + bastille restart "${jailname}" fi - echo "Added VLAN ${_vlan_id} to interface: \"${_jail_vnet}\"" + echo "Added VLAN ${vlan_id} to interface: \"${jail_vnet}\"" } info "\n[${TARGET}]:" case "${ACTION}" in + add) + validate_netconf validate_netif "${INTERFACE}" + if check_interface_added "${TARGET}" "${INTERFACE}" && [ -z "${VLAN_ID}" ]; then error_exit "Interface is already added: \"${INTERFACE}\"" elif { [ "${VNET}" -eq 1 ] || [ "${BRIDGE}" -eq 1 ] || [ "${PASSTHROUGH}" -eq 1 ]; } && [ -n "${VLAN_ID}" ]; then @@ -627,10 +640,12 @@ case "${ACTION}" in echo exit 0 fi + ## validate IP if not empty if [ -n "${IP}" ]; then validate_ip "${IP}" fi + if [ "${VNET}" -eq 1 ]; then if [ "$(bastille config ${TARGET} get vnet)" = "not set" ]; then error_exit "[ERROR]: ${TARGET} is not a VNET jail." @@ -645,6 +660,7 @@ case "${ACTION}" in bastille start "${TARGET}" fi fi + elif [ "${BRIDGE}" -eq 1 ]; then if [ "$(bastille config ${TARGET} get vnet)" = "not set" ]; then error_exit "[ERROR]: ${TARGET} is not a VNET jail." @@ -659,6 +675,7 @@ case "${ACTION}" in bastille start "${TARGET}" fi fi + elif [ "${PASSTHROUGH}" -eq 1 ]; then if [ "$(bastille config ${TARGET} get vnet)" = "not set" ]; then error_exit "[ERROR]: ${TARGET} is not a VNET jail." @@ -671,6 +688,7 @@ case "${ACTION}" in if [ "${AUTO}" -eq 1 ]; then bastille start "${TARGET}" fi + elif [ "${STANDARD}" -eq 1 ]; then if [ "$(bastille config ${TARGET} get vnet)" != "not set" ]; then error_exit "[ERROR]: ${TARGET} is a VNET jail." @@ -682,8 +700,10 @@ case "${ACTION}" in fi fi ;; + remove|delete) - check_interface_added "${TARGET}" "${INTERFACE}" || error_exit "Interface not found in jail.conf: \"${INTERFACE}\"" + + check_interface_added "${TARGET}" "${INTERFACE}" || error_exit "Interface not found in jail.conf: \"${INTERFACE}\"" validate_netif "${INTERFACE}" if ! grep -q "${INTERFACE}" ${bastille_jailsdir}/${TARGET}/jail.conf; then error_exit "[ERROR]: Interface not found in jail.conf: \"${INTERFACE}\"" diff --git a/usr/local/share/bastille/pkg.sh b/usr/local/share/bastille/pkg.sh index 677b4f4a..09dfe8a0 100644 --- a/usr/local/share/bastille/pkg.sh +++ b/usr/local/share/bastille/pkg.sh @@ -72,14 +72,14 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; H) USE_HOST_PKG=1 ;; y) AUTO_YES=1 ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -96,14 +96,12 @@ fi TARGET="${1}" shift -# Use mktemp to store exit codes -export TMP_BASTILLE_EXIT_CODE="$(mktemp)" -echo 0 > "${TMP_BASTILLE_EXIT_CODE}" - +ERRORS=0 + bastille_root_check set_target "${TARGET}" -pkg_run_command() { +for _jail in ${JAILS}; do # Validate jail state check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then @@ -136,12 +134,12 @@ pkg_run_command() { fi fi - bastille_check_exit_code "${_jail}" "$?" -} + if [ "$?" -ne 0 ]; then + ERRORS=$((ERRORS + 1)) + fi -for _jail in ${JAILS}; do - pkg_run_command "$@" done -echo -bastille_return_exit_code +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi \ No newline at end of file diff --git a/usr/local/share/bastille/pkgbase/FreeBSD-base.conf b/usr/local/share/bastille/pkgbase/FreeBSD-base.conf new file mode 100644 index 00000000..26c62044 --- /dev/null +++ b/usr/local/share/bastille/pkgbase/FreeBSD-base.conf @@ -0,0 +1,56 @@ +FreeBSD-base-latest: { + url: "pkg+https://pkg.FreeBSD.org/${ABI}/base_latest", + mirror_type: "srv", + signature_type: "fingerprints", + fingerprints: "/usr/share/keys/pkg", + enabled: yes +} +FreeBSD-base-weekly: { + url: "pkg+https://pkg.FreeBSD.org/${ABI}/base_weekly", + mirror_type: "srv", + signature_type: "fingerprints", + fingerprints: "/usr/share/keys/pkg", + enabled: yes +} +FreeBSD-base-release-0: { + url: "pkg+https://pkg.FreeBSD.org/${ABI}/base_release_0", + mirror_type: "srv", + signature_type: "fingerprints", + fingerprints: "/usr/share/keys/pkg", + enabled: yes +} +FreeBSD-base-release-1: { + url: "pkg+https://pkg.FreeBSD.org/${ABI}/base_release_1", + mirror_type: "srv", + signature_type: "fingerprints", + fingerprints: "/usr/share/keys/pkg", + enabled: yes +} +FreeBSD-base-release-2: { + url: "pkg+https://pkg.FreeBSD.org/${ABI}/base_release_2", + mirror_type: "srv", + signature_type: "fingerprints", + fingerprints: "/usr/share/keys/pkg", + enabled: yes +} +FreeBSD-base-release-3: { + url: "pkg+https://pkg.FreeBSD.org/${ABI}/base_release_3", + mirror_type: "srv", + signature_type: "fingerprints", + fingerprints: "/usr/share/keys/pkg", + enabled: yes +} +FreeBSD-base-release-4: { + url: "pkg+https://pkg.FreeBSD.org/${ABI}/base_release_4", + mirror_type: "srv", + signature_type: "fingerprints", + fingerprints: "/usr/share/keys/pkg", + enabled: yes +} +FreeBSD-base-release-5: { + url: "pkg+https://pkg.FreeBSD.org/${ABI}/base_release_5", + mirror_type: "srv", + signature_type: "fingerprints", + fingerprints: "/usr/share/keys/pkg", + enabled: yes +} \ No newline at end of file diff --git a/usr/local/share/bastille/rcp.sh b/usr/local/share/bastille/rcp.sh index aab2c28b..1a9eba3a 100644 --- a/usr/local/share/bastille/rcp.sh +++ b/usr/local/share/bastille/rcp.sh @@ -65,7 +65,7 @@ while [ "$#" -gt 0 ]; do case ${_opt} in q) OPTION="-a" ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -94,6 +94,4 @@ jail_path="$(echo ${bastille_jailsdir}/${TARGET}/root/${JAIL_PATH} | sed 's#//#/ if ! cp "${OPTION}" "${jail_path}" "${host_path}"; then error_exit "[ERROR]: RCP failed: ${jail_path} -> ${host_path}" -else - echo fi \ No newline at end of file diff --git a/usr/local/share/bastille/rdr.sh b/usr/local/share/bastille/rdr.sh index 19876671..44557e8f 100644 --- a/usr/local/share/bastille/rdr.sh +++ b/usr/local/share/bastille/rdr.sh @@ -35,14 +35,14 @@ usage() { error_notify "Usage: bastille rdr [option(s)] TARGET [clear|reset|list|(tcp|udp)] HOST_PORT JAIL_PORT [log ['(' logopts ')'] ]" cat << EOF - + Options: - -d | --destination [destination] Limit rdr to a destination IP. Useful if you have multiple IPs on one interface. - -i | --interface [interface] Set the interface to create the rdr rule on. Useful if you have multiple interfaces. - -s | --source [source] Limit rdr to a source IP or table. Useful to only allow access from certain sources. - -t | --type [ipv4|ipv6] Specify IP type. Must be used if -s or -d are used. Defaults to both. - -x | --debug Enable debug mode. + -d | --destination IP Limit rdr to a destination IP. Useful if you have multiple IPs on one interface. + -i | --interface IF,IF Specify interface(s) to apply rule to. Comman separated. + -s | --source IP|table Limit rdr to a source IP or table. + -t | --type ipv4|ipv6 Specify IP type. Must be used if -s or -d are used. Defaults to both. + -x | --debug Enable debug mode. EOF exit 1 @@ -76,7 +76,7 @@ check_jail_validity() { else error_exit "[ERROR]: VNET jails do not support rdr." fi - + # Check if rdr-anchor is defined in pf.conf if ! (pfctl -sn | grep rdr-anchor | grep 'rdr/\*' >/dev/null); then error_exit "[ERROR]: rdr-anchor not found in pf.conf" @@ -169,8 +169,9 @@ persist_rdr_log_rule() { load_rdr_rule() { local inet="${1}" - local if_name="${2}" - local if="${bastille_network_pf_ext_if}"=\"${2}\" + local if_raw="${2}" + local if_name="{ $(echo ${if_raw} | sed 's/,/ /') }" + local if="${bastille_network_pf_ext_if}"=\"${if_name}\" local src="${3}" local dst="${4}" local proto="${5}" @@ -185,7 +186,7 @@ load_rdr_rule() { | pfctl -a "rdr/${TARGET}" -f-; then error_exit "[ERROR]: Failed to create IPv4 rdr rule \"${if_name} ${src} ${dst} ${proto} ${host_port} ${jail_port}\"" else - echo "IPv4 ${proto}/${host_port}:${jail_port} on ${if_name}" + echo "IPv4 ${proto}/${host_port}:${jail_port} on ${if_raw}" fi fi # Create IPv6 rdr rule (if ip6.addr is enabled) @@ -196,7 +197,7 @@ load_rdr_rule() { | pfctl -a "rdr/${TARGET}" -f-; then error_exit "[ERROR]: Failed to create IPv6 rdr rule \"${if_name} ${src} ${dst} ${proto} ${host_port} ${jail_port}\"" else - echo "IPv6 ${proto}/${host_port}:${jail_port} on ${if_name}" + echo "IPv6 ${proto}/${host_port}:${jail_port} on ${if_raw}" fi fi } @@ -204,8 +205,9 @@ load_rdr_rule() { load_rdr_log_rule() { local inet="${1}" - local if_name="${2}" - local if="${bastille_network_pf_ext_if}"=\"${2}\" + local if_raw="${2}" + local if_name="{ $(echo ${if_raw} | sed 's/,/ /') }" + local if="${bastille_network_pf_ext_if}"=\"${if_name}\" local src="${3}" local dst="${4}" local proto="${5}" @@ -222,25 +224,25 @@ load_rdr_log_rule() { | pfctl -a "rdr/${TARGET}" -f-; then error_exit "[ERROR]: Failed to create logged IPv4 rdr rule \"${if_name} ${src} ${dst} ${proto} ${host_port} ${jail_port}\"" else - echo "IPv4 ${proto}/${host_port}:${jail_port} on ${if_name}" + echo "IPv4 ${proto}/${host_port}:${jail_port} on ${if_raw}" fi fi # Create IPv6 rdr rule with log (if ip6.addr is enabled) # shellcheck disable=SC2193 - if [ -n "${JAIL_IP6}" ] && { [ "${inet}" = "ipv6" ] || [ "${inet}" = "dual" ]; } then + if [ -n "${JAIL_IP6}" ] && { [ "${inet}" = "ipv6" ] || [ "${inet}" = "dual" ]; } then if ! ( pfctl -a "rdr/${TARGET}" -Psn; printf '%s\nrdr pass %s on $%s inet6 proto %s from %s to %s port %s -> %s port %s\n' "$if" "$log" "${bastille_network_pf_ext_if}" "$proto" "$src" "$dst" "$host_port" "$JAIL_IP6" "$jail_port" ) \ | pfctl -a "rdr/${TARGET}" -f-; then error_exit "[ERROR]: Failed to create logged IPv6 rdr rule \"${if_name} ${src} ${dst} ${proto} ${host_port} ${jail_port}\"" else - echo "IPv6 ${proto}/${host_port}:${jail_port} on ${if_name}" + echo "IPv6 ${proto}/${host_port}:${jail_port} on ${if_raw}" fi fi } # Handle options. -RDR_IF="$(grep "^[[:space:]]*${bastille_network_pf_ext_if}[[:space:]]*=" ${bastille_pf_conf} | awk -F'"' '{print $2}')" +RDR_IF="$(grep "^[[:space:]]*${bastille_network_pf_ext_if}[[:space:]]*=" ${bastille_pf_conf} | awk -F'"' '{print $2}' | sed -e 's/{ //' -e 's/ }//')" RDR_SRC="any" RDR_DST="any" RDR_INET="dual" @@ -256,7 +258,7 @@ while [ "$#" -gt 0 ]; do ;; -d|--destination) if ifconfig | grep -owq "inet ${2}"; then - OPTION_DST=1 + OPTION_DST=1 RDR_DST="${2}" shift 2 else @@ -264,22 +266,23 @@ while [ "$#" -gt 0 ]; do fi ;; -i|--interface) - if ifconfig | grep -owq "${2}:"; then - OPTION_IF=1 - RDR_IF="${2}" - shift 2 - else - error_exit "[ERROR]: '${2}' is not a valid interface." - fi + for if in $(echo "${2}" | sed 's/,/ /'); do + if ! ifconfig | grep -owq "${if}:"; then + error_exit "[ERROR]: '${if}' is not a valid interface." + fi + done + OPTION_IF=1 + RDR_IF="${2}" + shift 2 ;; -s|--source) if echo "${2}" | grep -Eoq "([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|.*:.*)"; then - check_rdr_ip_validity "${2}" - RDR_SRC="${2}" + check_rdr_ip_validity "${2}" + RDR_SRC="${2}" else - check_rdr_table_validity "${2}" - OPT_SRC_TABLE=1 - RDR_SRC="$(echo "${2}" | sed -e 's/^//')" + check_rdr_table_validity "${2}" + OPT_SRC_TABLE=1 + RDR_SRC="$(echo "${2}" | sed -e 's/^//')" fi OPTION_SRC=1 shift 2 @@ -320,7 +323,9 @@ set_target_single "${TARGET}" while [ "$#" -gt 0 ]; do case "${1}" in + list) + if [ "${OPTION_IF}" -eq 1 ] || [ "${OPTION_SRC}" -eq 1 ] || [ "${OPTION_DST}" -eq 1 ] || [ "${OPTION_INET_TYPE}" -eq 1 ];then error_exit "[ERROR]: Command \"${1}\" cannot be used with options." elif [ -n "${2}" ]; then @@ -331,7 +336,9 @@ while [ "$#" -gt 0 ]; do fi shift ;; + clear) + if [ "${OPTION_IF}" -eq 1 ] || [ "${OPTION_SRC}" -eq 1 ] || [ "${OPTION_DST}" -eq 1 ] || [ "${OPTION_INET_TYPE}" -eq 1 ];then error_exit "[ERROR]: Command \"${1}\" cannot be used with options." elif [ -n "${2}" ]; then @@ -342,7 +349,9 @@ while [ "$#" -gt 0 ]; do fi shift ;; + reset) + if [ "${OPTION_IF}" -eq 1 ] || [ "${OPTION_SRC}" -eq 1 ] || [ "${OPTION_DST}" -eq 1 ] || [ "${OPTION_INET_TYPE}" -eq 1 ];then error_exit "[ERROR]: Command \"${1}\" cannot be used with options." elif [ -n "${2}" ]; then @@ -355,22 +364,24 @@ while [ "$#" -gt 0 ]; do fi fi shift - ;; + ;; + tcp|udp) + if [ "$#" -lt 3 ]; then usage elif [ "${OPTION_SRC}" -eq 1 ] || [ "${OPTION_DST}" -eq 1 ] && [ "${OPTION_INET_TYPE}" -ne 1 ] && [ "${OPT_SRC_TABLE}" -eq 0 ];then error_exit "[ERROR]: [-t|--type] must be set when NOT using a table as [-s|--source] or [-d|--destination]." elif [ "$#" -eq 3 ]; then check_jail_validity - validate_rdr_rule $RDR_IF $RDR_SRC $RDR_DST $1 $2 $3 - persist_rdr_rule $RDR_INET $RDR_IF $RDR_SRC $RDR_DST $1 $2 $3 - load_rdr_rule $RDR_INET $RDR_IF $RDR_SRC $RDR_DST $1 $2 $3 - # Temp block to remove old format after new format is loaded the first time - while read rules; do - if [ "$(echo ${rules} | wc -w)" -lt 6 ]; then - sed -i '' "/^${rules}$/d" "${bastille_jailsdir}/${TARGET}/rdr.conf" - fi + validate_rdr_rule "$RDR_IF" $RDR_SRC $RDR_DST $1 $2 $3 + persist_rdr_rule $RDR_INET "$RDR_IF" $RDR_SRC $RDR_DST $1 $2 $3 + load_rdr_rule $RDR_INET "$RDR_IF" $RDR_SRC $RDR_DST $1 $2 $3 + # Temp block to remove old format after new format is loaded the first time + while read rules; do + if [ "$(echo ${rules} | wc -w)" -lt 6 ]; then + sed -i '' "/^${rules}$/d" "${bastille_jailsdir}/${TARGET}/rdr.conf" + fi done < "${bastille_jailsdir}/${TARGET}/rdr.conf" shift "$#" else @@ -386,18 +397,18 @@ while [ "$#" -gt 0 ]; do done if [ "${2}" = "(" ] && [ "${last}" = ")" ] ; then check_jail_validity - validate_rdr_rule $RDR_IF $RDR_SRC $RDR_DST $1 $2 $3 - persist_rdr_log_rule $RDR_INET $RDR_IF $RDR_SRC $RDR_DST $proto $host_port $jail_port "$@" - load_rdr_log_rule $RDR_INET $RDR_IF $RDR_SRC $RDR_DST $proto $host_port $jail_port "$@" + validate_rdr_rule "$RDR_IF" $RDR_SRC $RDR_DST $1 $2 $3 + persist_rdr_log_rule $RDR_INET "$RDR_IF" $RDR_SRC $RDR_DST $proto $host_port $jail_port "$@" + load_rdr_log_rule $RDR_INET "$RDR_IF" $RDR_SRC $RDR_DST $proto $host_port $jail_port "$@" shift $# else usage fi elif [ $# -eq 1 ]; then check_jail_validity - validate_rdr_rule $RDR_IF $RDR_SRC $RDR_DST $1 $2 $3 - persist_rdr_log_rule $RDR_INET $RDR_IF $RDR_SRC $RDR_DST $proto $host_port $jail_port "$@" - load_rdr_log_rule $RDR_INET $RDR_IF $RDR_SRC $RDR_DST $proto $host_port $jail_port "$@" + validate_rdr_rule "$RDR_IF" $RDR_SRC $RDR_DST $1 $2 $3 + persist_rdr_log_rule $RDR_INET "$RDR_IF" $RDR_SRC $RDR_DST $proto $host_port $jail_port "$@" + load_rdr_log_rule $RDR_INET "$RDR_IF" $RDR_SRC $RDR_DST $proto $host_port $jail_port "$@" shift 1 else usage @@ -409,21 +420,23 @@ while [ "$#" -gt 0 ]; do esac fi ;; + *) + if [ "${1}" = "dual" ] || [ "${1}" = "ipv4" ] || [ "${1}" = "ipv6" ]; then RDR_INET="${1}" - else + else usage fi if [ "$#" -eq 7 ] && { [ "${5}" = "tcp" ] || [ "${5}" = "udp" ]; } then check_jail_validity - validate_rdr_rule $RDR_IF $RDR_SRC $RDR_DST $1 $2 $3 + validate_rdr_rule "$RDR_IF" $RDR_SRC $RDR_DST $1 $2 $3 persist_rdr_rule "$@" load_rdr_rule "$@" shift "$#" elif [ "$#" -ge 8 ] && [ "${8}" = "log" ]; then check_jail_validity - validate_rdr_rule $RDR_IF $RDR_SRC $RDR_DST $1 $2 $3 + validate_rdr_rule "$RDR_IF" $RDR_SRC $RDR_DST $1 $2 $3 persist_rdr_log_rule "$@" load_rdr_log_rule "$@" shift "$#" diff --git a/usr/local/share/bastille/rename.sh b/usr/local/share/bastille/rename.sh index c5fe4beb..094179d9 100644 --- a/usr/local/share/bastille/rename.sh +++ b/usr/local/share/bastille/rename.sh @@ -53,7 +53,7 @@ while [ "$#" -gt 0 ]; do AUTO=1 shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; @@ -93,7 +93,9 @@ validate_name() { local NAME_VERIFY="${NEWNAME}" local NAME_SANITY="$(echo "${NAME_VERIFY}" | tr -c -d 'a-zA-Z0-9-_')" - if [ -n "$(echo "${NAME_SANITY}" | awk "/^[-_].*$/" )" ]; then + if echo "${NAME_VERIFY}" | grep -q "[.]"; then + error_exit "[ERROR]: Jail names may not contain a dot(.)!" + elif [ -n "$(echo "${NAME_SANITY}" | awk "/^[-_].*$/" )" ]; then error_exit "[ERROR]: Jail names may not begin with (-|_) characters!" elif [ "${NAME_VERIFY}" != "${NAME_SANITY}" ]; then error_exit "[ERROR]: Jail names may not contain special characters!" @@ -103,18 +105,18 @@ validate_name() { update_jailconf() { # Update jail.conf - local _jail_conf="${bastille_jailsdir}/${NEWNAME}/jail.conf" - local _rc_conf="${bastille_jailsdir}/${NEWNAME}/root/etc/rc.conf" + local jail_conf="${bastille_jailsdir}/${NEWNAME}/jail.conf" + local jail_rc_conf="${bastille_jailsdir}/${NEWNAME}/root/etc/rc.conf" - if [ -f "${_jail_conf}" ]; then - if ! grep -qw "path = ${bastille_jailsdir}/${NEWNAME}/root;" "${_jail_conf}"; then - sed -i '' "s|host.hostname.*=.*${TARGET};|host.hostname = ${NEWNAME};|" "${_jail_conf}" - sed -i '' "s|exec.consolelog.*=.*;|exec.consolelog = ${bastille_logsdir}/${NEWNAME}_console.log;|" "${_jail_conf}" - sed -i '' "s|path.*=.*;|path = ${bastille_jailsdir}/${NEWNAME}/root;|" "${_jail_conf}" - sed -i '' "s|mount.fstab.*=.*;|mount.fstab = ${bastille_jailsdir}/${NEWNAME}/fstab;|" "${_jail_conf}" - sed -i '' "s|^${TARGET}.*{$|${NEWNAME} {|" "${_jail_conf}" + if [ -f "${jail_conf}" ]; then + if ! grep -qw "path = ${bastille_jailsdir}/${NEWNAME}/root;" "${jail_conf}"; then + sed -i '' "s|host.hostname.*=.*${TARGET};|host.hostname = ${NEWNAME};|" "${jail_conf}" + sed -i '' "s|exec.consolelog.*=.*;|exec.consolelog = ${bastille_logsdir}/${NEWNAME}_console.log;|" "${jail_conf}" + sed -i '' "s|path.*=.*;|path = ${bastille_jailsdir}/${NEWNAME}/root;|" "${jail_conf}" + sed -i '' "s|mount.fstab.*=.*;|mount.fstab = ${bastille_jailsdir}/${NEWNAME}/fstab;|" "${jail_conf}" + sed -i '' "s|^${TARGET}.*{$|${NEWNAME} {|" "${jail_conf}" fi - if grep -qo "vnet;" "${_jail_conf}"; then + if grep -qo "vnet;" "${jail_conf}"; then update_jailconf_vnet fi fi @@ -122,108 +124,107 @@ update_jailconf() { update_jailconf_vnet() { - local _jail_conf="${bastille_jailsdir}/${NEWNAME}/jail.conf" - local _rc_conf="${bastille_jailsdir}/${NEWNAME}/root/etc/rc.conf" + local jail_conf="${bastille_jailsdir}/${NEWNAME}/jail.conf" + local jail_rc_conf="${bastille_jailsdir}/${NEWNAME}/root/etc/rc.conf" - # Change bastille interface name (only needed for bridged epairs) - # We still gather interface names for JIB and JNG managed interfaces (for future use) if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then - local _if_list="$(grep -Eo 'e[0-9]+a_[^;" ]+' ${_jail_conf} | sort -u)" + local if_list="$(grep -Eo 'e[0-9]+a_[^;" ]+' ${jail_conf} | sort -u)" elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then - local _if_list="$(grep -Eo 'ng[0-9]+_[^;" ]+' ${_jail_conf} | sort -u)" + local if_list="$(grep -Eo 'ng[0-9]+_[^;" ]+' ${jail_conf} | sort -u)" fi - for _if in ${_if_list}; do + for if in ${if_list}; do - local _old_if_prefix="$(echo ${_if} | awk -F'_' '{print $1}')" - local _old_if_suffix="$(echo ${_if} | awk -F'_' '{print $2}')" + local old_if_prefix="$(echo ${if} | awk -F'_' '{print $1}')" + local old_if_suffix="$(echo ${if} | awk -F'_' '{print $2}')" # For if_bridge network type if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then - local _epair_num="$(echo "${_old_if_prefix}" | grep -Eo "[0-9]+")" - local _old_host_epair="${_if}" - local _old_jail_epair="${_old_if_prefix%a}b_${_old_if_suffix}" + local epair_num="$(echo "${old_if_prefix}" | grep -Eo "[0-9]+")" + local old_host_epair="${if}" + local old_jail_epair="${old_if_prefix%a}b_${old_if_suffix}" - if [ "$(echo -n "e${_epair_num}a_${NEWNAME}" | awk '{print length}')" -lt 16 ]; then + if [ "$(echo -n "e${epair_num}a_${NEWNAME}" | awk '{print length}')" -lt 16 ]; then # Generate new epair name - local _new_host_epair="e${_epair_num}a_${NEWNAME}" - local _new_jail_epair="e${_epair_num}b_${NEWNAME}" + local new_host_epair="e${epair_num}a_${NEWNAME}" + local new_jail_epair="e${epair_num}b_${NEWNAME}" else - name_prefix="$(echo ${NEWNAME} | cut -c1-7)" - name_suffix="$(echo ${NEWNAME} | rev | cut -c1-2 | rev)" - local _new_host_epair="e${_epair_num}a_${name_prefix}xx${name_suffix}" - local _new_jail_epair="e${_epair_num}b_${name_prefix}xx${name_suffix}" + if echo "${old_if_suffix}" | grep -Eosq "bastille[0-9]+"; then + local new_host_epair="e${epair_num}a_${old_if_suffix}" + local new_jail_epair="e${epair_num}b_${old_if_suffix}" + else + get_bastille_epair_count + local bastille_epair_num=1 + while echo "${BASTILLE_EPAIR_LIST}" | grep -oq "bastille${bastille_epair_num}"; do + bastille_epair_num=$((bastille_epair_num + 1)) + done + local new_host_epair="e${epair_num}a_bastille${bastille_epair_num}" + local new_jail_epair="e${epair_num}b_bastille${bastille_epair_num}" + fi fi - local _new_if_prefix="$(echo ${_new_host_epair} | awk -F'_' '{print $1}')" - local _new_if_suffix="$(echo ${_new_host_epair} | awk -F'_' '{print $2}')" + local new_if_prefix="$(echo ${new_host_epair} | awk -F'_' '{print $1}')" + local new_if_suffix="$(echo ${new_host_epair} | awk -F'_' '{print $2}')" - if grep "${_old_if_suffix}" "${_jail_conf}" | grep -oq "jib addm"; then + if grep "${old_if_suffix}" "${jail_conf}" | grep -oq "jib addm"; then # For -V jails - # Replace host epair name in jail.conf - sed -i '' "s|jib addm ${_old_if_suffix}|jib addm ${_new_if_suffix}|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} ether|${_new_host_epair} ether|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} destroy|${_new_host_epair} destroy|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} description|${_new_host_epair} description|g" "${_jail_conf}" + # Replace host epair name in jail.conf + sed -i '' "s|jib addm ${old_if_suffix}\>|jib addm ${new_if_suffix}|g" "${jail_conf}" + sed -i '' "s|\<${old_host_epair} ether|${new_host_epair} ether|g" "${jail_conf}" + sed -i '' "s|\<${old_host_epair} destroy|${new_host_epair} destroy|g" "${jail_conf}" + sed -i '' "s|\<${old_host_epair} description|${new_host_epair} description|g" "${jail_conf}" # Replace jail epair name in jail.conf - sed -i '' "s|= ${_old_jail_epair};|= ${_new_jail_epair};|g" "${_jail_conf}" - sed -i '' "s|${_old_jail_epair} ether|${_new_jail_epair} ether|g" "${_jail_conf}" + sed -i '' "s|= ${old_jail_epair};|= ${new_jail_epair};|g" "${jail_conf}" + sed -i '' "s|\<${old_jail_epair} ether|${new_jail_epair} ether|g" "${jail_conf}" # Replace epair description - sed -i '' "s|host interface for Bastille jail ${TARGET}|host interface for Bastille jail ${NEWNAME}|g" "${_jail_conf}" + sed -i '' "s|host interface for Bastille jail ${TARGET}\>|host interface for Bastille jail ${NEWNAME}|g" "${jail_conf}" # Replace epair name in /etc/rc.conf - sed -i '' "/ifconfig/ s|${_old_jail_epair}|${_new_jail_epair}|g" "${_rc_conf}" + sed -i '' "s|ifconfig_${old_jail_epair}_name|ifconfig_${new_jail_epair}_name|g" "${jail_rc_conf}" else # For -B jails - # Replace host epair name in jail.conf - sed -i '' "s|up name ${_old_host_epair}|up name ${_new_host_epair}|g" "${_jail_conf}" - sed -i '' "s|addm ${_old_host_epair}|addm ${_new_host_epair}|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} ether|${_new_host_epair} ether|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} destroy|${_new_host_epair} destroy|g" "${_jail_conf}" - sed -i '' "s|${_old_host_epair} description|${_new_host_epair} description|g" "${_jail_conf}" + # Replace host epair name in jail.conf + sed -i '' "s|up name ${old_host_epair}\>|up name ${new_host_epair}|g" "${jail_conf}" + sed -i '' "s|addm ${old_host_epair}\>|addm ${new_host_epair}|g" "${jail_conf}" + sed -i '' "s|\<${old_host_epair} ether|${new_host_epair} ether|g" "${jail_conf}" + sed -i '' "s|\<${old_host_epair} destroy|${new_host_epair} destroy|g" "${jail_conf}" + sed -i '' "s|\<${old_host_epair} description|${new_host_epair} description|g" "${jail_conf}" # Replace jail epair name in jail.conf - sed -i '' "s|= ${_old_jail_epair};|= ${_new_jail_epair};|g" "${_jail_conf}" - sed -i '' "s|up name ${_old_jail_epair}|up name ${_new_jail_epair}|g" "${_jail_conf}" - sed -i '' "s|${_old_jail_epair} ether|${_new_jail_epair} ether|g" "${_jail_conf}" + sed -i '' "s|= ${old_jail_epair};|= ${new_jail_epair};|g" "${jail_conf}" + sed -i '' "s|up name ${old_jail_epair}\>|up name ${new_jail_epair}|g" "${jail_conf}" + sed -i '' "s|\<${old_jail_epair} ether|${new_jail_epair} ether|g" "${jail_conf}" # Replace epair description - sed -i '' "s|host interface for Bastille jail ${TARGET}|host interface for Bastille jail ${NEWNAME}|g" "${_jail_conf}" + sed -i '' "s|host interface for Bastille jail ${TARGET}\>|host interface for Bastille jail ${NEWNAME}|g" "${jail_conf}" # Replace epair name in /etc/rc.conf - sed -i '' "/ifconfig/ s|${_old_jail_epair}|${_new_jail_epair}|g" "${_rc_conf}" + sed -i '' "s|ifconfig_${old_jail_epair}_name|ifconfig_${new_jail_epair}_name|g" "${jail_rc_conf}" fi # For netgraph network type elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then - - local _ngif_num="$(echo "${_old_if_prefix}" | grep -Eo "[0-9]+")" - local _old_ngif="${_if}" - if [ "$(echo -n "ng${_ngif_num}_${NEWNAME}" | awk '{print length}')" -lt 16 ]; then - # Generate new netgraph interface name - local _new_ngif="ng${_ngif_num}_${NEWNAME}" - else - name_prefix="$(echo ${NEWNAME} | cut -c1-7)" - name_suffix="$(echo ${NEWNAME} | rev | cut -c1-2 | rev)" - local _new_ngif="ng${_ngif_num}_${name_prefix}xx${name_suffix}" - fi + local ngif_num="$(echo "${old_if_prefix}" | grep -Eo "[0-9]+")" + local old_ngif="${if}" + # Generate new netgraph interface name + local new_ngif="ng${ngif_num}_${NEWNAME}" + # shellcheck disable=SC2034 + local new_if_prefix="$(echo ${new_ngif} | awk -F'_' '{print $1}')" + local new_if_suffix="$(echo ${new_ngif} | awk -F'_' '{print $2}')" - local _new_if_prefix="$(echo ${_if} | awk -F'_' '{print $1}')" - local _new_if_suffix="$(echo ${_if} | awk -F'_' '{print $2}')" - - # Replace netgraph interface name - sed -i '' "s|jng bridge ${_old_if_suffix}|jng bridge ${_new_if_suffix}|g" "${_jail_conf}" - sed -i '' "s|${_old_ngif} ether|${_new_ngif} ether|g" "${_jail_conf}" - sed -i '' "s|jng shutdown ${_old_if_suffix}|jng shutdown ${_new_if_suffix}|g" "${_jail_conf}" + # Replace netgraph interface name + sed -i '' "s|jng bridge ${old_if_suffix}\>|jng bridge ${new_if_suffix}|g" "${jail_conf}" + sed -i '' "s|\<${old_ngif} ether|${new_ngif} ether|g" "${jail_conf}" + sed -i '' "s|jng shutdown ${old_if_suffix}\>|jng shutdown ${new_if_suffix}|g" "${jail_conf}" # Replace jail epair name in jail.conf - sed -i '' "s|= ${_old_ngif};|= ${_new_ngif};|g" "${_jail_conf}" + sed -i '' "s|= ${old_ngif};|= ${new_ngif};|g" "${jail_conf}" # Replace epair name in /etc/rc.conf - sed -i '' "/ifconfig/ s|${_old_ngif}|${_new_ngif}|g" "${_rc_conf}" + sed -i '' "s|ifconfig_${old_ngif}_name|ifconfig_${new_ngif}_name|g" "${jail_rc_conf}" fi done } diff --git a/usr/local/share/bastille/restart.sh b/usr/local/share/bastille/restart.sh index dc1aed1b..771a092a 100644 --- a/usr/local/share/bastille/restart.sh +++ b/usr/local/share/bastille/restart.sh @@ -35,13 +35,14 @@ usage() { error_notify "Usage: bastille restart [option(s)] TARGET" cat << EOF - + Options: - -b | --boot Respect jail boot setting. - -d | --delay VALUE Time (seconds) to wait after starting each jail. - -v | --verbose Print every action on jail start. - -x | --debug Enable debug mode. + -b | --boot Respect jail boot setting. + -d | --delay VALUE Time (seconds) to wait after starting each jail. + -i | --ignore Ignore stopped jails (do not start if stopped). + -v | --verbose Print every action on jail start. + -x | --debug Enable debug mode. EOF exit 1 @@ -51,6 +52,7 @@ EOF # We pass these to start and stop. _start_options="" _stop_options="" +IGNORE=0 while [ "$#" -gt 0 ]; do case "${1}" in -h|--help|help) @@ -64,6 +66,10 @@ while [ "$#" -gt 0 ]; do _start_options="${_start_options} -d ${2}" shift 2 ;; + -i|--ignore) + IGNORE=1 + shift + ;; -v|--verbose) _start_options="${_start_options} -v" _stop_options="${_stop_options} -v" @@ -74,23 +80,14 @@ while [ "$#" -gt 0 ]; do _stop_options="${_stop_options} -x" shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in - b) - _start_options="${_start_options} -b" - ;; - v) - _start_options="${_start_options} -v" - _stop_options="${_stop_options} -v" - ;; - x) - _start_options="${_start_options} -x" - _stop_options="${_stop_options} -x" - ;; - *) - error_exit "[ERROR]: Unknown Option: \"${1}\"" - ;; + b) _start_options="${_start_options} -b" ;; + i) IGNORE=1 ;; + v) _start_options="${_start_options} -v" _stop_options="${_stop_options} -v" ;; + x) _start_options="${_start_options} -x" _stop_options="${_stop_options} -x" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -112,17 +109,15 @@ set_target "${TARGET}" for _jail in ${JAILS}; do - ( - - # Only restart running jails - if check_target_is_running "${_jail}"; then + # Restart all jails except if --ignore + if [ "${IGNORE}" -eq 0 ]; then bastille stop ${_stop_options} ${_jail} bastille start ${_start_options} ${_jail} + elif [ "${IGNORE}" -eq 1 ]; then + if check_target_is_stopped "${_jail}"; then + info "\n[${_jail}]:" + error_continue "Jail is stopped." + fi fi - ) & - - bastille_running_jobs "${bastille_process_limit}" - -done -wait \ No newline at end of file +done \ No newline at end of file diff --git a/usr/local/share/bastille/service.sh b/usr/local/share/bastille/service.sh index b2988066..ee1c9632 100644 --- a/usr/local/share/bastille/service.sh +++ b/usr/local/share/bastille/service.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille service [option(s)] TARGET SERVICE_NAME ARGS" cat << EOF - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. @@ -60,12 +60,12 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -82,9 +82,7 @@ fi TARGET="${1}" shift -# Use mktemp to store exit codes -export TMP_BASTILLE_EXIT_CODE="$(mktemp)" -echo 0 > "${TMP_BASTILLE_EXIT_CODE}" +ERRORS=0 bastille_root_check set_target "${TARGET}" @@ -101,12 +99,15 @@ for _jail in ${JAILS}; do fi info "\n[${_jail}]:" - + jexec -l "${_jail}" /usr/sbin/service "$@" - bastille_check_exit_code "${_jail}" "$?" - -done -echo + if [ "$?" -ne 0 ]; then + ERRORS=$((ERRORS + 1)) + fi -bastille_return_exit_code +done + +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi \ No newline at end of file diff --git a/usr/local/share/bastille/setup.sh b/usr/local/share/bastille/setup.sh index 07218e09..03dda2cb 100644 --- a/usr/local/share/bastille/setup.sh +++ b/usr/local/share/bastille/setup.sh @@ -34,17 +34,19 @@ usage() { error_notify "Usage: bastille setup [option(s)] [bridge]" + error_notify " [linux]" error_notify " [loopback]" + error_notify " [netgraph]" error_notify " [pf|firewall]" error_notify " [shared]" - error_notify " [vnet]" error_notify " [storage]" + error_notify " [vnet]" cat << EOF - + Options: - -y | --yes Assume always yes on prompts. - -x | --debug Enable debug mode. + -y | --yes Assume always yes on prompts. + -x | --debug Enable debug mode. EOF exit 1 @@ -65,7 +67,7 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in y) AUTO_YES=1 ;; @@ -91,31 +93,93 @@ OPT_ARG="${2}" bastille_root_check +configure_linux() { + + if ! kldstat -qn linux || \ + ! kldstat -qn linux64 || \ + ! kldstat -qm fdescfs || \ + ! kldstat -qm linprocfs || \ + ! kldstat -qm linsysfs || \ + ! kldstat -qm tmpfs; then + + local required_mods="fdescfs linprocfs linsysfs tmpfs" + local linuxarc_mods="linux linux64" + + # Enable required modules + for mod in ${required_mods}; do + if ! kldstat -qm ${mod}; then + if [ ! "$(sysrc -f /boot/loader.conf -qn ${mod}_load)" = "YES" ] && [ ! "$(sysrc -f /boot/loader.conf.local -qn ${mod}_load)" = "YES" ]; then + info "\nLoading kernel module: ${mod}" + kldload ${mod} + info "\nPersisting module: ${mod}" + sysrc -f /boot/loader.conf ${mod}_load=YES + else + info "\nLoading kernel module: ${mod}" + kldload ${mod} + fi + fi + done + + # Mandatory Linux modules/rc. + for mod in ${linuxarc_mods}; do + if ! kldstat -qn ${mod}; then + info "\nLoading kernel module: ${mod}" + kldload ${mod} + fi + done + + # Enable linux + if [ ! "$(sysrc -qn linux_enable)" = "YES" ] && [ ! "$(sysrc -f /etc/rc.conf.local -qn linux_enable)" = "YES" ]; then + sysrc linux_enable=YES + fi + + # Install debootstrap package + if ! which -s debootstrap; then + pkg install -y debootstrap + fi + + info "\nLinux has been successfully configured!" + + else + info "\nLinux has already been configured!" + fi +} + # Configure netgraph configure_netgraph() { - if [ ! "$(kldstat -m netgraph)" ]; then + + if ! kldstat -qm netgraph || \ + ! kldstat -qm ng_netflow || \ + ! kldstat -qm ng_ksocket || \ + ! kldstat -qm ng_ether || \ + ! kldstat -qm ng_bridge || \ + ! kldstat -qm ng_eiface || \ + ! kldstat -qm ng_socket; then + # Ensure jib script is in place for VNET jails if [ ! "$(command -v jng)" ]; then - if [ -f /usr/share/examples/jails/jng ] && [ ! -f /usr/local/bin/jng ]; then + if [ -f "/usr/share/examples/jails/jng" ] && [ ! -f "/usr/local/bin/jng" ]; then install -m 0544 /usr/share/examples/jails/jng /usr/local/bin/jng fi fi - sysrc -f "${BASTILLE_CONFIG}" bastille_network_vnet_type="netgraph" + + local required_mods="netgraph ng_netflow ng_ksocket ng_ether ng_bridge ng_eiface ng_socket" + info "\nConfiguring netgraph modules..." - kldload netgraph - kldload ng_netflow - kldload ng_ksocket - kldload ng_ether - kldload ng_bridge - kldload ng_eiface - kldload ng_socket - sysrc -f /boot/loader.conf netgraph_load="YES" - sysrc -f /boot/loader.conf ng_netflow_load="YES" - sysrc -f /boot/loader.conf ng_ksocket_load="YES" - sysrc -f /boot/loader.conf ng_ether_load="YES" - sysrc -f /boot/loader.conf ng_bridge_load="YES" - sysrc -f /boot/loader.conf ng_eiface_load="YES" - sysrc -f /boot/loader.conf ng_socket_load="YES" + + # Load requried netgraph kernel modules + for mod in ${required_mods}; do + if ! kldstat -qm ${mod}; then + info "\nLoading kernel module: ${mod}" + kldload -v ${mod} + info "\nPersisting module: ${mod}" + sysrc -f /boot/loader.conf ${mod}_load=YES + fi + done + + # Set bastille_network_vnet_type to netgraph + sysrc -f "${BASTILLE_CONFIG}" bastille_network_vnet_type="netgraph" + info "\nNetgraph has been successfully configured!" else info "\nNetgraph has already been configured!" @@ -212,6 +276,7 @@ configure_bridge() { else _interface_select="${_auto_if}" fi + # Create bridge and persist on reboot _bridge_name="${_interface_select}bridge" ifconfig bridge0 create @@ -221,6 +286,17 @@ configure_bridge() { sysrc ifconfig_bridge0_name="${_bridge_name}" sysrc ifconfig_${_bridge_name}="addm ${_interface_select} up" + # Set some sysctl values + sysctl net.inet.ip.forwarding=1 + sysctl net.link.bridge.pfil_bridge=0 + sysctl net.link.bridge.pfil_onlyip=0 + sysctl net.link.bridge.pfil_member=0 + echo net.inet.ip.forwarding=1 >> /etc/sysctl.conf + echo net.link.bridge.pfil_bridge=0 >> /etc/sysctl.conf + echo net.link.bridge.pfil_onlyip=0 >> /etc/sysctl.conf + echo net.link.bridge.pfil_member=0 >> /etc/sysctl.conf + + info "\nBridge interface successfully configured: [${_bridge_name}]" else info "\nBridge has alread been configured: [${_bridge_name}]" @@ -228,14 +304,24 @@ configure_bridge() { } configure_vnet() { - # Ensure jib script is in place for VNET jails - if [ ! "$(command -v jib)" ]; then - if [ -f /usr/share/examples/jails/jib ] && [ ! -f /usr/local/bin/jib ]; then - install -m 0544 /usr/share/examples/jails/jib /usr/local/bin/jib + + # Ensure proper jail helper script + if [ "${bastille_network_vnet_type}" = "if_bridge" ]; then + if [ ! "$(command -v jib)" ]; then + if [ -f "/usr/share/examples/jails/jib" ] && [ ! -f "/usr/local/bin/jib" ]; then + install -m 0544 /usr/share/examples/jails/jib /usr/local/bin/jib + fi + fi + elif [ "${bastille_network_vnet_type}" = "netgraph" ]; then + if [ ! "$(command -v jng)" ]; then + if [ -f "/usr/share/examples/jails/jng" ] && [ ! -f "/usr/local/bin/jng" ]; then + install -m 0544 /usr/share/examples/jails/jng /usr/local/bin/jng + fi fi fi + # Create default VNET ruleset - if [ ! -f /etc/devfs.rules ] || ! grep -oq "bastille_vnet=13" /etc/devfs.rules; then + if [ ! -f "/etc/devfs.rules" ] || ! grep -oq "bastille_vnet=13" /etc/devfs.rules; then info "\nCreating bastille_vnet devfs.rules" cat << EOF > /etc/devfs.rules [bastille_vnet=13] @@ -277,7 +363,7 @@ rdr-anchor "rdr/*" block in all pass out quick keep state antispoof for \$ext_if inet -pass in inet proto tcp from any to any port ssh flags S/SA keep state +pass in proto tcp from any to any port ssh flags S/SA keep state EOF sysrc pf_enable=YES warn "pf ruleset created, please review ${bastille_pf_conf} and enable it using 'service pf start'." @@ -344,6 +430,27 @@ case "${OPT_CONFIG}" in pf|firewall) configure_pf ;; + linux) + if [ "${AUTO_YES}" -eq 1 ]; then + configure_linux + else + warn "[WARNING]: Running linux jails requires loading additional kernel" + warn "modules, as well as installing the 'debootstrap' package." + # shellcheck disable=SC3045 + read -p "Do you want to proceed with setup? [y|n]:" _answer + case "${_answer}" in + [Yy]|[Yy][Ee][Ss]) + configure_linux + ;; + [Nn]|[Nn][Oo]) + error_exit "Linux setup cancelled." + ;; + *) + error_exit "Invalid selection. Please answer 'y' or 'n'" + ;; + esac + fi + ;; netgraph) if [ "${AUTO_YES}" -eq 1 ]; then configure_vnet diff --git a/usr/local/share/bastille/start.sh b/usr/local/share/bastille/start.sh index 93805d99..cee7f5a9 100644 --- a/usr/local/share/bastille/start.sh +++ b/usr/local/share/bastille/start.sh @@ -38,7 +38,7 @@ usage() { Options: - -b | --boot Respect jail boot setting. + -b | --boot Respect jail boot setting. -d | --delay VALUE Time (seconds) to wait after starting each jail. -v | --verbose Print every action on jail start. -x | --debug Enable debug mode. @@ -76,13 +76,13 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in b) BOOT=1 ;; v) OPTION="-v" ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -104,8 +104,6 @@ set_target "${TARGET}" for _jail in ${JAILS}; do - ( - # Continue if '-b|--boot' is set and 'boot=off' if [ "${BOOT}" -eq 1 ]; then BOOT_ENABLED="$(sysrc -f ${bastille_jailsdir}/${_jail}/settings.conf -n boot)" @@ -123,14 +121,14 @@ for _jail in ${JAILS}; do bastille start ${_depend_jail} fi done - + if check_target_is_running "${_jail}"; then info "\n[${_jail}]:" error_continue "Jail is already running." fi info "\n[${_jail}]:" - + # Validate interfaces and add IPs to firewall table if [ "$(bastille config ${_jail} get vnet)" != 'enabled' ]; then _ip4_interfaces="$(bastille config ${_jail} get ip4.addr | sed 's/,/ /g')" @@ -183,19 +181,20 @@ for _jail in ${JAILS}; do fi fi - # Start jail - jail ${OPTION} -f "${bastille_jailsdir}/${_jail}/jail.conf" -c "${_jail}" - - # Add ZFS jailed datasets + # Validate jailed datasets mountpoint if [ -s "${bastille_jailsdir}/${_jail}/zfs.conf" ]; then - while read _dataset _mount; do - zfs set jailed=on "${_dataset}" - zfs jail ${_jail} "${_dataset}" - jexec -l -U root "${_jail}" zfs set mountpoint="${_mount}" "${_dataset}" - jexec -l -U root "${_jail}" zfs mount "${_dataset}" 2>/dev/null + while read dataset mount; do + if [ "$(zfs get -H -o value mountpoint ${dataset})" != "${mount}" ]; then + zfs set jailed=off "${dataset}" + zfs set mountpoint="${mount}" "${dataset}" + zfs set jailed=on "${dataset}" + fi done < "${bastille_jailsdir}/${_jail}/zfs.conf" fi + # Start jail + jail ${OPTION} -f "${bastille_jailsdir}/${_jail}/jail.conf" -c "${_jail}" + # Add rctl limits if [ -s "${bastille_jailsdir}/${_jail}/rctl.conf" ]; then while read _limits; do @@ -220,9 +219,4 @@ for _jail in ${JAILS}; do # Delay between jail action sleep "${DELAY_TIME}" - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait \ No newline at end of file diff --git a/usr/local/share/bastille/stop.sh b/usr/local/share/bastille/stop.sh index 09707da9..e6b26580 100644 --- a/usr/local/share/bastille/stop.sh +++ b/usr/local/share/bastille/stop.sh @@ -60,12 +60,12 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in v) OPTION="-v" ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -87,10 +87,8 @@ set_target "${TARGET}" "reverse" for _jail in ${JAILS}; do - ( - # Validate that all jails that 'depend' on this one are stopped - for _depend_jail in $(ls --color=never ${bastille_jailsdir} | sed -e 's/\n//g'); do + for _depend_jail in $(ls -v --color=never ${bastille_jailsdir} | sed -e 's/\n//g'); do if ! grep -hoqsw "depend=" ${bastille_jailsdir}/${_depend_jail}/settings.conf; then sysrc -q -f ${bastille_jailsdir}/${_depend_jail}/settings.conf depend="" >/dev/null fi @@ -105,7 +103,7 @@ for _jail in ${JAILS}; do info "\n[${_jail}]:" error_continue "Jail is already stopped." fi - + info "\n[${_jail}]:" # Remove RDR rules @@ -114,7 +112,7 @@ for _jail in ${JAILS}; do _ip6="$(bastille config ${_jail} get ip6.addr | sed 's/,/ /g')" if [ "${_ip4}" != "not set" ] || [ "${_ip6}" != "not set" ]; then if which -s pfctl; then - if [ "$(bastille rdr ${_jail} list)" ]; then + if bastille rdr ${_jail} list >/dev/null 2>&1; then bastille rdr "${_jail}" clear fi fi @@ -126,14 +124,6 @@ for _jail in ${JAILS}; do bastille limits "${_jail}" clear fi - # Unmount any jailed ZFS datasets - if [ -s "${bastille_jailsdir}/${_jail}/zfs.conf" ]; then - while read _dataset _mount; do - jexec -l -U root "${_jail}" zfs umount "${_dataset}" - zfs unjail "${_jail}" "${_dataset}" - done < "${bastille_jailsdir}/${_jail}/zfs.conf" - fi - # Stop jail jail ${OPTION} -f "${bastille_jailsdir}/${_jail}/jail.conf" -r "${_jail}" @@ -155,15 +145,10 @@ for _jail in ${JAILS}; do else _ip="$(echo ${_ip} | sed -E 's#/[0-9]+$##g')" fi - pfctl -q -t "${bastille_network_pf_table}" -T delete "${_ip}" + pfctl -q -t "${bastille_network_pf_table}" -T delete "${_ip}" done fi update_jail_syntax_v1 "${_jail}" - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait diff --git a/usr/local/share/bastille/sysrc.sh b/usr/local/share/bastille/sysrc.sh index 72e1bafd..da7e0f74 100644 --- a/usr/local/share/bastille/sysrc.sh +++ b/usr/local/share/bastille/sysrc.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille sysrc [option(s)] TARGET ARGS" cat << EOF - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. @@ -60,12 +60,12 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -82,17 +82,13 @@ fi TARGET="${1}" shift -# Use mktemp to store exit codes -export TMP_BASTILLE_EXIT_CODE="$(mktemp)" -echo 0 > "${TMP_BASTILLE_EXIT_CODE}" +ERRORS=0 bastille_root_check set_target "${TARGET}" for _jail in ${JAILS}; do - ( - # Validate jail state check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then bastille start "${_jail}" @@ -103,17 +99,15 @@ for _jail in ${JAILS}; do fi info "\n[${_jail}]:" - + jexec -l "${_jail}" /usr/sbin/sysrc "$@" - bastille_check_exit_code "${_jail}" "$?" + if [ "$?" -ne 0 ]; then + ERRORS=$((ERRORS + 1)) + fi - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait -echo -bastille_return_exit_code +if [ "${ERRORS}" -ne 0 ]; then + error_exit "[ERROR]: Command failed on ${ERRORS} jails." +fi \ No newline at end of file diff --git a/usr/local/share/bastille/tags.sh b/usr/local/share/bastille/tags.sh index 1f4d7cf8..7c6423d8 100644 --- a/usr/local/share/bastille/tags.sh +++ b/usr/local/share/bastille/tags.sh @@ -77,8 +77,6 @@ set_target "${TARGET}" for _jail in ${JAILS}; do - ( - bastille_jail_tags="${bastille_jailsdir}/${_jail}/tags" case ${ACTION} in add) @@ -120,9 +118,4 @@ for _jail in ${JAILS}; do ;; esac - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait diff --git a/usr/local/share/bastille/template.sh b/usr/local/share/bastille/template.sh index f3a40cf1..6f796c43 100644 --- a/usr/local/share/bastille/template.sh +++ b/usr/local/share/bastille/template.sh @@ -117,15 +117,18 @@ render() { } line_in_file() { - _jailpath="${1}" - _filepath="$(echo ${2} | awk '{print $2}')" - _line="$(echo ${2} | awk '{print $1}')" - if [ -f "${_jailpath}/${_filepath}" ]; then - if ! grep -qxF "${_line}" "${_jailpath}/${_filepath}"; then - echo "${_line}" >> "${_jailpath}/${_filepath}" + + local jail_path="${1}" + eval set -- "${2}" + local line="${1}" + local file_path="${2}" + + if [ -f "${jail_path}/${file_path}" ]; then + if ! grep -qxF "${line}" "${jail_path}/${file_path}"; then + echo "${line}" >> "${jail_path}/${file_path}" fi else - warn "[WARNING]: Path not found for line_in_file: ${_filepath}" + warn "[WARNING]: Path not found for line_in_file: ${file_path}" fi } @@ -144,12 +147,12 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -272,8 +275,6 @@ fi for _jail in ${JAILS}; do - ( - check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then bastille start "${_jail}" else @@ -283,7 +284,7 @@ for _jail in ${JAILS}; do fi info "\n[${_jail}]:" - + echo "Applying template: ${TEMPLATE}..." ## get jail ip4 and ip6 values @@ -313,7 +314,7 @@ for _jail in ${JAILS}; do { [ "${_jail_ip6}" = "not set" ] || [ "${_jail_ip6}" = "disable" ]; } then error_notify "Jail IP not found: ${_jail}" fi - + ## TARGET if [ -s "${bastille_template}/TARGET" ]; then if grep -qw "${_jail}" "${bastille_template}/TARGET"; then @@ -473,12 +474,7 @@ for _jail in ${JAILS}; do echo fi done - + info "\nTemplate applied: ${TEMPLATE}" - ) & - - bastille_running_jobs "${bastille_process_limit}" - done -wait diff --git a/usr/local/share/bastille/templates/default/vnet/Bastillefile b/usr/local/share/bastille/templates/default/vnet/Bastillefile index e529380c..f0c4cadb 100644 --- a/usr/local/share/bastille/templates/default/vnet/Bastillefile +++ b/usr/local/share/bastille/templates/default/vnet/Bastillefile @@ -1,14 +1,19 @@ -ARG EPAIR +ARG EXT_INTERFACE +ARG INTERFACE +ARG VNET ARG GATEWAY ARG GATEWAY6 ARG IFCONFIG="SYNCDHCP" ARG IFCONFIG6 -SYSRC ifconfig_${EPAIR}_name=vnet0 -SYSRC ifconfig_vnet0="${IFCONFIG}" +SYSRC ifconfig_${INTERFACE}_name=${VNET} +SYSRC ifconfig_${VNET}="${IFCONFIG}" + +# Set description if EXT_INTERFACE is set +CMD if [ -n "${EXT_INTERFACE}" ]; then /usr/sbin/sysrc ifconfig_${VNET}_descr="jail interface for ${EXT_INTERFACE}"; fi # Apply IFCONFIG6 if set -CMD if [ -n "${IFCONFIG6}" ]; then /usr/sbin/sysrc ifconfig_vnet0_ipv6="${IFCONFIG6}"; fi +CMD if [ -n "${IFCONFIG6}" ]; then /usr/sbin/sysrc ifconfig_${VNET}_ipv6="${IFCONFIG6}"; fi # GATEWAY will be empty for a DHCP config. -- cwells CMD if [ -n "${GATEWAY}" ]; then /usr/sbin/sysrc defaultrouter="${GATEWAY}"; fi diff --git a/usr/local/share/bastille/umount.sh b/usr/local/share/bastille/umount.sh index 37d8d082..4cd7ec1e 100644 --- a/usr/local/share/bastille/umount.sh +++ b/usr/local/share/bastille/umount.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille umount [option(s)] TARGET JAIL_PATH" cat << EOF - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. @@ -88,8 +88,6 @@ set_target "${TARGET}" for _jail in ${JAILS}; do - ( - # Validate jail state check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then bastille start "${_jail}" @@ -98,7 +96,7 @@ for _jail in ${JAILS}; do error_notify "Jail is not running." error_continue "Use [-a|--auto] to auto-start the jail." fi - + info "\n[${_jail}]:" _jailpath="$( echo "${bastille_jailsdir}/${_jail}/root/${MOUNT_PATH}" 2>/dev/null | sed 's#//#/#' | sed 's#\\##g')" @@ -127,12 +125,7 @@ for _jail in ${JAILS}; do if [ -f "${_jailpath}" ]; then rm -f "${_jailpath}" || error_continue "Failed to unmount volume: ${MOUNT_PATH}" fi - + echo "Unmounted: ${_jailpath}" - - ) & - - bastille_running_jobs "${bastille_process_limit}" - -done -wait \ No newline at end of file + +done \ No newline at end of file diff --git a/usr/local/share/bastille/update.sh b/usr/local/share/bastille/update.sh index 902acd7f..29028383 100644 --- a/usr/local/share/bastille/update.sh +++ b/usr/local/share/bastille/update.sh @@ -52,6 +52,10 @@ fi # Handle options. OPTION="" AUTO=0 +PKGBASE=0 +PLATFORM_OS="FreeBSD" +JAIL_PLATFORM_OS="FreeBSD" +RELEASE_PLATFORM_OS="FreeBSD" while [ "$#" -gt 0 ]; do case "${1}" in -h|--help|help) @@ -69,13 +73,13 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; f) OPTION="-F" ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -90,21 +94,6 @@ TARGET="${1}" bastille_root_check -if [ -f "/bin/midnightbsd-version" ]; then - error_exit "[ERROR]: Not yet supported on MidnightBSD." -fi - -if freebsd-version | grep -qi HBSD; then - error_exit "[ERROR]: Not yet supported on HardenedBSD." -fi - -# Check for alternate/unsupported archs -arch_check() { - if echo "${TARGET}" | grep -w "[0-9]\{1,2\}\.[0-9]\-RELEASE\-i386"; then - ARCH_I386="1" - fi -} - jail_check() { # Check if the jail is thick and is running @@ -120,76 +109,276 @@ jail_check() { info "\n[${TARGET}]:" + # Check for thin jail if grep -qw "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then error_notify "[ERROR]: ${TARGET} is not a thick container." error_exit "See 'bastille update RELEASE' to update thin jails." fi + + # Verify PLATFORM_OS inside jail + JAIL_PLATFORM_OS="$( ${bastille_jailsdir}/${TARGET}/root/bin/freebsd-version )" + if echo "${JAIL_PLATFORM_OS}" | grep -q "HBSD"; then + JAIL_PLATFORM_OS="HardenedBSD" + else + JAIL_PLATFORM_OS="FreeBSD" + fi + + # Set CURRENT_VERSION + CURRENT_VERSION=$(/usr/sbin/jexec -l "${TARGET}" freebsd-version 2>/dev/null) + if [ -z "${CURRENT_VERSION}" ]; then + error_exit "[ERROR]: Can't determine '${TARGET}' version." + fi + + # Validate method (Legacy/PkgBase) + if [ "${JAIL_PLATFORM_OS}" = "FreeBSD" ]; then + # Validate update method + MINOR_VERSION=$(echo ${CURRENT_VERSION} | sed -E 's/^[0-9]+\.([0-9]+)-.*$/\1/') + MAJOR_VERSION=$(echo ${CURRENT_VERSION} | grep -Eo '^[0-9]+') + if echo "${CURRENT_VERSION}" | grep -oq "\-CURRENT"; then + FREEBSD_BRANCH="current" + else + FREEBSD_BRANCH="release" + fi + if [ "${MAJOR_VERSION}" -ge 16 ] || pkg -r "${bastille_jailsdir}/${TARGET}/root" which /usr/bin/uname > /dev/null 2>&1; then + PKGBASE=1 + fi + fi } jail_update() { - local _jailname="${1}" - local _jailpath="${bastille_jailsdir}/${TARGET}/root" - local _freebsd_update_conf="${_jailpath}/etc/freebsd-update.conf" - local _workdir="${_jailpath}/var/db/freebsd-update" - # Update a thick container - if [ -d "${bastille_jailsdir}/${TARGET}" ]; then - CURRENT_VERSION=$(/usr/sbin/jexec -l "${TARGET}" freebsd-version 2>/dev/null) - if [ -z "${CURRENT_VERSION}" ]; then - error_exit "[ERROR]: Can't determine '${TARGET}' version." + if [ "${JAIL_PLATFORM_OS}" = "FreeBSD" ]; then + + local jailname="${TARGET}" + local jailpath="${bastille_jailsdir}/${TARGET}/root" + local freebsd_update_conf="${jailpath}/etc/freebsd-update.conf" + local work_dir="${jailpath}/var/db/freebsd-update" + + env PAGER="/bin/cat" freebsd-update ${OPTION} \ + --not-running-from-cron \ + -j "${jailname}" \ + -d "${work_dir}" \ + -f "${freebsd_update_conf}" \ + fetch + + env PAGER="/bin/cat" freebsd-update ${OPTION} \ + --not-running-from-cron \ + -j "${jailname}" \ + -d "${work_dir}" \ + -f "${freebsd_update_conf}" \ + install + + elif [ "${JAIL_PLATFORM_OS}" = "HardenedBSD" ]; then + + local jailname="${TARGET}" + local jailpath="${bastille_jailsdir}/${TARGET}/root" + local hbsd_update_conf="${jailpath}/etc/hbsd-update.conf" + + hbsd-update \ + -j "${jailname}" \ + -c "${hbsd_update_conf}" + fi + + # Update release version (including patch level) + NEW_VERSION=$(/usr/sbin/jexec -l "${TARGET}" freebsd-version 2>/dev/null) + if [ "${CURRENT_VERSION}" != "${NEW_VERSION}" ]; then + bastille config ${TARGET} set osrelease ${NEW_VERSION} >/dev/null + info "\nUpgrade complete: ${CURRENT_VERSION} > ${NEW_VERSION}\n" + else + info "\nNo updates available.\n" + fi +} + +jail_update_pkgbase() { + + if [ "${JAIL_PLATFORM_OS}" = "FreeBSD" ]; then + + local jailpath="${bastille_jailsdir}/${TARGET}/root" + local abi="FreeBSD:${MAJOR_VERSION}:${HW_MACHINE_ARCH}" + local fingerprints="${jailpath}/usr/share/keys/pkg" + if [ "${FREEBSD_BRANCH}" = "release" ]; then + local repo_name="FreeBSD-base-release-${MINOR_VERSION}" + elif [ "${FREEBSD_BRANCH}" = "current" ]; then + local repo_name="FreeBSD-base-latest" + fi + local repo_dir="${bastille_sharedir}/pkgbase" + + # Update repo (pkgbase) + if ! pkg --rootdir "${jailpath}" \ + --repo-conf-dir "${repo_dir}" \ + -o IGNORE_OSVERSION="yes" \ + -o VERSION_MAJOR="${MAJOR_VERSION}" \ + -o VERSION_MINOR="${MINOR_VERSION}" \ + -o ABI="${abi}" \ + -o ASSUME_ALWAYS_YES="yes" \ + -o FINGERPRINTS="${fingerprints}" \ + update -r "${repo_name}"; then + + error_exit "[ERROR]: Failed to update pkg repo: ${repo_name}" + fi + + # Update jail + if ! pkg --rootdir "${jailpath}" \ + --repo-conf-dir "${repo_dir}" \ + -o IGNORE_OSVERSION="yes" \ + -o VERSION_MAJOR="${MAJOR_VERSION}" \ + -o VERSION_MINOR="${MINOR_VERSION}" \ + -o ABI="${abi}" \ + -o ASSUME_ALWAYS_YES="yes" \ + -o FINGERPRINTS="${fingerprints}" \ + upgrade -r "${repo_name}"; then + + error_exit "[ERROR]: Failed to update jail: ${TARGET}" + fi + + # Update release version (including patch level) + NEW_VERSION=$(/usr/sbin/jexec -l "${TARGET}" freebsd-version 2>/dev/null) + if [ "${CURRENT_VERSION}" != "${NEW_VERSION}" ]; then + bastille config ${TARGET} set osrelease ${NEW_VERSION} >/dev/null + info "\nUpgrade complete: ${CURRENT_VERSION} > ${NEW_VERSION}\n" else - env PAGER="/bin/cat" freebsd-update ${OPTION} \ - --not-running-from-cron \ - -j "${_jailname}" \ - -d "${_workdir}" \ - -f "${_freebsd_update_conf}" \ - fetch install + info "\nNo updates available.\n" + fi + else + error_exit "[ERROR]: Jail not found: ${TARGET}" + fi +} + +release_check() { + + TARGET="${NAME_VERIFY}" + + # Validate release existence + if [ ! -d "${bastille_releasesdir}/${TARGET}" ]; then + error_exit "[ERROR]: Release not found: ${TARGET}" + fi + + # Verify PLATFORM_OS inside release + RELEASE_PLATFORM_OS="$( ${bastille_releasesdir}/${TARGET}/bin/freebsd-version )" + if echo "${RELEASE_PLATFORM_OS}" | grep -q "HBSD"; then + RELEASE_PLATFORM_OS="HardenedBSD" + else + RELEASE_PLATFORM_OS="FreeBSD" + fi + + if [ "${RELEASE_PLATFORM_OS}" = "FreeBSD" ]; then + + if echo "${TARGET}" | grep -w "[0-9]\{1,2\}\.[0-9]\-RELEASE\-i386"; then + ARCH_I386="1" + fi + + # Validate update method + MINOR_VERSION=$(echo ${TARGET} | sed -E 's/^[0-9]+\.([0-9]+)-.*$/\1/') + MAJOR_VERSION=$(echo ${TARGET} | grep -Eo '^[0-9]+') + if echo "${TARGET}" | grep -oq "\-CURRENT"; then + FREEBSD_BRANCH="current" + else + FREEBSD_BRANCH="release" + fi + if [ "${MAJOR_VERSION}" -ge 16 ] || pkg -r "${bastille_releasesdir}/${TARGET}" which /usr/bin/uname > /dev/null 2>&1; then + PKGBASE=1 fi fi } release_update() { - local _releasepath="${bastille_releasesdir}/${TARGET}" - local _freebsd_update_conf="${_releasepath}/etc/freebsd-update.conf" - local _workdir="${_releasepath}/var/db/freebsd-update" + if [ "${RELEASE_PLATFORM_OS}" = "FreeBSD" ]; then - # Update a release base(affects child containers) - if [ -d "${_releasepath}" ]; then + local release_dir="${bastille_releasesdir}/${TARGET}" + local freebsd_update_conf="${release_dir}/etc/freebsd-update.conf" + local work_dir="${release_dir}/var/db/freebsd-update" + + # Update a release base (affects child containers) TARGET_TRIM="${TARGET}" if [ -n "${ARCH_I386}" ]; then TARGET_TRIM=$(echo "${TARGET}" | sed 's/-i386//') fi + env PAGER="/bin/cat" freebsd-update ${OPTION} \ --not-running-from-cron \ - -b "${_releasepath}" \ - -d "${_workdir}" \ - -f "${_freebsd_update_conf}" \ + -b "${release_dir}" \ + -d "${work_dir}" \ + -f "${freebsd_update_conf}" \ fetch --currently-running "${TARGET_TRIM}" + env PAGER="/bin/cat" freebsd-update ${OPTION} \ --not-running-from-cron \ - -b "${_releasepath}" \ - -d "${_workdir}" \ - -f "${_freebsd_update_conf}" \ + -b "${release_dir}" \ + -d "${work_dir}" \ + -f "${freebsd_update_conf}" \ install --currently-running "${TARGET_TRIM}" - else - error_exit "[ERROR]: ${TARGET} not found. See 'bastille bootstrap RELEASE'." + + elif [ "${RELEASE_PLATFORM_OS}" = "HardenedBSD" ]; then + + local release_dir="${bastille_releasesdir}/${TARGET}" + local hbsd_update_conf="${release_dir}/etc/hbsd-update.conf" + + # Update a release base (affects child containers) + TARGET_TRIM="${TARGET}" + if [ -n "${ARCH_I386}" ]; then + TARGET_TRIM=$(echo "${TARGET}" | sed 's/-i386//') + fi + + hbsd-update \ + -r "${release_dir}" \ + -c "${hbsd_update_conf}" + fi +} + +release_update_pkgbase() { + + if [ "${RELEASE_PLATFORM_OS}" = "FreeBSD" ]; then + + local release_dir="${bastille_releasesdir}/${TARGET}" + local abi="FreeBSD:${MAJOR_VERSION}:${HW_MACHINE_ARCH}" + local fingerprints="${release_dir}/usr/share/keys/pkg" + if [ "${FREEBSD_BRANCH}" = "release" ]; then + local repo_name="FreeBSD-base-release-${MINOR_VERSION}" + elif [ "${FREEBSD_BRANCH}" = "current" ]; then + local repo_name="FreeBSD-base-latest" + fi + local repo_dir="${bastille_sharedir}/pkgbase" + + # Update repo (pkgbase) + if ! pkg --rootdir "${release_dir}" \ + --repo-conf-dir "${repo_dir}" \ + -o IGNORE_OSVERSION="yes" \ + -o ABI="${abi}" \ + -o ASSUME_ALWAYS_YES="yes" \ + -o FINGERPRINTS="${fingerprints}" \ + update -r "${repo_name}"; then + + error_exit "[ERROR]: Failed to update pkg repo: ${repo_name}" + fi + + # Update release (pkgbase) + if ! pkg --rootdir "${release_dir}" \ + --repo-conf-dir "${repo_dir}" \ + -o IGNORE_OSVERSION="yes" \ + -o ABI="${abi}" \ + -o ASSUME_ALWAYS_YES="yes" \ + -o FINGERPRINTS="${fingerprints}" \ + upgrade -r "${repo_name}"; then + + error_exit "[ERROR]: Failed to update release: ${TARGET}" + fi fi } template_update() { # Update a template - _template_path=${bastille_templatesdir}/${BASTILLE_TEMPLATE} + template_path=${bastille_templatesdir}/${BASTILLE_TEMPLATE} - if [ -d $_template_path ]; then + if [ -d ${template_path} ]; then info "\n[${BASTILLE_TEMPLATE}]:" if ! git -C $_template_path pull; then - error_exit "[ERROR]: ${BASTILLE_TEMPLATE} update unsuccessful." + error_exit "[ERROR]: ${BASTILLE_TEMPLATE} update unsuccessful." fi bastille verify "${BASTILLE_TEMPLATE}" - else + else error_exit "[ERROR]: ${BASTILLE_TEMPLATE} not found. See 'bastille bootstrap'." fi } @@ -197,36 +386,107 @@ template_update() { templates_update() { # Update all templates - _updated_templates=0 + updated_templates=0 + if [ -d ${bastille_templatesdir} ]; then # shellcheck disable=SC2045 - for _template_path in $(ls -d ${bastille_templatesdir}/*/*); do - if [ -d $_template_path/.git ]; then - BASTILLE_TEMPLATE=$(echo "$_template_path" | awk -F / '{ print $(NF-1) "/" $NF }') + for template_path in $(ls -d ${bastille_templatesdir}/*/*); do + if [ -d $template_path/.git ]; then + BASTILLE_TEMPLATE=$(echo "$template_path" | awk -F / '{ print $(NF-1) "/" $NF }') template_update - - _updated_templates=$((_updated_templates+1)) + updated_templates=$((updated_templates+1)) fi done fi - if [ "$_updated_templates" -ne "0" ]; then - info "\n$_updated_templates templates updated." - else + # Verify template updates + if [ "$updated_templates" -ne "0" ]; then + info "\n$updated_templates templates updated." + else error_exit "[ERROR]: No templates found. See 'bastille bootstrap'." fi } -# Check what we should update -if [ "${TARGET}" = 'TEMPLATES' ]; then - templates_update -elif echo "${TARGET}" | grep -Eq '^[A-Za-z0-9_-]+/[A-Za-z0-9_-]+$'; then - BASTILLE_TEMPLATE="${TARGET}" - template_update -elif echo "${TARGET}" | grep -q "[0-9]\{2\}.[0-9]-RELEASE"; then - arch_check - release_update -else - jail_check - jail_update "${TARGET}" -fi \ No newline at end of file +# Set needed variables for pkgbase +HW_MACHINE_ARCH=$(sysctl hw.machine_arch | awk '{ print $2 }') + +# Check what we need to update +# JAIL or RELEASE +UPDATE_TARGET="" +case "${TARGET}" in + templates|TEMPLATES) + UPDATE_TARGET="TEMPLATES" + ;; + */*) + BASTILLE_TEMPLATE="${TARGET}" + UPDATE_TARGET="TEMPLATE" + ;; + [2-4].[0-9]*) + PLATFORM_OS="MidnightBSD" + NAME_VERIFY=$(echo "${TARGET}") + UPDATE_TARGET="RELEASE" + ;; + *-current|*-CURRENT) + PLATFORM_OS="FreeBSD" + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]+)\.[0-9](-CURRENT)$' | tr '[:lower:]' '[:upper:]') + UPDATE_TARGET="RELEASE" + ;; + *\.*-stable|*\.*-STABLE) + PLATFORM_OS="FreeBSD" + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]+)\.[0-9](-STABLE)$' | tr '[:lower:]' '[:upper:]') + UPDATE_TARGET="RELEASE" + ;; + *-release|*-RELEASE) + PLATFORM_OS="FreeBSD" + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([0-9]+)\.[0-9](-RELEASE)$' | tr '[:lower:]' '[:upper:]') + UPDATE_TARGET="RELEASE" + ;; + current|CURRENT) + PLATFORM_OS="HardenedBSD" + NAME_VERIFY=$(echo "${TARGET}" | sed 's/CURRENT/current/g') + UPDATE_TARGET="RELEASE" + ;; + [1-9]*-stable|[1-9]*-STABLE) + PLATFORM_OS="HardenedBSD" + NAME_VERIFY=$(echo "${TARGET}" | grep -iwE '^([1-9]+)(-stable)$' | sed 's/STABLE/stable/g') + UPDATE_TARGET="RELEASE" + ;; + *) + UPDATE_TARGET="JAIL" + ;; +esac + +# Unsupported platforms +if [ "${PLATFORM_OS}" = "MidnightBSD" ] || [ -f "/bin/midnightbsd-version" ]; then + error_exit "[ERROR]: Not yet supported on MidnightBSD." +fi + +# Update +case ${UPDATE_TARGET} in + TEMPLATE) + template_update + ;; + TEMPLATES) + templates_update + ;; + RELEASE) + release_check + info "\nAttempting to update release: ${TARGET}" + if [ "${PKGBASE}" -eq 1 ]; then + release_update_pkgbase + else + release_update + fi + ;; + JAIL) + jail_check + if [ "${PKGBASE}" -eq 1 ]; then + jail_update_pkgbase + else + jail_update + fi + ;; + *) + error_exit "[ERROR]: Unknown update target." + ;; +esac \ No newline at end of file diff --git a/usr/local/share/bastille/upgrade.sh b/usr/local/share/bastille/upgrade.sh index fbb9fe56..c7313d4d 100644 --- a/usr/local/share/bastille/upgrade.sh +++ b/usr/local/share/bastille/upgrade.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille upgrade [option(s)] TARGET NEW_RELEASE|install" cat << EOF - + Options: -a | --auto Auto mode. Start/stop jail(s) if required. @@ -66,13 +66,13 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; f) OPTION="-F" ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -88,152 +88,340 @@ if [ $# -lt 2 ] || [ $# -gt 3 ]; then fi TARGET="${1}" -NEWRELEASE="${2}" +NEW_RELEASE="${2}" bastille_root_check set_target_single "${TARGET}" -# Check for unsupported actions -if [ -f "/bin/midnightbsd-version" ]; then - error_exit "[ERROR]: Not yet supported on MidnightBSD." -fi - -if freebsd-version | grep -qi HBSD; then - error_exit "[ERROR]: Not yet supported on HardenedBSD." -fi - thick_jail_check() { - local _jail="${1}" - # Validate jail state - check_target_is_running "${_jail}" || if [ "${AUTO}" -eq 1 ]; then - bastille start "${_jail}" + check_target_is_running "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then + bastille start "${TARGET}" else - info "\n[${_jail}]:" + info "\n[${TARGET}]:" error_notify "Jail is not running." error_exit "Use [-a|--auto] to auto-start the jail." fi + + if [ "${PLATFORM_OS}" = "FreeBSD" ]; then + + # Set OLD_RELEASE + OLD_RELEASE="$(${bastille_jailsdir}/${TARGET}/root/bin/freebsd-version 2>/dev/null)" + if [ -z "${OLD_RELEASE}" ]; then + error_exit "[ERROR]: Can't determine '${TARGET}' version." + fi + + # Set VERSION + NEW_MINOR_VERSION=$(echo ${NEW_RELEASE} | sed -E 's/^[0-9]+\.([0-9]+)-.*$/\1/') + NEW_MAJOR_VERSION=$(echo ${NEW_RELEASE} | grep -Eo '^[0-9]+') + + # Validate PKGBASE or non-PKGBASE + if echo "${NEW_RELEASE}" | grep -oq "\-CURRENT"; then + FREEBSD_BRANCH="current" + else + FREEBSD_BRANCH="release" + fi + if [ "${NEW_MAJOR_VERSION}" -ge 16 ] || pkg -r "${bastille_jailsdir}/${TARGET}/root" which /usr/bin/uname > /dev/null 2>&1; then + PKGBASE=1 + fi + + # Check if jail is already running NEW_RELEASE + if [ "${OLD_RELEASE}" = "${NEW_RELEASE}" ]; then + error_notify "[ERROR]: Jail is already running '${NEW_RELEASE}' release." + error_exit "See 'bastille update TARGET' to update the jail." + fi + + elif [ "${PLATFORM_OS}" = "HardenedBSD" ]; then + + # Set VERSION + OLD_RELEASE="$(${bastille_jailsdir}/${TARGET}/root/bin/freebsd-version 2>/dev/null)" + OLD_CONFIG_RELEASE="$(bastille config ${TARGET} get osrelease)" + if [ -z "${OLD_RELEASE}" ]; then + error_exit "[ERROR]: Can't determine '${TARGET}' version." + fi + + # Check if jail is already running NEW_RELEASE + if [ "${OLD_CONFIG_RELEASE}" = "${NEW_RELEASE}" ]; then + error_notify "[ERROR]: Jail is already running '${NEW_RELEASE}' release." + error_exit "See 'bastille update TARGET' to update the jail." + fi + fi } thin_jail_check() { - local _jail="${1}" - # Validate jail state - check_target_is_stopped "${_jail}" || if [ "${AUTO}" -eq 1 ]; then - bastille stop "${_jail}" + check_target_is_stopped "${TARGET}" || if [ "${AUTO}" -eq 1 ]; then + bastille stop "${TARGET}" else - info "\n[${_jail}]:" + info "\n[${TARGET}]:" error_notify "Jail is running." error_exit "Use [-a|--auto] to auto-stop the jail." fi + + # Set VERSION + OLD_RELEASE="$(bastille config ${TARGET} get osrelease)" + if [ -z "${OLD_RELEASE}" ]; then + error_exit "[ERROR]: Can't determine '${TARGET}' version." + fi + + # Check if jail is already running NEW_RELEASE + if [ "${OLD_RELEASE}" = "${NEW_RELEASE}" ]; then + error_notify "[ERROR]: Jail is already running '${NEW_RELEASE}' release." + error_exit "See 'bastille update RELEASE' to update the release." + fi } release_check() { - local _release="${1}" + # Validate the release name + case "${NEW_RELEASE}" in + [2-4].[0-9]*) + PLATFORM_OS="MidnightBSD" + NAME_VERIFY=$(echo "${NEW_RELEASE}") + ;; + *-current|*-CURRENT) + PLATFORM_OS="FreeBSD" + NAME_VERIFY=$(echo "${NEW_RELEASE}" | grep -iwE '^([1-9]+)\.[0-9](-CURRENT)$' | tr '[:lower:]' '[:upper:]') + ;; + *\.*-stable|*\.*-STABLE) + PLATFORM_OS="FreeBSD" + NAME_VERIFY=$(echo "${NEW_RELEASE}" | grep -iwE '^([1-9]+)\.[0-9](-STABLE)$' | tr '[:lower:]' '[:upper:]') + ;; + *-release|*-RELEASE) + PLATFORM_OS="FreeBSD" + NAME_VERIFY=$(echo "${NEW_RELEASE}" | grep -iwE '^([0-9]+)\.[0-9](-RELEASE)$' | tr '[:lower:]' '[:upper:]') + ;; + current|CURRENT) + PLATFORM_OS="HardenedBSD" + NAME_VERIFY=$(echo "${NEW_RELEASE}" | sed 's/CURRENT/current/g') + ;; + [1-9]*-stable|[1-9]*-STABLE) + PLATFORM_OS="HardenedBSD" + NAME_VERIFY=$(echo "${NEW_RELEASE}" | grep -iwE '^([1-9]+)(-stable)$' | sed 's/STABLE/stable/g') + ;; + *) + error_exit "[ERROR]: Invalid release: ${RELEASE}" + ;; + esac - # Validate the release - if ! echo "${_release}" | grep -q "[0-9]\{2\}.[0-9]-[RELEASE,BETA,RC]"; then - error_exit "[ERROR]: ${_release} is not a valid release." - fi + NEW_RELEASE="${NAME_VERIFY}" - # Exit if NEWRELEASE doesn't exist - if [ "${THIN_JAIL}" -eq 1 ]; then - if [ ! -d "${bastille_releasesdir}/${_release}" ]; then - error_notify "[ERROR]: Release not found: ${_release}" - error_exit "See 'bastille bootstrap ${_release} to bootstrap the release." + # Exit if NEW_RELEASE doesn't exist + if [ "${JAIL_TYPE}" = "thin" ]; then + if [ ! -d "${bastille_releasesdir}/${NEW_RELEASE}" ]; then + error_notify "[ERROR]: Release not found: ${NEW_RELEASE}" + error_exit "See 'bastille bootstrap'." fi fi } jail_upgrade() { - local _jailname="${1}" - - if [ "${THIN_JAIL}" -eq 1 ]; then - local _oldrelease="$(bastille config ${_jailname} get osrelease)" - else - local _oldrelease="$(jexec -l ${_jailname} freebsd-version)" - fi - local _newrelease="${2}" - local _jailpath="${bastille_jailsdir}/${_jailname}/root" - local _workdir="${_jailpath}/var/db/freebsd-update" - local _freebsd_update_conf="${_jailpath}/etc/freebsd-update.conf" + info "\n[${TARGET}]:" # Upgrade a thin jail - if grep -qw "${bastille_jailsdir}/${_jailname}/root/.bastille" "${bastille_jailsdir}/${_jailname}/fstab"; then - if [ "${_oldrelease}" = "not set" ]; then - _oldrelease="$(grep "${bastille_releasesdir}.*\.bastille.*nullfs.*" "${bastille_jailsdir}/${_jailname}/fstab" | awk -F"/releases/" '{print $2}' | awk '{print $1}')" - fi - local _newrelease="${NEWRELEASE}" + if grep -qw "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then + # Update "osrelease" entry inside fstab - sed -i '' "/.bastille/ s|${_oldrelease}|${_newrelease}|g" "${bastille_jailsdir}/${_jailname}/fstab" + if ! sed -i '' "/.bastille/ s|${OLD_RELEASE}|${NEW_RELEASE}|g" "${bastille_jailsdir}/${TARGET}/fstab"; then + error_exit "[ERROR]: Failed to update fstab." + fi + # Update "osrelease" inside jail.conf using 'bastille config' - bastille config ${_jailname} set osrelease ${_newrelease} + bastille config ${TARGET} set osrelease ${NEW_RELEASE} >/dev/null 2>/dev/null + # Start jail if AUTO=1 if [ "${AUTO}" -eq 1 ]; then - bastille start "${_jailname}" + bastille start "${TARGET}" fi - info "\nUpgraded ${_jailname}: ${_oldrelease} -> ${_newrelease}" - echo "See 'bastille etcupdate TARGET' to update /etc/rc.conf" + + info "\nUpgraded ${TARGET}: ${OLD_RELEASE} -> ${NEW_RELEASE}" + echo "See 'bastille etcupdate TARGET' to update /etc" + echo + else - # Upgrade a thick jail - env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron \ - --currently-running "${_oldrelease}" \ - -j "${_jailname}" \ - -d "${_workdir}" \ - -f "${_freebsd_update_conf}" \ - -r "${_newrelease}" upgrade - - # Update "osrelease" inside jail.conf using 'bastille config' - bastille config ${_jailname} set osrelease ${_newrelease} - warn "Please run 'bastille upgrade ${_jailname} install', restart the jail, then run 'bastille upgrade ${_jailname} install' again to finish installing updates." + + if [ "${PLATFORM_OS}" = "FreeBSD" ]; then + + local jailpath="${bastille_jailsdir}/${TARGET}/root" + local work_dir="${jailpath}/var/db/freebsd-update" + local freebsd_update_conf="${jailpath}/etc/freebsd-update.conf" + + # Upgrade a thick jail + env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron \ + --currently-running "${OLD_RELEASE}" \ + -j "${TARGET}" \ + -d "${work_dir}" \ + -f "${freebsd_update_conf}" \ + -r "${NEW_RELEASE}" upgrade + + UPGRADED_RELEASE="$(${bastille_jailsdir}/${TARGET}/root/bin/freebsd-version 2>/dev/null)" + if [ "${OLD_RELEASE}" = "${UPGRADED_RELEASE}" ]; then + info "\nNo upgrades available.\n" + else + # Update "osrelease" inside jail.conf using 'bastille config' + bastille config ${TARGET} set osrelease ${UPGRADED_RELEASE} >/dev/null 2>/dev/null + warn "Please run 'bastille upgrade ${TARGET} install', restart the jail, then run 'bastille upgrade ${TARGET} install' again to finish installing updates." + echo + fi + + elif [ "${PLATFORM_OS}" = "HardenedBSD" ]; then + + local jailname="${TARGET}" + local jailpath="${bastille_jailsdir}/${TARGET}/root" + local hbsd_update_conf="${jailpath}/etc/hbsd-update.conf" + + # Set proper vars in hbsd-update.conf + case ${NEW_RELEASE} in + current) + branch="hardened/current/master" + dnsrec="\$(uname -m).master.current.hardened.hardenedbsd.updates.hardenedbsd.org" + ;; + *-stable) + NEW_MAJOR_VERSION=$(echo ${NEW_RELEASE} | grep -Eo '^[0-9]+') + branch="hardened/${MAJOR_VERSION}-stable/master" + dnsrec="\$(uname -m).main.${MAJOR_VERSION}-stable.hardened.hardenedbsd.updates.hardenedbsd.org" + ;; + *) + error_exit "[ERROR]: Unknown ${PLATFORM_OS} release: ${NEW_RELEASE}" + ;; + esac + sysrc -f "${hbsd_update_conf}" branch="${branch}" >/dev/null 2>/dev/null + sysrc -f "${hbsd_update_conf}" dnsrec="${dnsrec}" >/dev/null 2>/dev/null + + hbsd-update \ + -j "${jailname}" \ + -c "${hbsd_update_conf}" + + UPGRADED_RELEASE="$(${bastille_jailsdir}/${TARGET}/root/bin/freebsd-version 2>/dev/null)" + if [ "${OLD_RELEASE}" = "${UPGRADED_RELEASE}" ]; then + info "\nNo upgrades available.\n" + else + info "\nUpgraded ${TARGET}: ${OLD_RELEASE} -> ${UPGRADED_RELEASE}\n" + fi + fi fi } +jail_upgrade_pkgbase() { + + if [ "${PLATFORM_OS}" = "FreeBSD" ]; then + + local jailpath="${bastille_jailsdir}/${TARGET}/root" + local abi="FreeBSD:${NEW_MAJOR_VERSION}:${HW_MACHINE_ARCH}" + local fingerprints="${jailpath}/usr/share/keys/pkgbase-${MAJOR_VERSION}" + if [ "${FREEBSD_BRANCH}" = "release" ]; then + local repo_name="FreeBSD-base-release-${NEW_MINOR_VERSION}" + elif [ "${FREEBSD_BRANCH}" = "current" ]; then + local repo_name="FreeBSD-base-latest" + fi + local repo_dir="${bastille_sharedir}/pkgbase" + + info "\n[${TARGET}]:" + + if [ "${OLD_RELEASE}" = "${NEW_RELEASE}" ]; then + error_notify "[ERROR]: Jail is already running '${NEW_RELEASE}'" + error_exit "See 'bastille update TARGET' to update jail." + fi + + # Upgrade jail with pkgbase (thick only) + # Update repo (pkgbase) + if ! pkg --rootdir "${jailpath}" \ + --repo-conf-dir "${repo_dir}" \ + -o IGNORE_OSVERSION="yes" \ + -o VERSION_MAJOR="${NEW_MAJOR_VERSION}" \ + -o VERSION_MINOR="${NEW_MINOR_VERSION}" \ + -o ABI="${abi}" \ + -o ASSUME_ALWAYS_YES="yes" \ + -o FINGERPRINTS="${fingerprints}" \ + update -r "${repo_name}"; then + + error_exit "[ERROR]: Failed to update pkg repo: ${repo_name}" + fi + + # Update jail + if ! pkg --rootdir "${jailpath}" \ + --repo-conf-dir "${repo_dir}" \ + -o IGNORE_OSVERSION="yes" \ + -o VERSION_MAJOR="${NEW_MAJOR_VERSION}" \ + -o VERSION_MINOR="${NEW_MINOR_VERSION}" \ + -o ABI="${abi}" \ + -o ASSUME_ALWAYS_YES="yes" \ + -o FINGERPRINTS="${fingerprints}" \ + upgrade -r "${repo_name}"; then + + error_exit "[ERROR]: Failed to upgrade jail: ${TARGET}" + fi + + # Update release version (including patch level) + NEW_VERSION=$(/usr/sbin/jexec -l "${TARGET}" freebsd-version 2>/dev/null) + bastille config ${TARGET} set osrelease ${NEW_VERSION} >/dev/null 2>/dev/null + + info "\nUpgraded ${TARGET}: ${OLD_RELEASE} -> ${NEW_RELEASE}" + else + error_exit "[ERROR]: Not implemented for platform: ${PLATFORM_OS}" + fi + +} + jail_updates_install() { - local _jailname="${1}" - local _jailpath="${bastille_jailsdir}/${_jailname}/root" - local _workdir="${_jailpath}/var/db/freebsd-update" - local _freebsd_update_conf="${_jailpath}/etc/freebsd-update.conf" + if [ "${PLATFORM_OS}" = "FreeBSD" ]; then - # Finish installing upgrade on a thick container - if [ -d "${bastille_jailsdir}/${_jailname}" ]; then + local jailpath="${bastille_jailsdir}/${TARGET}/root" + local work_dir="${jailpath}/var/db/freebsd-update" + local freebsd_update_conf="${jailpath}/etc/freebsd-update.conf" + + info "\n[${TARGET}]:" + + # Finish installing upgrade on a thick container env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron \ - -j "${_jailname}" \ - -d "${_workdir}" \ - -f "${_freebsd_update_conf}" \ + -j "${TARGET}" \ + -d "${work_dir}" \ + -f "${freebsd_update_conf}" \ install else - error_exit "[ERROR]: ${_jailname} not found. See 'bastille bootstrap RELEASE'." + error_exit "[ERROR]: Not implemented for platform: ${PLATFORM_OS}" fi } -# Check if jail is thick or thin -THIN_JAIL=0 +# Set needed variables +JAIL_TYPE="" +PKGBASE=0 +HW_MACHINE_ARCH=$(sysctl hw.machine_arch | awk '{ print $2 }') + +# Validate jail type (thick/thin) if grep -qw "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then - THIN_JAIL=1 + JAIL_TYPE="thin" fi -# Check what we should upgrade -if [ "${NEWRELEASE}" = "install" ]; then - if [ "${THIN_JAIL}" -eq 1 ]; then - thin_jail_check "${TARGET}" - else - thick_jail_check "${TARGET}" - fi - info "\n[${TARGET}]:" - jail_updates_install "${TARGET}" -else - release_check "${NEWRELEASE}" - if [ "${THIN_JAIL}" -eq 1 ]; then - thin_jail_check "${TARGET}" - else - thick_jail_check "${TARGET}" - fi - info "\n[${TARGET}]:" - jail_upgrade "${TARGET}" "${NEWRELEASE}" -fi +case ${NEW_RELEASE} in + install) + if [ "${JAIL_TYPE}" = "thin" ]; then + thin_jail_check "${TARGET}" + else + thick_jail_check "${TARGET}" + fi + jail_updates_install "${TARGET}" + ;; + *) + release_check + # Unsupported platforms + if [ "${PLATFORM_OS}" = "MidnightBSD" ] || [ -f "/bin/midnightbsd-version" ]; then + error_exit "[ERROR]: Not yet supported on MidnightBSD." + fi + if [ "${JAIL_TYPE}" = "thin" ]; then + thin_jail_check "${TARGET}" + jail_upgrade + else + thick_jail_check "${TARGET}" + if [ "${PKGBASE}" -eq 1 ]; then + jail_upgrade_pkgbase + else + jail_upgrade + fi + fi + ;; +esac \ No newline at end of file diff --git a/usr/local/share/bastille/verify.sh b/usr/local/share/bastille/verify.sh index 4f7993de..c8d34daf 100644 --- a/usr/local/share/bastille/verify.sh +++ b/usr/local/share/bastille/verify.sh @@ -35,7 +35,7 @@ usage() { error_notify "Usage: bastille verify [option(s)] RELEASE|TEMPLATE" cat << EOF - + Options: -x | --debug Enable debug mode. @@ -49,7 +49,7 @@ verify_release() { if [ -f "/bin/midnightbsd-version" ]; then error_exit "[ERROR]: Not yet supported on MidnightBSD." fi - + if freebsd-version | grep -qi HBSD; then error_exit "[ERROR]: Not yet supported on HardenedBSD." fi @@ -160,7 +160,7 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; *) @@ -195,5 +195,3 @@ case "${1}" in usage ;; esac - -echo diff --git a/usr/local/share/bastille/zfs.sh b/usr/local/share/bastille/zfs.sh index ac6967ba..5b7a63c1 100644 --- a/usr/local/share/bastille/zfs.sh +++ b/usr/local/share/bastille/zfs.sh @@ -33,8 +33,8 @@ . /usr/local/share/bastille/common.sh usage() { - - error_notify "Usage: bastille zfs [option(s)] TARGET destroy|rollback|snapshot [TAG]" + + error_notify "Usage: bastille zfs [option(s)] TARGET destroy|rollback [TAG]|snapshot [TAG]" error_notify " df|usage" error_notify " get|set key=value" error_notify " jail pool/dataset /jail/path" @@ -52,7 +52,9 @@ EOF } zfs_jail_dataset() { - + + local jail_config="${bastille_jailsdir}/${JAIL}/jail.conf" + # Exit if MOUNT or DATASET is empty if [ -z "${MOUNT}" ] || [ -z "${DATASET}" ]; then usage @@ -65,30 +67,48 @@ zfs_jail_dataset() { if grep -hoqsw "${DATASET}" ${bastille_jailsdir}/*/zfs.conf; then error_exit "[ERROR]: Dataset already assigned." fi + # Validate jail state - check_target_is_stopped "${_jail}" || if [ "${AUTO}" -eq 1 ]; then - bastille stop "${_jail}" - else + check_target_is_stopped "${JAIL}" || if [ "${AUTO}" -eq 1 ]; then + bastille stop "${JAIL}" + else error_notify "Jail is running." error_exit "Use [-a|--auto] to auto-stop the jail." fi # Add necessary config variables to jail - bastille config ${_jail} set enforce_statfs 1 >/dev/null - bastille config ${_jail} set allow.mount >/dev/null - bastille config ${_jail} set allow.mount.devfs >/dev/null - bastille config ${_jail} set allow.mount.zfs >/dev/null + bastille config ${JAIL} set enforce_statfs 1 >/dev/null + bastille config ${JAIL} set allow.mount >/dev/null + bastille config ${JAIL} set allow.mount.devfs >/dev/null + bastille config ${JAIL} set allow.mount.zfs >/dev/null + + # Enable ZFS inside jail + sysrc -f "${bastille_jailsdir}/${JAIL}/root/etc/rc.conf" zfs_enable="YES" + + # Jail the dataset + zfs set mountpoint="${MOUNT}" "${DATASET}" + zfs set jailed=on "${DATASET}" # Add dataset to zfs.conf - echo "${DATASET} ${MOUNT}" >> "${bastille_jailsdir}/${_jail}/zfs.conf" + echo "${DATASET} ${MOUNT}" >> "${bastille_jailsdir}/${JAIL}/zfs.conf" + + # Add config to jail.conf + sed -i '' '/^}$/d' "${jail_config}" + cat << EOF >> "${jail_config}" + # Jailed dataset: ${DATASET} + exec.created += "zfs jail ${JAIL} ${DATASET}"; +} +EOF if [ "${AUTO}" -eq 1 ]; then - bastille start "${_jail}" + bastille start "${JAIL}" fi } zfs_unjail_dataset() { + local jail_config="${bastille_jailsdir}/${JAIL}/jail.conf" + # Exit if DATASET is empty if [ -z "${DATASET}" ]; then usage @@ -98,57 +118,65 @@ zfs_unjail_dataset() { fi # Validate jail state - check_target_is_stopped "${_jail}" || if [ "${AUTO}" -eq 1 ]; then - bastille stop "${_jail}" - else + check_target_is_stopped "${JAIL}" || if [ "${AUTO}" -eq 1 ]; then + bastille stop "${JAIL}" + else error_notify "Jail is running." error_exit "Use [-a|--auto] to auto-stop the jail." fi + # Unjail the dataset + zfs set jailed=off "${DATASET}" + zfs umount "${DATASET}" + # Remove dataset from zfs.conf - if ! grep -hoqsw "${DATASET}" ${bastille_jailsdir}/${_jail}/zfs.conf; then + if ! grep -hoqsw "${DATASET}" ${bastille_jailsdir}/${JAIL}/zfs.conf; then error_exit "[ERROR]: Dataset not present in zfs.conf." else - sed -i '' "\#.*${DATASET}.*#d" "${bastille_jailsdir}/${_jail}/zfs.conf" + sed -i '' "\#.*${DATASET}.*#d" "${bastille_jailsdir}/${JAIL}/zfs.conf" fi + # Remove config from jail.conf + sed -i '' "\#.*Jailed dataset: ${DATASET}.*#d" "${jail_config}" + sed -i '' "\#.*zfs jail ${JAIL} ${DATASET}.*#d" "${jail_config}" + if [ "${AUTO}" -eq 1 ]; then - bastille start "${_jail}" + bastille start "${JAIL}" fi } zfs_snapshot() { # shellcheck disable=SC2140 - zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}"@"${TAG}" + zfs snapshot -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${JAIL}"@"${TAG}" _return=$? } zfs_rollback() { # shellcheck disable=SC2140 - zfs rollback -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}"@"${TAG}" + zfs rollback -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${JAIL}"@"${TAG}" # shellcheck disable=SC2140 - zfs rollback -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}/root"@"${TAG}" + zfs rollback -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${JAIL}/root"@"${TAG}" _return=$? } zfs_destroy_snapshot() { # shellcheck disable=SC2140 - zfs destroy ${OPT_DESTROY} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}"@"${TAG}" + zfs destroy ${OPT_DESTROY} "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${JAIL}"@"${TAG}" _return=$? } zfs_set_value() { - zfs set "${ATTRIBUTE}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}" + zfs set "${ATTRIBUTE}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${JAIL}" _return=$? } zfs_get_value() { - zfs get "${ATTRIBUTE}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}" + zfs get "${ATTRIBUTE}" "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${JAIL}" _return=$? } zfs_disk_usage() { - zfs list -t all -o name,used,avail,refer,mountpoint,compress,ratio -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail}" + zfs list -t all -o name,used,avail,refer,mountpoint,compress,ratio -r "${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${JAIL}" _return=$? } @@ -162,10 +190,10 @@ snapshot_checks() { # Verify rollback snapshots if [ "${SNAP_ROLLBACK}" -eq 1 ]; then if [ -n "${TAG}" ]; then - SNAP_TAG_CHECK="$(zfs list -H -t snapshot -o name ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail} | grep -o "${TAG}$" | tail -n 1)" + SNAP_TAG_CHECK="$(zfs list -H -t snapshot -o name ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${JAIL} | grep -o "${TAG}$" | tail -n 1)" else - TAG="$(zfs list -H -t snapshot -o name ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${_jail} | grep -o "bastille_${_jail}_.*$" | tail -n 1)" - SNAP_TAG_CHECK=$(echo ${TAG} | grep -wo "bastille_${_jail}_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}") + TAG="$(zfs list -H -t snapshot -o name ${bastille_zfs_zpool}/${bastille_zfs_prefix}/jails/${JAIL} | grep -o "bastille_${JAIL}_.*$" | tail -n 1)" + SNAP_TAG_CHECK=$(echo ${TAG} | grep -wo "bastille_${JAIL}_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}") fi if [ -z "${SNAP_TAG_CHECK}" ]; then error_continue "[ERROR]: Snapshot not found: ${TAG}" @@ -177,10 +205,10 @@ snapshot_checks() { # Generate a relatively short but unique name for the snapshots based on the current date/jail name. elif [ "${AUTO_TAG}" -eq 1 ]; then DATE=$(date +%F-%H%M%S) - TAG="bastille_${_jail}_${DATE}" + TAG="bastille_${JAIL}_${DATE}" # Check for the generated snapshot name. SNAP_GEN_CHECK="" - SNAP_GEN_CHECK=$(echo ${TAG} | grep -wo "bastille_${_jail}_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}") + SNAP_GEN_CHECK=$(echo ${TAG} | grep -wo "bastille_${JAIL}_[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}") if [ -z "${SNAP_GEN_CHECK}" ]; then error_notify "[ERROR]: Failed to validate snapshot name." fi @@ -226,7 +254,7 @@ snapshot_destroy() { else OPT_DESTROY="-r" fi - + zfs_destroy_snapshot # Check for exit status and just notify. @@ -260,12 +288,12 @@ while [ "$#" -gt 0 ]; do enable_debug shift ;; - -*) + -*) for _opt in $(echo ${1} | sed 's/-//g' | fold -w1); do case ${_opt} in a) AUTO=1 ;; x) enable_debug ;; - *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; + *) error_exit "[ERROR]: Unknown Option: \"${1}\"" ;; esac done shift @@ -296,9 +324,9 @@ if [ -z "${bastille_zfs_zpool}" ]; then error_exit "[ERROR]: ZFS zpool not defined." fi -for _jail in ${JAILS}; do +for JAIL in ${JAILS}; do - info "\n[${_jail}]:" + info "\n[${JAIL}]:" case "${ACTION}" in destroy|destroy_snap|destroy_snapshot) diff --git a/usr/local/share/man/man8/bastille.8 b/usr/local/share/man/man8/bastille.8 new file mode 100644 index 00000000..9ff3cf51 --- /dev/null +++ b/usr/local/share/man/man8/bastille.8 @@ -0,0 +1,120 @@ +.Dd 2025/08/27 +.Dt bastille 8 +.Os FreeBSD +.Sh NAME +bastille - Bastille is an open-source system for automating deployment +\ and management of containerized applications on FreeBSD. +.Sh SYNOPSIS +.Nm bastille +.Ar command +.Ar TARGET +.Op arg +.Sh DESCRIPTION +.Nm To start all containers during boot use: +.Pp +sysrc bastille_enable=YES +.Pp +.Nm The following modules are available: +.Pp +.Bl -tag -width -indent +.It bootstrap +Bootstrap a FreeBSD release for container base. +.It clone +Clone an existing container. +.It cmd +Execute arbitrary command on targeted container(s). +.It console +Console into a running container. +.It convert +Convert a thin container into a thick container. +.It cp +cp(1) files from host to targeted container(s). +.It create +Create a new thin container or a thick container if -T|--thick option specified. +.It destroy +Destroy a stopped container or a FreeBSD release. +.It edit +Edit container configuration files (advanced). +.It export +Exports a container archive or image. +.It help +Help about any command +.It htop +Interactive process viewer (requires htop). +.It import +Import a container archive or image. +.It list +List containers, releases, templates, logs, limits or backups. +.It limits +Apply resources limits to targeted container(s). See rctl(8). +.It pkg +Manipulate binary packages within targeted container(s). See pkg(8). +.It restart +Restart a running container. +.It rdr +Redirect host port to container port. +.It service +Manage services within targeted container(s). +.It start +Start a stopped container. +.It stop +Stop a running container. +.It sysrc +Safely edit rc files within targeted container(s). +.It tags +Add tags to targeted container(s). +.It template +Apply file templates to targeted container(s). +.It top +Display and update information about the top(1) cpu processes. +.It update +Update container base -pX release. +.It upgrade +Upgrade container release to X.Y-RELEASE. +.It verify +Compare release against a "known good" index. +.It zfs +Manage (get|set) zfs attributes on targeted container(s). +.El +.Pp +.Sh FILES +.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact +.It Pa /usr/local/bin/bastille +Bastille executable +.El +.Pp +.Sh BUGS +Please report any bugs on Github +.Nm https://github.com/BastilleBSD/bastille/issues +.Pp +.Sh EXAMPLE +bastille bootstrap 12.1-RELEASE +.Pp +bastille create myjail 12.1-RELEASE 10.0.0.1 em0 +.Pp +.Nm To create a container with VNET and DHCP use +.Pp +bastille create -V myjail 12.1-RELEASE 0.0.0.0 em0 +.Sh HISTORY +.Nm Features added in 0.6.20200412: +.Pp +.Bl -tag -width -indent +.It clone +Clone an existing container. +.It import (updated) +Support for iocage and ezjail import +.Pp +.El +.Nm Features added in 0.6.20200202: +.Pp +.Bl -tag -width -indent +.It convert +Convert a thin container into a thick container. +.It export +Exports a container archive or image. +.It import +Import a container archive or image. +.It limits +Apply resources limits to targeted container(s). See rctl(8). +.It rdr +Redirect host port to container port.