Repository: caddyserver/caddy (language: go)

Issue:
allow use of env placeholder in tls certificates
I'm using this directive to load certificates through systemd's `LoadCredential=` (reference [here](https://systemd.io/CREDENTIALS/)).

```
        tls "{env.CREDENTIALS_DIRECTORY}/cert.pem" "{env.CREDENTIALS_DIRECTORY}/cert.key"
```

Unfortunately, the placeholder does not seem to get resolved.

```
Dec 04 10:49:00 caddy[1517810]: Error: loading http app module: provision http: getting tls app: loading tls app module: provision tls: loading certificates: open {env.CREDENTIALS_DIRECTORY}/cert.pem: no such file or directory
```


Discussion / hints:

Fix patch:
diff --git a/modules/caddytls/fileloader.go b/modules/caddytls/fileloader.go
index 430932b999a..8603bbe652b 100644
--- a/modules/caddytls/fileloader.go
+++ b/modules/caddytls/fileloader.go
@@ -29,6 +29,26 @@ func init() {
 // FileLoader loads certificates and their associated keys from disk.
 type FileLoader []CertKeyFilePair
 
+// Provision implements caddy.Provisioner.
+func (fl FileLoader) Provision(ctx caddy.Context) error {
+	repl, ok := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
+	if !ok {
+		repl = caddy.NewReplacer()
+	}
+	for k, pair := range fl {
+		for i, tag := range pair.Tags {
+			pair.Tags[i] = repl.ReplaceKnown(tag, "")
+		}
+		fl[k] = CertKeyFilePair{
+			Certificate: repl.ReplaceKnown(pair.Certificate, ""),
+			Key:         repl.ReplaceKnown(pair.Key, ""),
+			Format:      repl.ReplaceKnown(pair.Format, ""),
+			Tags:        pair.Tags,
+		}
+	}
+	return nil
+}
+
 // CaddyModule returns the Caddy module information.
 func (FileLoader) CaddyModule() caddy.ModuleInfo {
 	return caddy.ModuleInfo{
@@ -87,4 +107,7 @@ func (fl FileLoader) LoadCertificates() ([]Certificate, error) {
 }
 
 // Interface guard
-var _ CertificateLoader = (FileLoader)(nil)
+var (
+	_ CertificateLoader = (FileLoader)(nil)
+	_ caddy.Provisioner = (FileLoader)(nil)
+)
diff --git a/modules/caddytls/folderloader.go b/modules/caddytls/folderloader.go
index 33b31a54af0..89e978df631 100644
--- a/modules/caddytls/folderloader.go
+++ b/modules/caddytls/folderloader.go
@@ -43,6 +43,18 @@ func (FolderLoader) CaddyModule() caddy.ModuleInfo {
 	}
 }
 
+// Provision implements caddy.Provisioner.
+func (fl FolderLoader) Provision(ctx caddy.Context) error {
+	repl, ok := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
+	if !ok {
+		repl = caddy.NewReplacer()
+	}
+	for k, path := range fl {
+		fl[k] = repl.ReplaceKnown(path, "")
+	}
+	return nil
+}
+
 // LoadCertificates loads all the certificates+keys in the directories
 // listed in fl from all files ending with .pem. This method of loading
 // certificates expects the certificate and key to be bundled into the
@@ -146,4 +158,7 @@ func tlsCertFromCertAndKeyPEMBundle(bundle []byte) (tls.Certificate, error) {
 	return cert, nil
 }
 
-var _ CertificateLoader = (FolderLoader)(nil)
+var (
+	_ CertificateLoader = (FolderLoader)(nil)
+	_ caddy.Provisioner = (FolderLoader)(nil)
+)
diff --git a/modules/caddytls/pemloader.go b/modules/caddytls/pemloader.go
index 61b08851c8a..9c5ec17c936 100644
--- a/modules/caddytls/pemloader.go
+++ b/modules/caddytls/pemloader.go
@@ -30,6 +30,25 @@ func init() {
 // of not needing to store them on disk at all.
 type PEMLoader []CertKeyPEMPair
 
+// Provision implements caddy.Provisioner.
+func (pl PEMLoader) Provision(ctx caddy.Context) error {
+	repl, ok := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
+	if !ok {
+		repl = caddy.NewReplacer()
+	}
+	for k, pair := range pl {
+		for i, tag := range pair.Tags {
+			pair.Tags[i] = repl.ReplaceKnown(tag, "")
+		}
+		pl[k] = CertKeyPEMPair{
+			CertificatePEM: repl.ReplaceKnown(pair.CertificatePEM, ""),
+			KeyPEM:         repl.ReplaceKnown(pair.KeyPEM, ""),
+			Tags:           pair.Tags,
+		}
+	}
+	return nil
+}
+
 // CaddyModule returns the Caddy module information.
 func (PEMLoader) CaddyModule() caddy.ModuleInfo {
 	return caddy.ModuleInfo{
@@ -69,4 +88,7 @@ func (pl PEMLoader) LoadCertificates() ([]Certificate, error) {
 }
 
 // Interface guard
-var _ CertificateLoader = (PEMLoader)(nil)
+var (
+	_ CertificateLoader = (PEMLoader)(nil)
+	_ caddy.Provisioner = (PEMLoader)(nil)
+)
diff --git a/modules/caddytls/storageloader.go b/modules/caddytls/storageloader.go
index ddaaa51560c..f9f0e7e680f 100644
--- a/modules/caddytls/storageloader.go
+++ b/modules/caddytls/storageloader.go
@@ -52,6 +52,22 @@ func (StorageLoader) CaddyModule() caddy.ModuleInfo {
 func (sl *StorageLoader) Provision(ctx caddy.Context) error {
 	sl.storage = ctx.Storage()
 	sl.ctx = ctx
+
+	repl, ok := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
+	if !ok {
+		repl = caddy.NewReplacer()
+	}
+	for k, pair := range sl.Pairs {
+		for i, tag := range pair.Tags {
+			pair.Tags[i] = repl.ReplaceKnown(tag, "")
+		}
+		sl.Pairs[k] = CertKeyFilePair{
+			Certificate: repl.ReplaceKnown(pair.Certificate, ""),
+			Key:         repl.ReplaceKnown(pair.Key, ""),
+			Format:      repl.ReplaceKnown(pair.Format, ""),
+			Tags:        pair.Tags,
+		}
+	}
 	return nil
 }
 


Test patch: