Many security standards, ISO 27001 among them, require that data at rest is encrypted. On Syself Autopilot you meet that on the hardware you own: you encrypt the disks in your bare metal servers, and only you hold the key that can read them. Encryption at rest stores the data on a disk as ciphertext. Without the key it is just noise, worthless to anyone who ends up with the physical disk. Hetzner already controls who can enter its data centers and wipes every disk before it is reused, so this is not about a disk walking out the door. It is a control you own and can point to in an audit, and it holds even once a disk leaves your hands. You do this with LUKS, the standard way Linux encrypts a disk. You do not need to be a storage expert. You encrypt each data disk once, and from then on it unlocks automatically every time the server starts. > [!WARNING] > You hold the key, and only you. If you lose it, the data on those disks is gone for good. There is no recovery, and nothing Syself can do to bring it back. Before you rely on this, keep a backup of anything you cannot lose on a separate system, and try the full encrypt-and-unlock cycle once on a test server before you use it in production. Disk encryption as a built-in Syself Autopilot feature is planned for a future release. Until then you set it up yourself with the steps below, and the Syself Consulting team can design it with you, set it up, and operate it as a full service. ## How it works, in short There are two steps, and only the second one keeps happening. 1. **You encrypt each disk once.** You run a couple of commands to turn a data disk into an encrypted disk. You do this a single time per disk, when the server joins. 2. **A DaemonSet you run unlocks it at startup.** Each time a server starts, a small privileged DaemonSet on it finds the encrypted disks and opens them with your key, before your storage comes up. Nobody types a password at a console, and your apps use the disk exactly as before. The encrypting and the unlocking are simple and the same on every server. The one thing you decide and control is the key. Encryption sits at the very bottom, directly on the physical disk. On top of the unlocked disk you build the storage that [TopoLVM](/docs/hetzner/apalla/storage/local/local-nvme-with-topolvm) hands out as local volumes. TopoLVM never sees the encryption. It works with the disk as usual, and everything written to it is already encrypted underneath. Because encryption is the bottom layer, it protects every volume at once. Picture it as layers, from the disk at the bottom up to your app: 1. The physical disk holds a locked container. This is the LUKS part. Locked, it is unreadable. 2. Unlocking it opens a readable version of the disk at `/dev/mapper/encrypted-nvme`. 3. LVM builds its volume group and thin pool on that unlocked version, not on the raw disk. 4. TopoLVM serves `local-nvme`, `local-ssd`, and `local-hdd` volumes to your pods from it. A pod that uses a local volume sees none of this and works exactly as before. ## The key is the part you own Everything else is reliable and the same on every server. The one decision that is yours is the key: where it comes from, and how far you trust the path that brings it to a server at boot. The recommendation is to bring your own key and manage it yourself, so control stays with you. You also choose how many keys to run. A LUKS disk holds its own passphrase, so the granularity is yours: one key for the whole cluster, a key per server, or a key per disk, whatever your policy asks. More keys means a single leaked key unlocks less, at the cost of more keys to look after. To keep things simple, start with one key for the whole cluster and all its disks, and split it finer later if your security policy asks for it. > [!IMPORTANT] > The servers have no secure chip (a TPM) to hold the key, so the key arrives on the server as plain text at the moment it unlocks the disk. Your encryption is therefore only as safe as the way you store and deliver the key. Keep the key in a store you control, limit who can read it, and change it from time to time. Getting the key path right is the real work here; the disk commands are the easy part. The DaemonSet reads the key from a file that comes from a Kubernetes Secret. It does not care how the key got there, so any delivery you trust works. A plain Secret is fine only for a first test: ```yaml title="encryption-key.yaml" apiVersion: v1 kind: Secret metadata: name: disk-encryption-key namespace: kube-system type: Opaque stringData: key: "your-passphrase-here" ``` For real use, do not keep the passphrase in a plain Secret. Keep the key of record in a system you own and audit, your own key manager (KMS) or Vault, and copy it into this Secret automatically with the External Secrets Operator, or bring it to the server through another mechanism you trust. The real key stays with you, and the cluster only ever holds the copy it needs to unlock the disk. A LUKS disk can hold several keys at once, so you can change a key without taking anything offline. Find the disk by its hardware id, then add a new passphrase, update your key store, check the new one works, and remove the old one: ```console $ ls -l /dev/disk/by-id/ | grep eui $ DISK=/dev/disk/by-id/nvme-eui.0025388b01b5c3e8 $ cryptsetup luksAddKey "$DISK" $ cryptsetup luksOpen --test-passphrase "$DISK" $ cryptsetup luksRemoveKey "$DISK" ``` If you would rather not build the key handling yourself, the Syself Consulting team can design it with you and set the whole thing up. ## Encrypt a disk once Do this once per data disk, when you first set the server up, in place of the plain disk-preparation step. First open a shell on the server, with a privileged debug pod (`kubectl debug node/ -it --image=busybox --profile=sysadmin -- chroot /host`) or the Hetzner rescue system. Then run these. Adjust the disk name and volume group to match the disk type, the same way [the TopoLVM setup](/docs/hetzner/apalla/storage/local/local-nvme-with-topolvm) does. Lock the disk with a key Find the data disk's stable id first. Kernel names like `/dev/nvme1n1` can swap between disks when a node is reprovisioned, so address the disk by its hardware id instead: ```console $ ls -l /dev/disk/by-id/ | grep eui ``` Each id is a symlink to a kernel name. Check those names against `lsblk`: the OS disk is the one carrying `/` and `/boot`, and it must never be encrypted. Take the id of the other disk. Turn that disk into an encrypted container, protected by a passphrase you choose: ```console $ cryptsetup luksFormat /dev/disk/by-id/nvme-eui.0025388b01b5c3e8 ``` > [!CAUTION] > This erases everything on the disk, so make sure it is a data disk and never the OS disk. Save the passphrase somewhere safe that you will still have after the server is gone. Without it, the data cannot be recovered. Unlock it Open the encrypted disk into a new device you can build storage on: ```console $ cryptsetup luksOpen /dev/disk/by-id/nvme-eui.0025388b01b5c3e8 encrypted-nvme ``` Build the storage on the unlocked device Set up LVM on the unlocked device, `/dev/mapper/encrypted-nvme`, not the raw disk. This is the point of the whole exercise: build on the unlocked device and everything underneath stays encrypted; build on the raw disk and the data is written in the clear. ```console $ pvcreate /dev/mapper/encrypted-nvme $ vgcreate vg-nvme /dev/mapper/encrypted-nvme $ lvcreate --thinpool pool-nvme --extents 100%FREE vg-nvme ``` ## Unlock the disks at startup After a restart the disk is locked again, so something on the server has to unlock it before your storage can use it. The way to automate this is a small privileged DaemonSet that you run on your bare metal nodes: at startup it finds the encrypted disks and opens them with your key, before TopoLVM comes up. You build and run this yourself; you deploy it once and point it at the key, and it behaves the same on every server. If you would rather not, the Syself Consulting team can set it up for you. Run it as a privileged DaemonSet on each bare metal node. It scans the disks for LUKS containers and runs `cryptsetup open` on each one into a `/dev/mapper/encrypted-` device, so the unlocked devices are back before TopoLVM serves volumes. Have it check whether a disk is already open, so a restart is safe to repeat, and no one is needed at the console. The node's operating system does the rest. It ships `cryptsetup` and the `dm_crypt` kernel module, and it activates a volume group the moment its device appears, a plain disk or an unlocked encrypted disk alike. So once a disk is unlocked, its volume group comes up on its own, `lvmd` finds it, and TopoLVM mounts volumes into pods exactly as it does for an unencrypted disk. There is nothing extra to mount. ## Cloud volumes are not encrypted for you Cloud volumes, the `standard` class, are not encrypted by default, and Hetzner offers no switch to turn it on. The CSI driver can do it instead, when you give a StorageClass a Secret holding an `encryption-passphrase`. It then puts LUKS on the volume the first time it mounts it and opens it on every mount after that: ```yaml title="encrypted-storageclass.yaml" apiVersion: v1 kind: Secret metadata: name: encryption-secret namespace: kube-system type: Opaque stringData: encryption-passphrase: "your-passphrase-here" --- apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: standard-encrypted provisioner: csi.hetzner.cloud reclaimPolicy: Retain volumeBindingMode: WaitForFirstConsumer allowVolumeExpansion: true parameters: csi.storage.k8s.io/node-publish-secret-name: encryption-secret csi.storage.k8s.io/node-publish-secret-namespace: kube-system ``` Claims on `standard-encrypted` get a LUKS layer you hold the key to; claims on `standard` do not. There is no need for a DaemonSet and nothing to unlock at boot, because the driver opens the volume as part of mounting it. A cloud server has no secure chip either, so the passphrase still arrives as plain text, and everything above about where the key comes from applies here too. ## What it costs Scrambling and unscrambling the data uses some CPU on every read and write. Modern processors do this in hardware, so the cost is usually small, but it is not zero. On a disk that is already the busy part of a database, measure with and without encryption on your own hardware so you know the real effect. Related: [Set up local NVMe with TopoLVM](/docs/hetzner/apalla/storage/local/local-nvme-with-topolvm) for the storage this sits under, [Encrypt data disks](/docs/hetzner/apalla/security/encrypt-data-disks) for the threat this closes and the key-custody model, and [Tune storage performance](/docs/hetzner/apalla/storage/operations/tune-storage-performance) if the extra CPU starts to show.