keymgmt

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 11, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package keymgmt holds the safe header-write protocol shared by every operation that mutates the key-slot header. A clobbered or half-written header locks the user out of every blob under it, so writes go through SafePut: back up the current header, confirm it hasn't changed underneath us, write, then read back and verify the result still unlocks before trusting it. RestoreBackup is the recovery counterpart.

This is the one place that needs both the storage layer (backend) and the crypto layer (crypto): the backend handles backup and the raw read/write, crypto parses and unlocks the result. Keeping the orchestration here lets each of those layers stay unaware of the other.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RestoreBackup

func RestoreBackup(ctx context.Context, store backend.HeaderStore) error

RestoreBackup copies the header backup back over the header and confirms the result parses, so recovery from a bad write is one command instead of a raw rclone incantation. It reports a clear error when there is no backup to restore, which includes versioned remotes (recover a prior object version through the remote's version history there).

func RotateMaster

func RotateMaster(ctx context.Context, store Vault, hdr *crypto.Header, base []byte, oldMK *crypto.MasterKey, verify func(*crypto.Header) (*crypto.MasterKey, error), onFlip func(*crypto.MasterKey)) (*crypto.MasterKey, error)

RotateMaster re-keys a vault: it mints a fresh master, re-encrypts every blob under it, and rewrites the header to wrap the new master under hdr's slots. hdr carries the desired slot set (unchanged for a precautionary rotate, minus a slot for offboarding). base is the current header bytes (freshness); oldMK the current master; verify re-unlocks the new header with the operator's credential. Returns the new master.

It never leaves a reader unable to decrypt, via a three-phase transition that keeps the invariant "the master the header yields is a recipient of every blob" at all times:

  1. widen — re-encrypt every blob to {old, new}, header still yields old.
  2. flip — write the new header (yields new); every blob already has new.
  3. narrow — re-encrypt every blob to {new} only; old can no longer decrypt.

A crash loses the in-memory new master, but the operation is re-runnable from any state: a re-run re-keys from whatever the header currently yields.

onFlip, if non-nil, is called with the new master immediately after the header flip succeeds (before the narrow pass). The caller uses it to advance its local rollback pin to the new master at the moment it becomes authoritative, so an interrupted narrow doesn't leave the pin behind the header (which would make a re-run look like a rollback).

func SafePut

func SafePut(ctx context.Context, store backend.HeaderStore, h *crypto.Header, base []byte, mk *crypto.MasterKey, verify func(*crypto.Header) (*crypto.MasterKey, error)) error

SafePut writes header h with the full safety protocol around it. It bumps h's revision, seals it (authentication tag) with mk, and writes the marshaled result.

  • base is the exact header bytes read at the start of the operation (nil if the storage had no header yet). Immediately before writing, SafePut re-reads the header and aborts if it no longer matches base, so a concurrent key operation can't be silently overwritten. This is a freshness check, not a lock: a write landing in the gap between this read and the write below still races. For an operation a human runs occasionally that is an acceptable, documented residual.
  • mk is the master the header should wrap; SafePut seals with it and, after writing, confirms the read-back header's authentication tag verifies under it (catches a corrupted/substituted write).
  • verify re-unlocks the read-back header with the caller's own credential (a passphrase or an age identity) and must yield mk, an end-to-end check that the header is still usable by the caller before they walk away.

On any verification failure SafePut returns an error and leaves the backup in place; recover with RestoreBackup.

Types

type Vault

type Vault interface {
	backend.Backend
	backend.HeaderStore
}

Vault is a backend that holds both namespace blobs and the key header, which rotation needs together.

Jump to

Keyboard shortcuts

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