Files
mesh-controller/internal/envfile/envfile.go
T
jschoubben 4531f2244f A secret reaches a process as a file (ADR 0086)
The broker settings take a _FILE twin like the store connections; the
catalogue engine refuses a secret placeholder in a container's env and a
secret-carrying env-file unless the container says why with
secrets-in-environment, which stays in the catalogue and never reaches the
machine.
2026-09-21 10:10:33 +02:00

40 lines
1.9 KiB
Go

// Package envfile reads a setting that may be a secret from the environment or, preferably, from
// a file the environment names.
//
// **A secret reaches a process as a file** (novox/hq ADR 0086). An environment variable is
// readable in `docker inspect`, in the process's /proc entry and in whatever composed it; a file
// the mesh sealed to the machine and the host wrote at 0600 is readable where it is used and
// nowhere else. So every variable of the control plane's that carries a credential has a `_FILE`
// twin naming such a file, and the plain form remains only for a control plane a person starts by
// hand and for the bundle that raises the first one. The store's connections had this shape
// already (internal/store); this is the same rule for the rest.
package envfile
import (
"fmt"
"os"
"strings"
)
// Value is the setting named by `name`: the content of the file `name_FILE` points at when that
// is set, else the variable itself. Both set is refused — two sources that could disagree is how
// a setting silently stops meaning what it says. Neither set is "", nil.
func Value(name string) (string, error) {
plain, hasPlain := os.LookupEnv(name)
path, hasFile := os.LookupEnv(name + "_FILE")
switch {
case hasFile && hasPlain && strings.TrimSpace(plain) != "" && strings.TrimSpace(path) != "":
return "", fmt.Errorf("both %s and %s_FILE are set; one of them, not both", name, name)
case hasFile && strings.TrimSpace(path) != "":
raw, err := os.ReadFile(strings.TrimSpace(path))
if err != nil {
return "", fmt.Errorf("%s_FILE names %s, which cannot be read: %w", name, path, err)
}
// A file has a line ending and a value does not — trimmed, and only the ending, because a
// value may begin or end with a space and still be the value.
return strings.TrimRight(string(raw), "\r\n"), nil
default:
return strings.TrimSpace(plain), nil
}
}