dbrotate

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package dbrotate rotates a managed database's owner password in the engine itself, then switches the stored credential every app reads.

Index

Constants

View Source
const (
	ReasonVerifyFailed = "verify_failed"
	ReasonApplyFailed  = "apply_failed"
	ReasonRefUpdate    = "reference_update_failed"
	ReasonUnresolved   = "unresolved"
	ReasonInterrupted  = "interrupted"

	ActionStart    = "database.password.rotate.start"
	ActionComplete = "database.password.rotate"
	ActionRollback = "database.password.rotate.rollback"
	ActionPolicy   = "database.password.policy"
	SystemActor    = "database-password-rotation"
)

Reasons stored on a rotation row. Fixed strings, never engine output.

Variables

View Source
var (
	ErrUnsupported  = errors.New("this engine has no owner password to rotate")
	ErrNoSecrets    = errors.New("secrets are not configured on this control plane")
	ErrNotRunning   = errors.New("database has no running container")
	ErrPending      = errors.New("a previous rotation is not settled yet")
	ErrVerifyFailed = errors.New("new password was refused by the engine, the old one was restored")
	ErrBadInterval  = errors.New("interval must be 0 to 3650 days")
)

Typed failures the API maps to status codes.

View Source
var ErrEngine = errors.New("database engine refused the statement")

ErrEngine wraps every engine-side failure. It never carries engine output.

Functions

This section is empty.

Types

type Apps

type Apps interface {
	// Dependents splits linked apps into running ones, which restart, and
	// suspended ones, which pick the new credential up when started.
	Dependents(ctx context.Context, database string) (running, suspended []string, err error)
	Restart(ctx context.Context, database string) []string
}

Apps lists and restarts the apps that read a database credential.

type Auditor

type Auditor interface {
	Record(ctx context.Context, action, database, actor string)
}

Auditor writes one audit row. It is never handed a password.

type Databases

type Databases interface {
	GetDesiredDatabase(ctx context.Context, name string) (*store.DesiredDatabase, error)
}

Databases reads desired database records.

type Driver

type Driver interface {
	// Set makes newPassword the owner password. adminPassword is the one in
	// force now, for engines that authenticate the admin session.
	Set(ctx context.Context, ex Exec, containerID, database, adminPassword, newPassword string) error
	// Verify logs in as the owner with password and fails if it is refused.
	Verify(ctx context.Context, ex Exec, containerID, database, password string) error
}

Driver changes and checks one engine's owner password. Passwords travel on stdin only, never in a command line or an error.

func DriverFor

func DriverFor(engine string) (Driver, bool)

DriverFor returns the driver for engine, or false when the engine has no owner password this platform can rotate (Redis family, search engines, ClickHouse, Memcached).

type Exec

type Exec interface {
	ExecWithInput(ctx context.Context, containerID string, cmd []string, stdin io.Reader) (io.ReadCloser, error)
}

Exec is the slice of the container runtime a driver needs.

type Preview

type Preview struct {
	Database        string
	Engine          string
	Supported       bool
	Reason          string
	RestartRequired bool
	Apps            []string
	SuspendedApps   []string
	State           string
	LastError       string
	LastChangedAt   time.Time
	IntervalDays    int
	NextDue         time.Time
}

Preview is what an operator sees before confirming a rotation.

type Result

type Result struct {
	Database      string
	RestartedApps []string
	RotatedAt     time.Time
}

Result is the outcome of one completed rotation.

type Secrets

type Secrets interface {
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
	Exists(ctx context.Context, serviceName, envKey string) (bool, error)
	SetValueGuarded(ctx context.Context, serviceName, envKey, plaintext string, overwriteLocked bool) error
	ListKeys(ctx context.Context, serviceName string) ([]store.SecretKeyInfo, error)
	DeleteValue(ctx context.Context, serviceName, envKey string) error
}

Secrets is the encrypted credential store.

type Service

type Service struct {
	Store     Store
	Databases Databases
	Secrets   Secrets
	Target    Target
	Apps      Apps
	Auditor   Auditor
	Logger    *slog.Logger
	Now       func() time.Time
	// contains filtered or unexported fields
}

Service rotates database owner passwords.

func (*Service) Heal

func (s *Service) Heal(ctx context.Context, name string) error

Heal settles name's unsettled rotation. A row that is not pending is left alone.

func (*Service) Preview

func (s *Service) Preview(ctx context.Context, name string) (Preview, error)

Preview reports what rotating name would do, without changing anything.

func (*Service) Rotate

func (s *Service) Rotate(ctx context.Context, name, actor string) (Result, error)

Rotate performs one staged rotation: stage the new password, apply it in the engine, verify a real login, switch the stored credential, then restart the linked apps. A failed verification restores the old password.

func (*Service) Run

func (s *Service) Run(ctx context.Context, interval time.Duration) error

Run sweeps once at boot, then every interval until ctx ends.

func (*Service) SetInterval

func (s *Service) SetInterval(ctx context.Context, name string, days int, actor string) error

SetInterval sets how often name rotates on its own, in days (0 is off).

func (*Service) Sweep

func (s *Service) Sweep(ctx context.Context) int

Sweep settles pending rotations and rotates databases whose interval has elapsed, at most sweepBatch rotations per pass. It returns how many it rotated.

type Store

type Store interface {
	GetDatabasePasswordRotation(ctx context.Context, name string) (store.DatabasePasswordRotation, error)
	ListDatabasePasswordRotations(ctx context.Context) ([]store.DatabasePasswordRotation, error)
	SetDatabasePasswordRotationInterval(ctx context.Context, name string, days int, now time.Time) error
	SaveDatabasePasswordRotationState(ctx context.Context, name, state, reason string, lastRotated, pendingSince, now time.Time) error
	DeleteDatabasePasswordRotation(ctx context.Context, name string) error
}

Store is the rotation persistence. *store.DB satisfies it.

type Target

type Target interface {
	Locate(ctx context.Context, d *store.DesiredDatabase) (Exec, string, error)
}

Target finds the running container of a database. It returns ErrNotRunning when there is none.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL