# clevis: bind a disk encryption key to a TPM or a Tang server

> Clevis is a pluggable framework for automated decryption that encrypts data as a JWE object bound to a proof, so a LUKS volume can be unlocked at boot by a TPM or a network Tang server with no password prompt. It suits a Linux administrator who wants unattended unlocking, and the pin concept is the whole design.

**latchset/clevis** — Automated Encryption Framework

- Repository: https://github.com/latchset/clevis
- Stars: 1,280 · Forks: 127
- Language: Shell
- License: GPL-3.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/latchset-clevis

## What a pin is, and why the whole design hangs on it

Clevis is a pluggable framework for automated decryption, usable for automated decryption of data or even automated unlocking of LUKS volumes. The vocabulary is small and worth learning precisely. Encrypting data is one command, and the two parameters beyond the plaintext are the pin and the config. The pin, in clevis terminology, is a plugin which implements automated decryption, and you pass the name of a pin. The config is a JSON object which is passed directly to the pin and contains all the necessary configuration to perform encryption and set up automated decryption:

```bash
$ clevis encrypt PIN CONFIG < PLAINTEXT > CIPHERTEXT.jwe
```

Decryption needs nothing:

```bash
$ clevis decrypt < CIPHERTEXT.jwe > PLAINTEXT
```

No additional input and no interaction is required for the decrypt command. That asymmetry is the point of the framework. The pin is a proof, the config says how to check it, and the encrypted blob carries both the ciphertext and the evidence needed to satisfy the check later.

## The Tang pin, and the SSH-like trust prompt

Tang is a server implementation which provides cryptographic binding services without the need for an escrow, and Clevis has full support for it. The example encrypts the message hi using the Tang pin, and the only parameter needed is the URL of the Tang server:

```bash
$ echo hi | clevis encrypt tang '{"url": "http://tang.local"}' > hi.jwe
The advertisement is signed with the following keys:
        kWwirxc5PhkFIH0yE28nc-EvjDY

Do you wish to trust the advertisement? [yN] y
```

During encryption the Tang pin requests the key advertisement from the server and asks you to trust the keys, and the documentation says this works similarly to SSH, which is the right analogy because you are making a one-time decision about whether to believe a server's key. If you would rather not be asked, you can load the advertisement manually with the `adv` parameter, which takes either a string referencing the file where the advertisement is stored or the JSON contents of the advertisement itself. When the advertisement is specified that way, Clevis presumes that it is trusted, so the trust decision moves to you and the boot path stays unattended.

## The TPM pins, and what gets stored in the JWE

Clevis supports Trusted Platform Module 1.2 and 2.0 chips, and the model is the same for both. The cryptographically-strong, random key used for encryption is encrypted using the TPM chip, and is decrypted using the TPM at the time of decryption, which allows clevis to decrypt the secret stored in the JWE. The commands differ only in the pin name:

```bash
$ echo hi | clevis encrypt tpm1 '{}' > hi.jwe
```

```bash
$ echo hi | clevis encrypt tpm2 '{}' > hi.jwe
```

Clevis stores the public and private keys of the encrypted key in the JWE object, so they can be fetched on decryption to unseal the key encrypted using the TPM chip. In other words, the TPM does not store your data key, it seals it, and the sealed form travels inside the JWE. The manual pages for `clevis-encrypt-tpm1` and `clevis-encrypt-tpm2` hold more options, such as binding to particular PCR registry states and values, which is how you tie the unlock to a measurement of the boot state rather than to the mere presence of the chip.

## The TPM1 well-known SRK requirement

The TPM1 pin has a documented limitation that will stop an unattended unlock if you skip it. To avoid prompting for a password during unlocking, the encryption and decryption processes require that the well-known Storage Root Key be configured when taking ownership of the TPM 1.2 chip. That means you must have either run the `tpm_takeownership` command during setup:

```bash
$ tpm_takeownership --srk-well-known
```

or executed the `tpm_changeownerauth` command:

```bash
$ tpm_changeownerauth --srk --set-well-known
```

The documentation adds a clarification that is easy to misread, namely that a well-known key is not the same as an empty key. If you have changed the SRK to a well-known key, you then need to recreate the initramfs image, because /var/lib/tpm is included in it. On Debian-like systems that is `update-initramfs -u`, and on Fedora-like systems it is `dracut -f`. This applies to initramfs-tools and to Dracut in host-only mode, because in Dracut's default mode /var/lib/tpm is already configured to allow access to the TPM 1.2 chip using a well-known SRK.

## A separately encrypted /var, and the chicken-and-egg problem

