-
Notifications
You must be signed in to change notification settings - Fork 7
Open
Description
Add support for ZeroSSL, configurable per-domain via haloy.yaml. Let's Encrypt remains the default. EAB credentials for ZeroSSL use the existing ValueSource pattern, so they can be provided inline, via env vars, or via built-in secret management
Proposed Changes:
Add three new fields to config.Domain:
acme_provider(string):"letsencrypt"(default) or"zerossl"eab_kid(ValueSource): External Account Binding Key ID for ZeroSSLeab_hmac(ValueSource): External Account Binding HMAC key for ZeroSSL
domains:
- domain: example.com
acme_provider: zerossl
eab_kid:
from:
secret: "onepassword:zerossl_creds.eab_kid"
eab_hmac:
from:
secret: "onepassword:zerossl_creds.eab_hmac"
# Using environment variables
domains:
- domain: example.com
acme_provider: zerossl
eab_kid:
from:
env: ZEROSSL_EAB_KID
eab_hmac:
from:
env: ZEROSSL_EAB_HMAC
# Inline
domains:
- domain: example.com
acme_provider: zerossl
eab_kid:
value: "abc123"
eab_hmac:
value: "hmac-key-here"Implementation Plan
Config layer (internal/config/)
deploy_config.go: AddACMEProvider,EABKeyID,EABHMACKeyfields toDomainstruct. UpdateDomain.Validate()to enforce that ZeroSSL requires both EAB fields and that Let's Encrypt rejects them.labels.go: Add label format strings (dev.haloy.domain.%d.acme-provider,dev.haloy.domain.%d.eab-kid,dev.haloy.domain.%d.eab-hmac). UpdateToLabels()andParseContainerLabels()to serialize/deserialize the new fields.
Secret resolution (internal/configloader/)
resolve_secrets.go: Add domain EABValueSourcefields togatherValueSources()andgatherTargetValueSources()so they go through the same resolution pipeline as env vars and API tokens.
Certificate management (internal/haloyd/)
certificates.go:- Add ZeroSSL ACME directory constant (
https://acme.zerossl.com/v2/DV90) - Extend
CertificatesDomainwithACMEProvider,EABKeyID,EABHMACKeyfields - Refactor
ACMEClientManagerto support per-provider ACME clients (keyed by provider name) - Support EAB registration for ZeroSSL via
acme.Client.RegisterwithExternalAccountBinding - Separate account storage per provider (
accounts/letsencrypt/account.json,accounts/zerossl/account.json) - Update
ObtainCertificateto accept and use provider info - Update
hasConfigurationChangedto detect provider changes (trigger re-issuance when provider switches)
- Add ZeroSSL ACME directory constant (
deployments.go: UpdateGetCertificateDomains()to populate newCertificatesDomainfields from parsed container labels.updater.go: Extended domain info flows through naturally sinceGetCertificateDomainspopulates it.
Config validation
acme_provider: "zerossl"requires botheab_kidandeab_hmacacme_provider: ""or"letsencrypt"rejects EAB fields- Unknown provider values are rejected
Files to modify
| File | Change |
|---|---|
internal/config/deploy_config.go |
Add fields to Domain, update validation |
internal/config/labels.go |
Add label constants, update ToLabels/ParseContainerLabels |
internal/configloader/resolve_secrets.go |
Gather EAB ValueSources from domains |
internal/haloyd/certificates.go |
ZeroSSL directory, EAB registration, per-provider clients |
internal/haloyd/deployments.go |
Populate provider/EAB in GetCertificateDomains |
internal/haloyd/updater.go |
Minor comment update |
Testing
- Unit tests for Domain validation with new fields (valid/invalid combos)
- Unit tests for label round-trip (ToLabels -> ParseContainerLabels) with EAB fields
- Unit tests for gatherValueSources including domain EAB fields
- Unit tests for provider-specific ACME client creation
- Verify existing Let's Encrypt flow is unaffected (default, no EAB)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels