Don't bind systemd-creds to a specific credential name

Omit --name= from systemd-creds encrypt so the encrypted credential
can be loaded under any name via LoadCredentialEncrypted=. Previously,
the embedded name had to match the credential name in the service
unit, causing decryption failures when services used different names.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Roman Kivalin
2026-04-13 23:29:26 +02:00
co-authored by Claude Opus 4.6
parent 37f6e4d443
commit 96f98352a8
6 changed files with 13 additions and 12 deletions
+2
View File
@@ -9,6 +9,8 @@
### Fixes
- Don't embed credential name in `systemd-creds encrypt`, allowing services to load credentials under any name
### Changes
## 0.4.0 (2026-04-13)
+3 -1
View File
@@ -1,6 +1,8 @@
certforge (0.5.0-1) unstable; urgency=low
*
* Support multiple zones per DNS client with automatic zone matching
* Config validation for domain/DANE zone matching
* Don't bind systemd-creds to a specific credential name
-- Roman Kivalin <roman@shl.dev> Sun, 13 Apr 2026 22:00:00 +0000
+1 -1
View File
@@ -74,7 +74,7 @@ impl AcmeClient {
.map_err(|e| Error::Config(format!("failed to serialize credentials: {e}")))?;
if let Some(cred_path) = &config.account_key_credential {
credentials::encrypt_credential("acme-account-key", &creds_json, cred_path)
credentials::encrypt_credential(&creds_json, cred_path)
.await?;
tracing::info!(path = %cred_path.display(), "saved account credentials (encrypted)");
} else if let Some(file_path) = &config.account_key_path {
+3 -3
View File
@@ -45,15 +45,15 @@ async fn decrypt_credential(path: &Path) -> Result<Vec<u8>> {
/// Encrypt data and write it to an encrypted credential file.
///
/// Uses `systemd-creds encrypt --name=<name> - <path>`.
pub async fn encrypt_credential(name: &str, data: &[u8], path: &Path) -> Result<()> {
/// Credentials are not bound to a specific name, allowing services to
/// load them under any credential name via LoadCredentialEncrypted=.
pub async fn encrypt_credential(data: &[u8], path: &Path) -> Result<()> {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let mut child = Command::new("systemd-creds")
.arg("encrypt")
.arg(format!("--name={name}"))
.arg("-")
.arg(path)
.stdin(std::process::Stdio::piped())
+3 -5
View File
@@ -227,7 +227,7 @@ fn print_init_commands(config: &config::Config) {
if let Some(path) = &config.acme.account_key_credential {
println!(
"# ACME account key (will be auto-generated if not present)\nsystemd-creds encrypt --name=acme-account-key - {}\n",
"# ACME account key (will be auto-generated if not present)\nsystemd-creds encrypt - {}\n",
path.display()
);
}
@@ -235,9 +235,8 @@ fn print_init_commands(config: &config::Config) {
for (name, dns) in &config.dns {
if let Some(path) = &dns.tsig_key_credential {
println!(
"# DNS TSIG key for '{name}' (zones: {:?})\nsystemd-creds encrypt --name={} - {}\n",
"# DNS TSIG key for '{name}' (zones: {:?})\nsystemd-creds encrypt - {}\n",
dns.all_zones(),
dns.tsig_key_name,
path.display()
);
}
@@ -246,8 +245,7 @@ fn print_init_commands(config: &config::Config) {
for cert in &config.certificates {
if let Some(path) = &cert.key_credential {
println!(
"# TLS private key for certificate '{}'\nsystemd-creds encrypt --name={}-tls-key - {}\n",
cert.name,
"# TLS private key for certificate '{}'\nsystemd-creds encrypt - {}\n",
cert.name,
path.display()
);
+1 -2
View File
@@ -343,8 +343,7 @@ async fn save_key(key: &CertKeyPair, cert_config: &CertificateConfig) -> Result<
let pem = key.to_pem();
if let Some(cred_path) = &cert_config.key_credential {
let cred_name = format!("{}-tls-key", cert_config.name);
credentials::encrypt_credential(&cred_name, pem.as_bytes(), cred_path).await?;
credentials::encrypt_credential(pem.as_bytes(), cred_path).await?;
tracing::info!(path = %cred_path.display(), "saved private key (encrypted)");
} else if let Some(key_path) = &cert_config.key_path {
if let Some(parent) = key_path.parent() {