The most interesting failure mode in the documentation is a separately encrypted /var volume with the TPM1 pin. Because the TPM1 pin relies on the tcsd daemon from the Trousers project to access the TPM 1.2 chip, that daemon must start early in the boot process to unlock the root filesystem automatically, and /var/lib/tpm contains runtime data for tcsd and must be available before the daemon starts. A minimal copy of the required /var files is included in the initramfs image prepared by Clevis, so the daemon should be able to start during the initrd bootup phase if everything is configured correctly. Then comes the catch. After switching to the real root filesystem, the System Manager bootup phase starts and /var is mounted from the actual target, and at this point Clevis cannot unlock it, because tcsd would need /var to unlock /var. So it must already be unlocked, which is the circular dependency the configuration has to break. If the /var volume is part of the main LVM volume group and protected by the same LUKS volume, no special configuration is needed. If it is encrypted separately, with a different LUKS volume and even the same password, you have to follow the extra instructions.

## The crypttab change that makes /var work

The fix for a separately encrypted /var is a one-line change to /etc/crypttab, and the mechanism is worth understanding. The initramfs-tools unlock of the root and swap filesystems works by copying the corresponding option lines from /etc/crypttab into the initramfs, so to get the /var volume options included you add the `initramfs` option on the relevant line on a Debian-like system:

```bash
luks-aa0ce19c-cde9-44a2-adbd-4afb1845a959 UUID=aa0ce19c-cde9-44a2-adbd-4afb1845a959 none discard,initramfs
```

That line corresponds to the crypto_LUKS volume used by the /var volume, which you can confirm with the `lsblk -fp` command. The documentation shows the layout for both schemes, an LVM on LUKS arrangement where /dev/vda3 is the crypto_LUKS volume and /dev/mapper/separate-var is the xfs filesystem mounted at /var, and a LUKS on LVM arrangement where the LVM member sits below the crypto_LUKS volume. The same applies to both, and the instruction is simply to check the crypto_LUKS volume UUID. The LUKS-on-LVM case is the one where the mistake is easy to make, because the partition in the output looks like a plain LVM member and the crypto_LUKS layer is one level further down.

## The project itself, and how it is built

The repository is a small one, with `src/`, a `meson.build`, a `meson_options.txt`, an `INSTALL.md`, a `COPYING` and a `COPYING.openssl`, an `.fmf/` directory for test metadata, a `.packit.yaml` for distribution, and `src/` holding the code. The primary language is recorded as Shell, which is consistent with a tool that is mostly a small set of commands and scripts with a plugin architecture. The licence is GPL-3.0, the project is not archived, and the last push was on 2026-10-16. The release tags are plain version numbers rather than semver, v24 on 2026-10-15, v23 on 2026-05-13 and v22 on 2026-03-16, so the version tracks the distribution's package version rather than a library API version. The `.fmf/` directory and the `packit.yaml` are the Fedora packaging metadata, which tells you this is packaged and shipped by distributions rather than installed from source by hand, and `INSTALL.md` is where the distribution-specific install instructions live, since the upstream project expects the packager to wire clevis into the initramfs and the boot process.

## Conclusion

Adopt clevis if you need your LUKS volumes to unlock automatically at boot on a machine with a TPM or a reachable Tang server, because binding the key to a hardware proof removes the password prompt from the boot path. Skip it if you need an interactive passphrase on a machine without either of those, since clevis has no pin for that case. Before you deploy, check the TPM1 well-known SRK requirement, because the TPM1 pin needs the Storage Root Key to be set to the well-known value before encryption and decryption can avoid prompting, and remember that a separately encrypted /var volume needs extra initramfs configuration, since the tcsd daemon must start before /var is unlocked.

## FAQ

### What is a pin in Clevis?

A pin is a plugin which implements automated decryption, and you pass the pin's name to clevis. The config is a JSON object passed directly to the pin containing the configuration needed for encryption and automated decryption.

### How do I encrypt and decrypt data with clevis?

Encrypt with `clevis encrypt PIN CONFIG < PLAINTEXT > CIPHERTEXT.jwe`, and decrypt with `clevis decrypt < CIPHERTEXT.jwe > PLAINTEXT`. The decrypt command needs no additional input or interaction.

### What does the TPM1 pin need before it can unlock without a password?

The well-known Storage Root Key must be configured when taking ownership of the TPM 1.2 chip, by running `tpm_takeownership --srk-well-known` during setup or `tpm_changeownerauth --srk --set-well-known`. A well-known key is not the same as an empty key.

### How do I make a separately encrypted /var volume work with the TPM1 pin?

Add the initramfs option to the relevant line in /etc/crypttab so the volume options are copied into the initramfs image, and regenerate the image with update-initramfs -u on Debian-like systems or dracut -f on Fedora-like systems. If /var shares the main LUKS volume, no special configuration is needed.

### Can I skip the trust prompt when using the Tang pin?

Yes. Supply the advertisement manually with the adv parameter, which takes either a path to the file holding the advertisement or the JSON contents of the advertisement. When the advertisement is specified manually, Clevis presumes that it is trusted.

## Sources

- [Issues](https://github.com/latchset/clevis/issues)
- [latchset/clevis on GitHub](https://github.com/latchset/clevis)
- [License: GPL-3.0](https://github.com/latchset/clevis/blob/master/LICENSE)
- [README](https://github.com/latchset/clevis/blob/master/README.md)
- [Releases](https://github.com/latchset/clevis/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/latchset-clevis
