Encrypted ZFS storage pool broken after reboot

Edit: solved—see comments below.

I have attempted to configure Incus to use an existing, encrypted ZFS dataset as its default storage pool. I had configured ZFS to automatically unlock and mount both the zpool and the dataset on boot. After running incus admin init and selecting the dataset to use for the default storage pool, the dataset no longer mounts on boot and it isn’t available for use by Incus. In addition, many Incus commands fail with Error: The remote isn't a private server which is confusing because I don’t think I’m telling it to use a remote. [solved—see below]

System Information
Arch Linux
kernel version: LTS 6.6.36
ZFS version: 2.2.4-1
Incus version: 6.2

Setup Details

ZFS and Encryption:

  • zpool called data and mounted at /data
  • Encrypted ZFS dataset called incus and mounted at /data/incus
  • The dataset automounts via zfs-mount.service
  • The key for the dataset is provided by a custom service:
    • zfs-load-key@.service which takes as a parameter the zpool/dataset to load the key for
    • In this case the parameter will be data-incus (escaped (%i)) or data/incus (unescaped (%I))
    • Credential is accessed through systemd credentials available in $CREDENTIALS_DIRECTORY to the service as it runs
    • the credential is named zfs-%i-key (in this case zfs-data-incus-key)
    • the service runs zfs load-key -L file://${CREDENTIALS_DIRECTORY}/zfs-%i-key %I
    • The service is configured After and Requires zfs-import.target
    • And WantedBy zfs-mount.service
    • runs zfs-loadkey -L file://${CREDENTIALS_DIRECTORY}/zfs-%i-key %I
  • The original encryption setup used a keyfile in /tmp which is not available after a reboot, therefore the dataset automounting can only happen if the above service is working properly.

Incus:

  • ran incus admin init
  • chose to use the existing ZFS dataset data/incus
Full Preseed from `incus admin init`
config: {}
networks:
- config:
    ipv4.address: auto
    ipv6.address: auto
  description: ""
  name: incusbr0
  type: ""
  project: default
storage_pools:
- config:
    source: data/incus
  description: ""
  name: default
  driver: zfs
profiles:
- config: {}
  description: ""
  devices:
    eth0:
      name: eth0
      network: incusbr0
      type: nic
    root:
      path: /
      pool: default
      type: disk
  name: default
projects: []
cluster: null
Full config from `incus admin init --dump`
config:
  images.auto_update_interval: "0"
networks:
- config:
    ipv4.address: redacted
    ipv4.nat: "true"
    ipv6.address: redacted
    ipv6.nat: "true"
  description: ""
  name: incusbr0
  type: bridge
  project: default
storage_pools:
- config:
    source: data/incus
    volatile.initial_source: data/incus
    zfs.pool_name: data/incus
  description: ""
  name: default
  driver: zfs
profiles:
- config: {}
  description: Default Incus profile
  devices:
    eth0:
      name: eth0
      network: incusbr0
      type: nic
    root:
      path: /
      pool: default
      type: disk
  name: default
projects:
- config:
    features.images: "true"
    features.networks: "true"
    features.networks.zones: "true"
    features.profiles: "true"
    features.storage.buckets: "true"
    features.storage.volumes: "true"
  description: Default Incus project
  name: default

Other notes:

  • Before rebooting, I noticed that several sub-datasets were created under data/incus: buckets, containers, custom and so on
  • Before incus admin init, the data/incus ZFS dataset had its mount point set to /data/incus but after it is legacy
  • All the sub-datasets have mountpoint legacy

Tried so far:

  • manually mounting the dataset with zfs mount
    • fails because the mountpoint is legacy, says to use generic mount instead
  • redoing incus admin init
    • can’t create a storage pool called default because it already exists
  • deleting the default storage pool
    • have to add --force-local to avoid Error: The remote isn't a private server
    • Fails because the storage pool is currently in use

Hypotheses:

  • the zfs-load-key service runs after Incus tries to mount the dataset for the storage pool
    • so I need a different WantedBy, what could it be?
  • need to configure mounts (via /etc/fstab) for the datasets (to where?)
  • I should have added the storage pool manually outside of incus admin init
    • I could still recreate everything and do this but it’s not obvious that it will help and will be tedious
  • Incus shouldn’t have set the mountpoints to legacy and I should set them back to what they were before

How can I configure Incus to auto-mount an encrypted ZFS dataset for its default storage pool?

The remote isn't a private server is a client side error suggesting you’ve incorrectly set your default remote to be an image server or something like that.

Can you show incus remote list? Chances are all you need is a incus remote switch local.

Yep, thanks that is part of it. I was confused about what remotes were and tried to set the default image server as a remote. No longer getting ‘The remote isn’t a private server’. Will try rebooting with that set properly and see if the zfs mounts come back.

`incus remote list` for completeness
+------------------+------------------------------------+---------------+-------------+--------+--------+--------+
|       NAME       |                URL                 |   PROTOCOL    |  AUTH TYPE  | PUBLIC | STATIC | GLOBAL |
+------------------+------------------------------------+---------------+-------------+--------+--------+--------+
| images (current) | https://images.linuxcontainers.org | simplestreams | none        | YES    | NO     | NO     |
+------------------+------------------------------------+---------------+-------------+--------+--------+--------+
| local            | unix://                            | incus         | file access | NO     | YES    | NO     |
+------------------+------------------------------------+---------------+-------------+--------+--------+--------+

Update: after fixing my sub{g,u}id configuration, Incus is working!

Contrary to my expectation, not all the ZFS datasets get mounted by default, but Incus is still using the configured ZFS dataset. In particular, there are many ZFS datasets created, but it seems that only the running containers are mounted.

output of `zfs list`
NAME                                                                                 USED  AVAIL  REFER  MOUNTPOINT
data                                                                                9.22M  96.4G    24K  /data
data/incus                                                                          8.29M  96.4G    98K  legacy
data/incus/buckets                                                                    98K  96.4G    98K  legacy
data/incus/containers                                                                804K  96.4G    98K  legacy
data/incus/containers/alpine-test                                                    706K  96.4G  6.45M  legacy
data/incus/custom                                                                     98K  96.4G    98K  legacy
data/incus/deleted                                                                   588K  96.4G    98K  legacy
data/incus/deleted/buckets                                                            98K  96.4G    98K  legacy
data/incus/deleted/containers                                                         98K  96.4G    98K  legacy
data/incus/deleted/custom                                                             98K  96.4G    98K  legacy
data/incus/deleted/images                                                             98K  96.4G    98K  legacy
data/incus/deleted/virtual-machines                                                   98K  96.4G    98K  legacy
data/incus/images                                                                   6.55M  96.4G    98K  legacy
data/incus/images/7f0266d9ed14443f5ccf8670586547c9ee382b2bbd69b154c92166cd5b48295b  6.45M  96.4G  6.45M  legacy
data/incus/virtual-machines                                                           98K  96.4G    98K  legacy
output of `zfs mount`
data                            /data
data/incus/containers/alpine-test  /var/lib/incus/storage-pools/default/containers/alpine-test