{"record":{"id":"3300334d0bbf88af","repo":"caddyserver/caddy","slug":"expanding-eab-mac-key-redacted-v","errorCode":null,"errorMessage":"expanding EAB MAC key (redacted): %v","messagePattern":"expanding EAB MAC key \\(redacted\\): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/acmeissuer.go","lineNumber":173,"sourceCode":"\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"expanding TestCA endpoint '%s': %v\", iss.TestCA, err)\n\t\t}\n\t\tiss.TestCA = testca\n\t}\n\n\t// expand EAB credentials, if non-empty\n\tif iss.ExternalAccount != nil {\n\t\tif iss.ExternalAccount.KeyID != \"\" {\n\t\t\tkeyID, err := repl.ReplaceOrErr(iss.ExternalAccount.KeyID, true, true)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"expanding EAB key ID '%s': %v\", iss.ExternalAccount.KeyID, err)\n\t\t\t}\n\t\t\tiss.ExternalAccount.KeyID = keyID\n\t\t}\n\t\tif iss.ExternalAccount.MACKey != \"\" {\n\t\t\tmacKey, err := repl.ReplaceOrErr(iss.ExternalAccount.MACKey, true, true)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"expanding EAB MAC key (redacted): %v\", err)\n\t\t\t}\n\t\t\tiss.ExternalAccount.MACKey = macKey\n\t\t}\n\t}\n\n\t// expand account key, if non-empty\n\tif iss.AccountKey != \"\" {\n\t\taccountKey, err := repl.ReplaceOrErr(iss.AccountKey, true, true)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"expanding account key PEM '%s': %v\", iss.AccountKey, err)\n\t\t}\n\t\tiss.AccountKey = accountKey\n\t}\n\n\t// expand DNS override domain, if non-empty\n\tif iss.Challenges != nil && iss.Challenges.DNS != nil && iss.Challenges.DNS.OverrideDomain != \"\" {\n\t\toverrideDomain, err := repl.ReplaceOrErr(iss.Challenges.DNS.OverrideDomain, true, true)\n\t\tif err != nil {","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/acmeissuer.go#L155-L191","documentation":"Returned by ACMEIssuer.Provision (modules/caddytls/acmeissuer.go:173) when the EAB HMAC key (acme_eab / \"mac_key\") contains a placeholder that fails to expand. The message deliberately omits the value ('(redacted)') because it is a secret; only expansion errors, not content, are reported. Provisioning aborts before the issuer is usable.","triggerScenarios":"eab { mac_key {env.EAB_MAC_KEY} } configured while EAB_MAC_KEY is unset in the Caddy process, or the placeholder syntax is invalid (unbalanced braces, unknown prefix, leading/trailing whitespace).","commonSituations":"Secret injected via Docker secrets or Vault but exposed under a different variable name; CI has the var but the production unit does not; quoting issues in systemd Environment= lines; copy-paste from docs leaving a placeholder the deployment never defines.","solutions":["Define EAB_MAC_KEY in the service environment (EnvironmentFile=/etc/caddy/acme.env with tight permissions) and reload Caddy","Confirm the name matches exactly what the config references","Ensure the placeholder is exactly {env.EAB_MAC_KEY} with no stray characters","If EAB is unnecessary for your CA, delete the eab block"],"exampleFix":"# /etc/caddy/acme.env (chmod 600)\nEAB_KEY_ID=kid-123\nEAB_MAC_KEY=base64urlkey\n\n# Caddyfile\n example.com {\n   tls {\n     issuer acme {\n       eab {\n         key_id {env.EAB_KEY_ID}\n         mac_key {env.EAB_MAC_KEY}\n       }\n     }\n   }\n }\n\n# systemd unit\n[Service]\nEnvironmentFile=/etc/caddy/acme.env","handlingStrategy":"validation","validationCode":"if strings.Contains(cfgText, \"{env.EAB_MAC_KEY}\") && os.Getenv(\"EAB_MAC_KEY\") == \"\" {\n    return errors.New(\"EAB_MAC_KEY referenced but not set; issuer provisioning will fail\")\n}","typeGuard":null,"tryCatchPattern":"if err := issuer.Provision(ctx); err != nil {\n    if strings.Contains(err.Error(), \"expanding EAB MAC key\") {\n        // value is redacted in logs; only the env var / syntax needs fixing\n    }\n    return err\n}","preventionTips":["Never log or echo the MAC key; Caddy already redacts it - keep that invariant in your tooling","Use secret managers that export to the process environment (systemd EnvironmentFile, Docker secrets wrappers)","Test the secret's presence in the exact runtime context (unit vs shell) - shells and units differ"],"tags":["tls","acme","eab","secrets","placeholders","environment"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}