56 lines
2.3 KiB
Go
56 lines
2.3 KiB
Go
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 <token>` 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
|
|
}
|