Skip to content

What the gate allows

D is a dataset inside the tenant root, D↓ a dataset strictly below it, S a snapshot name.

Command Runs
exit, echo -n, ps -Ao args= nothing (exit 0)
command -v NAME nothing (exit 1: "not installed")
zpool get -o value -H feature@extensible_dataset POOL same, only for the root's pool
zfs get -H name D, zfs get -H receive_resume_token D, zfs get -H -p used D, zfs get -Hpd 1 -t snapshot guid,creation D, zfs get -Hpd 1 type,guid,creation D same
zfs receive [-s] [-F] [-u] D↓ zfs receive -u [-s] [-F] D↓, then the encryption check
zfs receive -A D↓ same
zfs destroy [-r] D↓@S[,S...] same
zfs destroy D↓@a; zfs destroy D↓@b (syncoid's chain) one zfs destroy D↓@a,b
zfs destroy [-r] D↓ same
zfs create [-p] D↓ same
zfs list [-H] [-p] [-r] [-d N] [-t TYPES] [-o COLUMNS] [-s/-S COLUMN] [D] same, D defaults to the root; columns come from an allowlist
zfs send [-w] [-L] [-c] [-e] [-R] [-p] [-i/-I ORIGIN] D@S same, the origin must be a snapshot of D
zfs send -t TOKEN same, after checking the token names a snapshot inside the root

Anything else exits 126 with zfs-tenant: command not allowed: <reason>, and every decision is logged to the auth log with the tenant root. Every allowed command runs inside the tenant's zone.