Before version 1.33.0, LINSTORⓇ did not have a method of entering the LINSTOR controller service master passphrase when the service was restarted unless it was stored in plain text within the .toml configuration file for the service, or stored in an environment variable. The LINSTOR controller service uses the LINSTOR master passphrase for the LINSTOR encypted disk feature. For security-conscious users, storing a sensitive encryption key in plain text on disk presents a risk.
With a feature added in LINSTOR version 1.33.0, LINSTOR users can use the systemd-creds utility to store a hashed version of the passphrase. By using this feature, the LINSTOR controller service can automatically unlock encrypted volumes on startup without exposing a plain text passphrase. This method requires either physical TPM 2.0 hardware or TPM 2.0 emulation for virtual machines. You can enter a systemd-analyze has-tpm2 (or systemd-creds has-tpm2 on older systemd versions) command to verify that your system supports TPM 2.0.
Method 1: Using a systemd service file
Use systemd-ask-password to collect the passphrase, then pipe it into systemd-creds to generate a host-specific encrypted credential:
systemd-ask-password -n | systemd-creds --name=linstor-masterpassphrase encrypt -p - -
Example output:
🔐 Password: •••••••
Credential secret file '/var/lib/systemd/credential.secret' is not located on encrypted media, using anyway.
SetCredentialEncrypted=linstor-masterpassphrase: \
Whxqht+dQJax1aZeCGLxmiAAAAABAAAADAAAABAAAADJwSSiH4neI09LWpQAAAAA2Tx+P \
1teV6QaDhlioJChA775cKFZzWNgHCXy8dvYvkcl/wWQgVej+1NvkZVL9pZIvNjNKgmVW9 \
lmmvZsX4sm+oeBuHhKpZeoYQ==
❗ IMPORTANT: In a highly available LINSTOR controller service configuration, each system that could host the LINSTOR controller service must generate its own hashed passphrase. You cannot copy a credential from one host to another. The hash is unique per host.
Use the following command to edit the LINSTOR controller systemd unit override on each potential LINSTOR controller node:
systemctl edit linstor-controller.service
Copy the generated SetCredentialEncrypted=... string into the service override:
### Editing /etc/systemd/system/linstor-controller.service.d/override.conf
### Anything between here and the comment below will become the new contents of the file
[Service]
SetCredentialEncrypted=linstor-masterpassphrase: \
Whxqht+dQJax1aZeCGLxmiAAAAABAAAADAAAABAAAADJwSSiH4neI09LWpQAAAAA2Tx+P \
1teV6QaDhlioJChA775cKFZzWNgHCXy8dvYvkcl/wWQgVej+1NvkZVL9pZIvNjNKgmVW9 \
lmmvZsX4sm+oeBuHhKpZeoYQ==
### Lines below this comment will be discarded
[...]
Restart the LINSTOR controller service to load the new masterpassphrase:
systemctl restart linstor-controller.service
You should now see a log message confirming that the LINSTOR controller service is using systemd-creds:
journalctl -u linstor-controller.service | grep masterpass
Example output:
Oct 14 17:52:36 linstor-ctrl-0 Controller[3371]: 2025-09-17 17:52:36.335 [Main] INFO LINSTOR/Controller/ffffff SYSTEM - Using masterpassphrase provided by systemd-creds
Alternatively, you can verify that the LINSTOR controller service is unlocked using the LINSTOR REST API:
curl -X GET http://127.0.0.1:3370/v1/encryption/passphrase
Expected response from the API:
{"status":"unlocked"}
If the passphrase is not loaded, the status will show as unset or locked.
Method 2: Starting without a service file
For advanced use cases where the LINSTOR controller service is not managed by a systemd unit, you can still use systemd-creds to create an encrypted credential and pass it to the LINSTOR controller service manually.
The following command creates a file named ciphertext.cred in your working directory containing the hashed passphrase:
systemd-ask-password -n | systemd-creds --name=linstor-masterpassphrase encrypt - ciphertext.cred
The resulting ciphertext.cred file containing the hashed passphrase will look similar to this:
cat ciphertext.cred
Whxqht+dQJax1aZeCGLxmiAAAAABAAAADAAAABAAAACgSALHCD7qGvD9AK4AAAAAg5EUvX6ohi6BJSV
uaC56a57qFAHvbTYlZBWvuUj23GKFidELIacN//2Kz5zRNknV9vGQ/fmTdUdoIMtWAWnhICT41+gRWK
I=
You can then start the LINSTOR controller service manually by using systemd-run, loading the credentials as part of the process:
systemd-run --wait --pty --unit=$UNIT_NAME --working-directory=${WORKING_DIR} --send-sighup \
-p LoadCredentialEncrypted=linstor-masterpassphrase:/root/ciphertext.cred \
/usr/bin/java -Xms256M -Xmx8G -XX:+CrashOnOutOfMemoryError \
-classpath "/usr/share/linstor-server/lib/conf:/usr/share/linstor-server/lib/*" com.linbit.linstor.core.Controller \
--logs=/var/log/linstor-controller --config-directory=/etc/linstor
In the startup logs, there should be a line similar to the following confirming the LINSTOR controller service is using the systemd-creds:
2025-10-14 17:35:40.758 [Thread-2] INFO LINSTOR/Controller/ffffff SYSTEM - Using masterpassphrase provided by systemd-creds
Alternatively, you can verify the unlocked state with the same API call used in method 1:
curl -X GET http://127.0.0.1:3370/v1/encryption/passphrase
Conclusion
By using systemd-creds to store the LINSTOR controller service master passphrase, administrators can improve their security posture by avoiding plain text storage of sensitive credentials. Whether used via a systemd service file or passed at runtime, this method ensures that passphrases are not only hashed, but are TPM-bound and host-specific, reducing the attack surface significantly.
Again, to highlight the importance of the fact, each host in a highly available LINSTOR controller service setup must generate its own hashed passphrase, because credentials cannot be shared across different systems.