Installer review: secrets are staged privately, and a bundle is 0600 whether or not it existed
From review: the store and broker passwords genesis makes were carried into the controller through a world-readable file in /tmp, a bundle left at 0644 by an earlier installer kept that mode while now holding them, a mesh raised by the old installer would have been handed new passwords its servers do not have, and the broker-admin action's marker did not depend on the value. Secrets now stage in a 0700 directory owned by the controller's account; the bundle is chmod'd; an existing store or broker volume with no credential file is refused by name; the marker holds the password's fingerprint. Also: one install path for the store, broker and vault, no error-string matching for the operator key, and no unreachable fallback for the superuser.
This commit is contained in:
@@ -82,11 +82,9 @@ func (c controlPlane) carry(ctx context.Context, local, remote string) error {
|
||||
// landed unreadable, `secret accept` failed with `permission denied`, and what depended on it
|
||||
// crash-looped on material it never received. There is no shell in the image to chown it with.
|
||||
//
|
||||
// What goes through here is a module manifest and a store connection string. The connection is the
|
||||
// same value the produced bundle already holds in the clear — a foundation names its own bootstrap
|
||||
// credentials, and at genesis there is nowhere else for them to be — so this widens nothing. The
|
||||
// file on the machine is removed at once, and the copy inside the container goes when the
|
||||
// container does, which for the temporary control plane is step 10.
|
||||
// What goes through here is a module manifest — public, the same bytes as in the catalogue. A
|
||||
// value that is secret goes through carryingSecret below. The file on the machine is removed at
|
||||
// once, and the copy inside the container goes when the container does.
|
||||
func (c controlPlane) carrying(ctx context.Context, name string, content []byte, remote string) error {
|
||||
local := filepath.Join(os.TempDir(), name)
|
||||
if err := os.WriteFile(local, content, 0o644); err != nil {
|
||||
@@ -96,6 +94,38 @@ func (c controlPlane) carrying(ctx context.Context, name string, content []byte,
|
||||
return c.carry(ctx, local, remote)
|
||||
}
|
||||
|
||||
// controlPlaneUID is the account the control plane's image runs as — `USER 65534:65534` in its
|
||||
// Dockerfile — and so the only account inside the container that needs to read what is carried in.
|
||||
const controlPlaneUID = 65534
|
||||
|
||||
// carryingSecret is carrying for a value that is a secret: staged in a directory only root can
|
||||
// enter, at 0600, owned by the control plane's own account — which `docker cp` keeps, so inside
|
||||
// the container the file is readable by the process that must read it and by nobody else. Since
|
||||
// genesis makes the mesh's root credentials rather than copying the template's (rootsecrets.go),
|
||||
// a store connection string or a broker password carried this way is a real secret, and 0644 in a
|
||||
// shared temporary directory would hand it to any local user for the length of the copy.
|
||||
func (c controlPlane) carryingSecret(ctx context.Context, name string, content []byte, remote string) error {
|
||||
dir, err := os.MkdirTemp("", "mesh-carrying-")
|
||||
if err != nil {
|
||||
return fmt.Errorf("nowhere to stage %s before copying it into %s: %w", name, c.container, err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
local := filepath.Join(dir, name)
|
||||
if err := os.WriteFile(local, content, 0o600); err != nil {
|
||||
return fmt.Errorf("nowhere to stage %s before copying it into %s: %w", name, c.container, err)
|
||||
}
|
||||
if err := os.Chown(local, controlPlaneUID, controlPlaneUID); err != nil {
|
||||
// Not root — a test, or an installer run as a user, which no real genesis is. The
|
||||
// directory is 0700, so nobody else on the machine can reach the file either way; inside
|
||||
// the container the only account is the control plane's, so 0644 there is read by it and
|
||||
// by nothing else. The narrower ownership is taken whenever it can be.
|
||||
if err := os.Chmod(local, 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return c.carry(ctx, local, remote)
|
||||
}
|
||||
|
||||
func indent(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
|
||||
Reference in New Issue
Block a user