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.
40 lines
1.9 KiB
Go
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
|
|
}
|
|
}
|