Environment variables are convenient for local development and easy to leak in production. They appear in process inspection, crash dumps, debug tooling, child processes, and management consoles. A systemd service that loads an API key from its environment therefore inherits a long list of accidental disclosure paths. The credential facility is one way to shrink that exposure without building a custom secret loader for every service.
The LoadCredential= and related unit settings give a service a small, read-only credential named by an identifier. The service receives $CREDENTIALS_DIRECTORY, and reads the credential from a path inside that directory. Recent systemd documentation describes the directory as accessible only to the service's user and the superuser, with memory backing intended to avoid disk swap where the platform supports it. That is useful, but it is not the same as making the secret safe against a compromised service identity.
Understand the boundary
A credential is a file delivered to the unit process, not a capability that proves who called it. The service user can read it because the program needs it. Any code running as that user may also try to read it unless the service has further isolation, such as filesystem restrictions, a dedicated dynamic user, and a confined runtime. An attacker who already controls the service account can often read the secret while the service is running.
The gain comes from reducing accidental exposure before the compromise. The secret does not need to appear in the process command line, a global environment block, or a repository checkout. It can be provisioned at unit start, and its lifetime can be tied to the service rather than to an administrator's shell.
Encryption at rest is a separate feature. LoadCredentialEncrypted= can decrypt a credential with a key derived from the machine's trusted hardware or a local secret, depending on systemd configuration. That protects a stored credential file from a casual copy, but the host must still be capable of decrypting it for the service. Define the recovery and migration plan for the key material, or a hardware or boot change may lock the service out.
Build a minimal unit
The service unit should name the credential it needs and avoid passing the value through Environment=. A typical unit might use LoadCredential=api_token:/run/secrets/api_token and start with User=service-user. The application should read ${CREDENTIALS_DIRECTORY}/api_token through a small, audited loader. Do not print the value in a start-up log, command line, or error message.
The source file needs a controlled owner and mode, and the service must start after the source is available. If the file is encrypted, the unit must use the matching encrypted loader and the host must have the required trust material. Test a normal boot, a reboot, a rotation, and a service restart. A credential that works only on the administrator's development host has not been deployed.
Rotate without breaking the unit
The application's authentication design determines whether rotation can be graceful. A service may need to accept the old and new values during a short overlap. Another service may read the credential once at start and need a restart after replacement. Record which behavior applies.
A safe rotation sequence is:
Create the new credential in the trusted source location.
Validate ownership and permissions.
Update the running service or its unit in a controlled way.
Confirm the service can authenticate with the new value.
Revoke the old value at the upstream system.
Inspect logs for accidental disclosure.
Repeat the change through the same automation during a drill.
Avoid putting the secret value in a unit file that is stored in version control. If configuration is distributed as code, keep the encrypted credential reference or a deployment-time path in the repository and keep the plaintext in the host's secret store.
Test the failure modes
Remove the credential for a test unit and confirm that the service fails closed with a useful but non-secret error. Change the file permissions and verify the failure. Restart under a different user. Run systemd-creds list from inside the service context according to the installed version and confirm which names are present. Then inspect how the application reports a rejected credential, because an error path can leak the value even when the loading path is clean.
Systemd credentials reduce one common leak pattern. They do not replace secret rotation, least privilege, network restrictions, or upstream audit. The useful design question is not whether the secret is stored in a file. It is who can read the secret during normal operation, who can use it, how it is revoked, and whether a failure is observable without copying the value into a log.