Load age encrypted credentials in systemd units.
Note: This is a fork of josh/systemd-age-creds, which is now archived. This version provides simple binary distribution instead of the original Nix-based deployment.
At the moment, systemd-creds only support symmetric encryption requiring secrets to be encrypted on the machine with the TPM itself. Though, it's on the systemd TODO to add one day.
Solutions like SOPS allow secrets to be encrypted elsewhere, checked into git and then only decrypted on the deployment host. It would be nice if a similar pattern could be applied to systemd credentials.
systemd-age-creds provides a service credential server over AF_UNIX socket to provide age encrypted credentials to systemd units using LoadCredential.
Download and install the RPM package from the latest release:
# Download the RPM
VERSION=v1.4.0 # Replace with latest version
ARCH=$(uname -m) # x86_64 or aarch64
curl -LO https://github.com/abyrne55/systemd-age-creds/releases/download/${VERSION}/systemd-age-creds-1.4.0-1.fc42.${ARCH}.rpm
# Verify checksum
curl -LO https://github.com/abyrne55/systemd-age-creds/releases/download/${VERSION}/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing
# Install (will automatically install age if available in repos)
sudo dnf install ./systemd-age-creds-*.rpm
# Enable and start the socket
sudo systemctl enable --now systemd-age-creds.socketDownload and install the binary from the latest release:
# Download the tarball
VERSION=v1.4.0 # Replace with latest version
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
curl -LO https://github.com/abyrne55/systemd-age-creds/releases/download/${VERSION}/systemd-age-creds-${VERSION}-linux-${ARCH}.tar.gz
# Verify checksum
curl -LO https://github.com/abyrne55/systemd-age-creds/releases/download/${VERSION}/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing
# Extract and install
tar -xzf systemd-age-creds-${VERSION}-linux-${ARCH}.tar.gz
sudo install -m 755 systemd-age-creds /usr/local/bin/systemd-age-creds
sudo cp systemd/systemd-age-creds.socket /etc/systemd/system/
sudo cp systemd/systemd-age-creds.service /etc/systemd/system/
sudo systemctl daemon-reload
# Enable and start the socket
sudo systemctl enable --now systemd-age-creds.socket# Clone the repository
git clone https://github.com/abyrne55/systemd-age-creds.git
cd systemd-age-creds
# Build and install
make install
# Enable and start the socket
sudo systemctl enable --now systemd-age-creds.socketsystemd-age-creds requires age to be installed. Install it using your package manager:
Fedora/RHEL:
sudo dnf install ageDebian/Ubuntu:
sudo apt install ageArch Linux:
sudo pacman -S agemacOS (for local development):
brew install ageOr download binaries from the age releases page.
# Create directories
sudo mkdir -p /etc/age/credentials
# Generate an age identity (or copy your existing one)
sudo age-keygen -o /etc/age/identity.txt
sudo chmod 600 /etc/age/identity.txt
# Encrypt a credential
echo "my-secret-value" | age -r $(sudo age-keygen -y /etc/age/identity.txt) \
| sudo tee /etc/age/credentials/my-credential.age > /dev/nullOther systemd services can load decrypted credentials using LoadCredential:
[Service]
LoadCredential=my-credential:%t/systemd-age-creds.sock
ExecStart=/usr/bin/myappThe decrypted credential will be available at /run/credentials/<unit-name>/my-credential.
foo.service
[Service]
ExecStart=/usr/bin/myservice.sh
# Instead of loading a symmetrically encrypted systemd cred from a file,
# LoadCredentialEncrypted=foobar:/etc/credstore/myfoobarcredential.txt
#
# You can reference the credential id loading from the systemd-age-creds socket.
LoadCredential=foobar:%t/systemd-age-creds.sockThe default configuration looks for:
- Age identity:
/etc/age/identity.txt - Encrypted credentials:
/etc/age/credentials/*.age
If your files are in different locations, create a systemd drop-in override:
sudo systemctl edit systemd-age-creds.serviceThen add:
[Service]
Environment=AGE_IDENTITY=/path/to/your/identity.txt
Environment=AGE_DIR=/path/to/your/credentialsSave and reload:
sudo systemctl daemon-reload
sudo systemctl restart systemd-age-creds.socketTest that credentials are being served correctly:
sudo systemd-run -p LoadCredential=my-credential:/run/systemd-age-creds.sock \
cat /run/credentials/run-*/my-credentialCheck the service status:
sudo systemctl status systemd-age-creds.service
sudo journalctl -u systemd-age-creds.serviceCheck the socket status:
sudo systemctl status systemd-age-creds.socketCommon issues:
- Permission denied errors: Ensure
/etc/age/identity.txthas mode 600 and is owned by root - Credential not found: Verify the
.agefile exists in/etc/age/credentials/(or your customAGE_DIR) - age binary not found: Install age using your package manager (see "Installing age" section)