package bootstrap import ( "crypto/rand" "encoding/hex" "fmt" "os" "path/filepath" ) // PushCredential is the bootstrap's one-off credential for the holders' first images (design 51 *The move*; issue 1966 ENG-5): // a bearer token of 32 random bytes, hex, on one line, made for one fresh-mesh run. No vault and no bus holds it: this run // holds it and writes it once, to the file the store's holder reads on each write (`Authorization: Bearer ` on an OCI // write to the store's port, from any node); the holder removes the file when it answers its first `publish`, and this run // forgets the token when it ends. On the holder's own node the bootstrap may push to the registry container's loopback with // no credential at all. type PushCredential struct { // File is where the token was written. File string token string } // Token is the bearer token, for a push through the store's front from another node. func (c *PushCredential) Token() string { return c.token } // Forget drops the token from this run's memory. The file is the holder's to remove. func (c *PushCredential) Forget() { c.token = "" } // MintPushCredential makes a token and writes it to file, mode 0600, owned by owner (user id, group id) when given; the // directory is made if it is not there. A file that is there is replaced: a credential left by an earlier run is never reused. func MintPushCredential(file string, owner *[2]int) (*PushCredential, error) { raw := make([]byte, 32) if _, err := rand.Read(raw); err != nil { return nil, fmt.Errorf("a push credential cannot be made: %w", err) } token := hex.EncodeToString(raw) if err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil { return nil, fmt.Errorf("the push credential's directory %s cannot be made: %w", filepath.Dir(file), err) } tmp := file + ".new" if err := os.WriteFile(tmp, []byte(token+"\n"), 0o600); err != nil { return nil, fmt.Errorf("the push credential cannot be written to %s: %w", file, err) } if owner != nil { if err := os.Chown(tmp, owner[0], owner[1]); err != nil { os.Remove(tmp) return nil, fmt.Errorf("the push credential cannot be given to the store's holder: %w", err) } } if err := os.Rename(tmp, file); err != nil { os.Remove(tmp) return nil, fmt.Errorf("the push credential cannot be put at %s: %w", file, err) } return &PushCredential{File: file, token: token}, nil }