SYSTEMD-CREDS(1)
๐ systemd-creds โ the manual, but make it cute โจ
okay bestie, gather round, because this is systemd-creds from the systemd-creds(1) manual and she is serving credential-management realness ๐
no cap.
๐ธ NAME ๐ธ
systemd-creds โ lists, shows, encrypts and decrypts service credentials. that's it, that's the whole job, and she does it flawlessly ๐ซถ
โจ SYNOPSIS โจ
systemd-creds [OPTIONS...] COMMAND [ARGS...]
๐ฆ DESCRIPTION ๐ฆ
so systemd-creds is the little tool that lists, shows, encrypts and decrypts unit credentials. and what even are credentials? they're limited-size binary or textual objects that get passed to unit processes ๐. their main character purpose is passing cryptographic keys (both public and private, yes both, she's versatile) or certificates, user account info, or identity info from the host over to services.
credentials get configured in unit files through these settings: ImportCredential=, LoadCredential=, SetCredential=, LoadCredentialEncrypted=, and SetCredentialEncrypted=. if you want the deets on those, go read systemd.exec(5), she's got you.
and for even more info, there's the System and Service Credentials[1] documentation. iykyk ๐
๐ COMMANDS ๐
here's what she understands, bestie:
listโ shows you a list of the credentials that got passed into the current execution context. lowkey what it actually does is show the files in the directory that$CREDENTIALS_DIRECTORYpoints at, and it's meant to be run from inside a service context, fr fr.
next to every credential name you also get its size and its security state. that security state is one of:
"secure"โ when the credential is backed by unswappable memory, i.e."ramfs"๐"weak"โ when it's backed by any other type of memory ๐ฌ"insecure"โ if it has any access mode that is not0400, i.e. if it's readable by literally anyone who isn't the owner ๐
Added in version 250.
cat credential...โ shows the contents of the credentials you name that got passed into the current execution context. takes one or more credential names, and their contents get written to standard output. ๐ฑ
when you combine it with --json= or --transcode=, the output gets transcoded in simple ways before it's outputted.
Added in version 250.
setupโ generates a host encryption key for credentials, but only if one hasn't already been generated. this is the one that makes sure/var/lib/systemd/credential.secretis initialized with a random secret key if it doesn't exist yet ๐. that secret key is what gets used when you encrypt/decrypt credentials withencryptordecrypt, and it's only accessible to the root user, periodt.
note that there's typically no need to invoke this command explicitly, because it's implicitly called whenever encrypt is invoked and credential host key encryption is selected. so like, she shows up uninvited, but in a helpful way ๐
Added in version 250.
encrypt input|- output|-โ loads the specified (unencrypted plaintext) input credential file, encrypts it, and writes the (encrypted ciphertext) output to the specified target credential file. the resulting file can be referenced in theLoadCredentialEncrypted=setting in unit files, or its contents can be used literally inSetCredentialEncrypted=settings. iconic behavior honestly.
it takes two file system paths. the file name part of the output path gets embedded as the name in the encrypted credential, so that encrypted credentials can't be renamed and reused for different purposes without anybody noticing ๐. you can override the credential name to embed with the --name= setting. the input or output paths can be specified as "-", and in that case the credential data gets read from / written to standard input and standard output. and heads up: if the output path is specified as "-", the credential name can't be derived from the file system path, so you should specify it explicitly via the --name= switch.
the credential data is encrypted and authenticated symmetrically with one of these encryption keys:
- a secret key automatically derived from the system's TPM2 chip. this encryption key is not stored on the host system, so decryption is only possible with access to the original TPM2 chip. in other words, a credential secured this way can only be decrypted again by the local machine. ๐ฅ๏ธ
- a secret key stored in the
/var/lib/systemd/credential.secretfile, which is only accessible to the root user. this "host" encryption key is stored on the host file system, so decryption is possible with access to the host file system and sufficient privileges. the key gets automatically generated when needed, but you can also create it explicitly with thesetupcommand, see above. - a combination of the above: an encryption key derived from both the TPM2 chip and the host file system. this means decryption requires both access to the original TPM2 chip and the OS installation. this is the default mode of operation if a TPM2 chip is available and
/var/lib/systemd/resides on persistent media. slay.
which of the three keys gets used for encryption can be configured with the --with-key= switch. depending on the use-case for the encrypted credential, the key to use may differ. for example, for credentials that shall be accessible from the initrd, encryption with the host key is not appropriate, since access to the host key is typically not available from the initrd. so for those credentials, only the TPM2 key should be used.
encrypted credentials are always encoded in Base64. always. no exceptions ๐
use decrypt (see below) to undo the encryption operation, and to acquire the decrypted plaintext credential from the encrypted ciphertext credential.
the credential data is encrypted using AES256-GCM, i.e. providing both confidentiality and integrity, keyed by a SHA256 hash of one or both of the secret keys described above. ๐
Added in version 250.
decrypt input|- [output|-]โ undoes the effect of theencryptoperation: loads the specified (encrypted ciphertext) input credential file, decrypts and authenticates it, and writes the (decrypted plaintext) output to the specified target credential file. it's giving reversible ๐
takes one or two file system paths. the file name part of the input path is compared with the credential name embedded in the encrypted file. if it doesn't match, decryption fails โ. this is done to make sure encrypted credentials aren't re-purposed without this being detected. the credential name to compare with the embedded credential name can also be overridden with the --name= switch. if the input path is specified as "-", the encrypted credential is read from standard input. if only one path is specified, or the output path is specified as "-", the decrypted credential is written to standard output. in this mode, the expected name embedded in the credential can't be derived from the path, and should be specified explicitly with --name=.
decrypting credentials requires access to the original TPM2 chip and/or the credentials host key, see above. info about which keys are required is embedded in the encrypted credential data, so decryption is entirely automatic ๐ช.
Added in version 250.
--no-ask-passwordโ do not query the user for authentication for privileged operations. she's not gonna bug you about it ๐-h,--helpโ print a short help text and exit. classic.--versionโ print a short version string and exit. also classic.
๐ OPTIONS ๐
--systemโ when specified with thelistandcatcommands, operates on the credentials passed to system as a whole instead of on those passed to the current execution context. super useful in container environments where credentials may be passed in from the container manager ๐ฆ
Added in version 250.
--userโ when specified with theencryptanddecryptcommands, encrypts a user-scoped (rather than a system-scoped) credential. use--uid=to select which user the credential is from. such credentials may only be decrypted from the specified user's context, unless privileges can be acquired. generally: when an encrypted credential shall be used in the per-user service manager it should be encrypted with this option set, and when it shall be used in the system service manager it should be encrypted without it. ๐ง
internally, this ensures that the selected user's numeric UID and username, as well as the system's machine-id(5), are incorporated into the encryption key.
Added in version 256.
--uid=โ specifies the user to encrypt the credential for. takes a user name or numeric UID. if set, it implies--user. if set to the special string"self", it sets the user to the user of the calling process. and if--useris used without--uid=, then--uid=selfis implied, i.e. the credential is encrypted for the calling user ๐
Added in version 256.
--transcode=โ when specified with thecatordecryptcommands, transcodes the output before showing it. takes one of"base64","unbase64","hex"or"unhex"as argument, in order to encode/decode the credential data with Base64 or as a series of hexadecimal values. the special value"help"may be used to list supported transcode types ๐
note that this has no effect on the encrypt command, because encrypted credentials are unconditionally encoded in Base64.
Added in version 250.
--newline=โ when specified withcatordecrypt, controls whether to add a trailing newline character to the end of the output if it doesn't already end in one. takes one of"auto","yes"or"no". the default mode of"auto"will suffix the output with a single newline character only when writing credential data to a TTY. ๐
Added in version 250.
--pretty,-pโ when specified withencrypt, controls whether to show the encrypted credential as aSetCredentialEncrypted=setting that may be pasted directly into a unit file. only has an effect when used together with--name=and"-"as the output file. copy-paste queen ๐โจ
Added in version 250.
- *
--name=name* โ when specified with theencryptcommand, controls the credential name to embed in the encrypted credential data. if not specified, the name is chosen automatically from the filename component of the specified output path. if specified as an empty string, no credential name is embedded in the encrypted credential, and no verification of credential name is done when the credential is decrypted. ๐ท๏ธ --name=โ okay so for the decrypt command, this controls the credential name that the name baked into the encrypted credential gets validated against ๐ต๏ธโ๏ธ If you don't pass it, the name is picked automatically from the filename component of the input path you gave. But bestie, listen: if there's no credential name embedded in the encrypted credential file at all (i.e.--name=with an empty string was used at encryption time), then whatever name you specify here does nothing โ because no credential name validation is happening. Periodt.
Why embed the name in the first place? To protect against credentials being reused for purposes they were never meant for ๐ โ under the assumption that the credential name is chosen carefully to encode its intended purpose.
Added in version 250.
--timestamp=timestampโ with the encrypt command, this controls the timestamp embedded into the encrypted credential. Defaults to the current time. It takes a timestamp specification in the format described insystemd.time(7)โฐ
With the decrypt command, this controls the timestamp used to validate the "not-after" timestamp that was configured with --not-after= during encryption. If you don't specify it, it defaults to the current system time.
Added in version 250.
--not-after=timestampโ with the encrypt command, this controls the time when the credential shall not be used anymore ๐ค It embeds that timestamp into the encrypted credential. During decryption, the timestamp gets checked against the current system clock, and if the timestamp is in the past, the decryption will fail. By default, no such timestamp is set. Takes a timestamp specification in the format described insystemd.time(7).
Added in version 250.
--with-key=,-H,-Tโ with the encrypt command, this controls the encryption/signature key to use ๐ It takes one of"host","tpm2","host+tpm2","null","auto","auto-initrd". See above for the deets on the key types.
If it's set to "auto" (which is the default), the TPM2 key is used if a TPM2 device is found and we're not running in a container. The host key is used if /var/lib/systemd/ is on persistent media. Which means on typical systems, encryption is by default bound to both the TPM2 chip and the OS installation โ and both need to be available to decrypt the credential again ๐ฏโ๏ธ If "auto" is selected but neither TPM2 is available (or we're in a container) nor /var/lib/systemd/ is on persistent media, encryption will fail.
If it's set to "null", a fixed zero length key is used โ so, in this mode, no confidentiality nor authenticity are provided!! ๐ That logic is useful for covering systems that lack a TPM2 chip but where credentials still need to be generated. Note that decryption of such credentials is refused on systems that have a TPM2 chip and where UEFI SecureBoot is enabled (this is done so that such a locked-down system cannot be tricked into loading a credential generated this way that lacks authentication information. If either UEFI SecureBoot or a TPM2 are not available, then loading such credentials is allowed by default).
If it's set to "auto-initrd", a TPM2 key is used if a TPM2 is found. If not, a fixed zero length key is used โ equivalent to "null" mode. This option is particularly useful to generate credential files that are encrypted/authenticated against TPM2 where available but still work on systems lacking support for this โจ
The special value "help" may be used to list supported key types.
systemd v262 and later additionally pin the encrypted credential to the TPM2's SRK to defend against MITM interposer attacks when decrypting credentials ๐ก๏ธ This makes the resulting credentials incompatible with earlier systemd versions.
The -H switch is a shortcut for --with-key=host. Similarly, -T is a shortcut for --with-key=tpm2.
When encrypting credentials that shall be used in the initrd (where /var/lib/systemd/ is typically not available), make sure to use --with-key=auto-initrd mode, to disable binding against the host secret ๐
This switch has no effect on the decrypt command, because the information on which key to use for decryption is already included in the encrypted credential.
Added in version 250.
--tpm2-device=PATHโ controls the TPM2 device to use. Expects a device node path referring to the TPM2 chip (e.g./dev/tpmrm0). Alternatively, the special value"auto"may be specified, in order to automatically determine the device node of a suitable TPM2 device (of which there must be exactly one). The special value"list"may be used to enumerate all suitable TPM2 devices currently discovered ๐
Added in version 250.
--tpm2-pcrs=PCR[+PCR...]โ configures the TPM2 PCRs (Platform Configuration Registers) to bind the encryption key to ๐งฉ Takes a"+"separated list of numeric PCR indexes in the range0...23. If an empty string is specified, it binds the encryption key to no PCRs at all (this is also the default if this option is not used). For details about the PCRs available, see the documentation of the switch of the same name forsystemd-cryptenroll(1).
Added in version 250.
--tpm2-public-key=PATH,--tpm2-public-key-pcrs=PCR[+PCR...]โ configures a TPM2 signed PCR policy to bind encryption to, for use with the encrypt command. The--tpm2-public-key=option accepts a path to a PEM encoded RSA public key, to bind the encryption to. If this isn't specified explicitly, but a filetpm2-pcr-public-key.pemexists in one of the directories/etc/systemd/,/run/systemd/,/usr/lib/systemd/(searched in this order), it's automatically used ๐
The --tpm2-public-key-pcrs= option takes a list of TPM2 PCR indexes to bind to (same syntax as --tpm2-pcrs= described above). If not specified, it defaults to 11 (i.e. this binds the policy to any unified kernel image for which a PCR signature can be provided).
Note the difference between --tpm2-pcrs= and --tpm2-public-key-pcrs=: the former binds decryption to the current, specific PCR values; the latter binds decryption to any set of PCR values for which a signature by the specified public key can be provided ๐คฏ The latter is hence more useful in scenarios where software updates shall be possible without losing access to all previously encrypted secrets.
Added in version 252.
--tpm2-signature=PATHโ takes a path to a TPM2 PCR signature file as generated by thesystemd-measure(1)tool, and that may be used to allow the decrypt command to decrypt credentials that are bound to specific signed PCR values โ๏ธ If this isn't specified explicitly, and a credential with a signed PCR policy is attempted to be decrypted, a suitable signature filetpm2-pcr-signature.jsonis searched for in/etc/systemd/,/run/systemd/,/usr/lib/systemd/(in this order) and used.
Added in version 252.
--allow-nullโ allow decrypting credentials that use a null key. By default, decryption of credentials encrypted/authenticated with a null key is only allowed if UEFI SecureBoot is off or if a TPM2 is not available ๐
Added in version 256.
--refuse-nullโ refuse decrypting credentials that use a null key, regardless of the UEFI SecureBoot state or TPM2 availability (see above) ๐ซ
Added in version 259.
--quiet,-qโ suppress additional output ๐คซ
Added in version 251.
--no-pagerโ do not pipe output into a pager.--no-legendโ do not print the legend, i.e. column headers and the footer with hints.--json=MODEโ shows output formatted as JSON ๐งพ Expects one of"short"(for the shortest possible output without any redundant whitespace or line breaks),"pretty"(for a pretty version of the same, with indentation and line breaks) or"off"(to turn off JSON output, the default).
โจ EXIT STATUS โจ
On success, 0 is returned. That's it, bestie, a clean little 0 ๐
๐ธ EXAMPLES ๐ธ
Example 1. Encrypt a password for use as credential
The following command line encrypts the specified password "hunter2", writing the result to a file password.cred:
# echo -n hunter2 | systemd-creds encrypt - password.cred
This decrypts the file password.cred again, revealing the literal password:
# systemd-creds decrypt password.cred
hunter2
Example 2. Encrypt a password and include it in a unit file
The following command line prompts the user for a password and generates a SetCredentialEncrypted= line from it for a credential named "mysql-password", suitable for inclusion in a unit file:
# systemd-ask-password -n | systemd-creds encrypt --name=mysql-password -p - -
๐ Password: ****
SetCredentialEncrypted=mysql-password: \
k6iUCUh0RJCQyvL8k8q1UyAAAAABAAAADAAAABAAAAASfFsBoPLIm/dlDoGAAAAAAAAAA \
NAAAAAgAAAAAH4AILIOZ3w6rTzYsBy9G7liaCAd4i+Kpvs8mAgArzwuKxd0ABDjgSeO5k \
mKQc58zM94ZffyRmuNeX1lVHE+9e2YD87KfRFNoDLS7F3YmCb347gCiSk2an9egZ7Y0Xs \
700Kr6heqQswQEemNEc62k9RJnEl2q7SbcEYguegnPQUATgAIAAsAAAASACA/B90W7E+6 \
yAR9NgiIJvxr9bpElztwzB5lUJAxtMBHIgAQACCaSV9DradOZz4EvO/LSaRyRSq2Hj0ym \
gVJk/dVzE8Uxj8H3RbsT7rIBH02CIgm/Gv1ukSXO3DMHmVQkDG0wEciyageTfrVEer8z5 \
9cUQfM5ynSaV2UjeUWEHuz4fwDsXGLB9eELXLztzUU9nsAyLvs3ZRR+eEK/A==
The generated line can be pasted 1:1 into a unit file, and will ensure the acquired password will be made available in the $CREDENTIALS_DIRECTORY/mysql-password credential file for the started service ๐ซ
Utilizing the unit file drop-in logic, this can be used to securely pass a password credential to a unit. A similar, more comprehensive set of commands to insert a password into a service xyz.service:
# mkdir -p /etc/systemd/system/xyz.service.d
# systemd-ask-password -n | ( echo "[Service]" && systemd-creds encrypt --name=mysql-password -p - - ) >/etc/systemd/system/xyz.service.d/50-password.conf
# systemctl daemon-reload
# systemctl restart xyz.service
๐ฆ SEE ALSO ๐ฆ
systemd(1), systemd.exec(5), systemd-measure(1)
๐ NOTES ๐
- System and Service Credentials https://systemd.io/CREDENTIALS
okay that's the whole page bestie, you ate that ๐
This was systemd 262.1 serving up SYSTEMD-CREDS(1) realness ๐ go forth and encrypt responsibly, mwah ๐ซถ๐
๐ฆ where this page comes from
- arch rolling: systemd 262.1-1 ยท LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later AND MIT-0
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms