fix(setup): SMTP 密码和上传桶密钥同时存进 /etc/felis,安装器每次从这里重建 Secret,看门狗和 breakGlass 在 k3s 宕机时也能读到
This commit is contained in:
13 files changed
+532
-33
No files matched your search
@@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
// Host copies of the credentials `felis setup` takes at the keyboard: the [smtp]
|
||||
// relay password and the uploads bucket's keys. The cluster reads them from the
|
||||
// felis-smtp and felis-uploads-s3 Secrets, and a Secret lives in k3s's datastore,
|
||||
// which a reinstall (uninstall.sh keeps /etc/felis) or a host rebuilt from a
|
||||
// database bundle's state/ starts empty. Each file holds the bare value, mode
|
||||
// 0600, directly in /etc/felis beside secrets.env: every installer run applies
|
||||
// the Secrets from these files, and every database bundle, so the off-site copy
|
||||
// too, carries them.
|
||||
const (
|
||||
hostSMTPPasswordPath = "/etc/felis/smtp-password"
|
||||
hostUploadsS3AccessKeyPath = "/etc/felis/uploads-s3-access-key"
|
||||
hostUploadsS3SecretKeyPath = "/etc/felis/uploads-s3-secret-key"
|
||||
)
|
||||
|
||||
// writeHostCredential replaces the file at path with value, mode 0600, through a
|
||||
// temporary file in the same directory, so a crash leaves the old value or the
|
||||
// new one and never a partial one.
|
||||
func writeHostCredential(path, value string) error {
|
||||
tmp, err := os.CreateTemp(filepath.Dir(path), "."+filepath.Base(path)+".*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpPath := tmp.Name()
|
||||
defer os.Remove(tmpPath)
|
||||
// CreateTemp already makes the file 0600; the Chmod states it rather than
|
||||
// leaning on that.
|
||||
if err := tmp.Chmod(0o600); err != nil {
|
||||
_ = tmp.Close()
|
||||
return err
|
||||
}
|
||||
if _, err := tmp.WriteString(value); err != nil {
|
||||
_ = tmp.Close()
|
||||
return err
|
||||
}
|
||||
if err := tmp.Sync(); err != nil {
|
||||
_ = tmp.Close()
|
||||
return err
|
||||
}
|
||||
if err := tmp.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Rename(tmpPath, path)
|
||||
}
|
||||
|
||||
// readHostCredential returns the value in path; ok is false when there is no
|
||||
// such file. An empty file is a value: the relay password of a relay without AUTH.
|
||||
func readHostCredential(path string) (value string, ok bool, err error) {
|
||||
b, err := os.ReadFile(path)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return "", false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
return string(b), true, nil
|
||||
}
|
||||
|
||||
// relayPassword is the [smtp] relay password as the host holds it: the copy
|
||||
// `felis setup` keeps at path, else, on an install from before that copy, the
|
||||
// felis-smtp Secret in ns, whose absence means a relay without AUTH. cl is only
|
||||
// used when the file is missing; a nil cl then reports errClusterUnreachable.
|
||||
func relayPassword(ctx context.Context, path string, cl client.Client, ns string) (string, error) {
|
||||
if pw, ok, err := readHostCredential(path); err != nil || ok {
|
||||
return pw, err
|
||||
}
|
||||
if cl == nil {
|
||||
return "", errClusterUnreachable
|
||||
}
|
||||
return smtpSecretPassword(ctx, cl, ns)
|
||||
}
|
||||
|
||||
var errClusterUnreachable = errors.New("the cluster did not answer")
|
||||
Reference in new issue
Block a user