hubca

package
v0.0.7 Latest Latest
Warning

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

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 30 Imported by: 0

Documentation

Overview

Package hubca is the hub's own certificate authority, and the short-lived certificates it issues its two credential monitors (Task 20409).

Why the hub has one

The git interception proxy and the Kubernetes access monitor exist so that a forge token and a cluster credential stay on the hub: the sandbox holds a session token instead, and a process it does not control decides every push and every API request. That token rides every request, so both listeners speak TLS — and until this package, their certificate was a pair of files the operator supplied. A self-signed pair needed its CA in every sandbox image, a public one needed a name the sandbox could reach and a CA would sign, and so most hubs ran neither and delivered the PAT itself into the sandbox. The security property was one the operator had to finish building.

With `tls: auto` on a monitor's section the hub builds it. A CA is minted once per control plane, its private key sealed under the hub's KEK registry (envelope encryption, the same as every brokered secret) and kept in the control-plane database, never as a loose file. So every hub-cluster member serves the same identity, a database backup carries it, and `cloop hub key rotate` rewraps it. Each monitor's serving certificate is a leaf issued from that CA for the names sandboxes reach it at — the advertise URL's host and the listen address's — valid for LeafLifetime and replaced by the cluster leader when less than RenewWithin remains.

What a sandbox trusts

The CA, never the leaf, and only for the monitor's URL. The CA certificate travels to each sandbox (pkg/executor.GitCA) and git is told to trust it through http.<advertise_url>.sslCAInfo — not GIT_SSL_CAINFO, which replaces the trust store — so another https host whose certificate this CA signed is still verified against the image's own store and refused. A kubeconfig carries the CA as its cluster's certificate-authority-data. Because the sandbox trusts the CA, a leaf can be replaced under a running workload: a push in flight keeps its connection, and the next one verifies the new leaf against the same CA.

The CA's private key is opened only in the hub process, to sign leaves. It is in no Spec, no lease, no start frame and no log.

Replacing the CA

A CA's key that may have leaked — a backup taken with the root key, a misused KMS identity, a departed operator — is replaced online, in three steps an operator takes with `cloop hub ca rotate` (rotate.go, Task 20438): stage a second CA, which every sandbox dispatched from then on trusts beside the first; activate it once no run dispatched before the stage is still running, when the cluster leader reissues every leaf from it; and retire the first, whose sealed key is destroyed. A process's view of which CAs exist, which one signs and which ones a sandbox is told to trust is a Trust (trust.go), re-read every minute and whenever another process takes a step.

A CA minted by a rotation carries X.509 name constraints for the names the monitors are reached at, so even a verifier that trusts it more widely than git's per-URL setting does — Node.js, which trusts it for every host — would refuse a certificate it signed for any other host.

Index

Constants

View Source
const (
	// CALifetime is how long the CA is valid. Long, because a CA that
	// expires is one every sandbox stops trusting at once, and replacing it
	// is a change to every workload's trust rather than to one listener's
	// certificate. Leaves are what is short-lived.
	CALifetime = 10 * 365 * 24 * time.Hour
	// LeafLifetime is how long a monitor's certificate is valid.
	LeafLifetime = 72 * time.Hour
	// RenewWithin: a leaf with less than this left is replaced. The 48-hour
	// overlap is what a renewal that failed has to be noticed and fixed in
	// before anything stops verifying.
	RenewWithin = 48 * time.Hour
	// NearExpiry is when `cloop hub doctor` fails a leaf: renewal should have
	// replaced it a day before this.
	NearExpiry = 24 * time.Hour
	// EmergencyWithin: a hub process that is not the cluster leader replaces
	// a leaf itself only this close to its expiry — a leader that has been
	// gone for two days, or a cluster whose leader cannot sign.
	EmergencyWithin = time.Hour

	// MaxSANs bounds the names one leaf carries.
	MaxSANs = 16
)
View Source
const (
	UseGitProxy  = "git_proxy"
	UseKubeGuard = "kube_guard"
	UseNode      = "node"
)

Paths a dispatch is given the hub's CA on (executor.LabelHubCAUses).

View Source
const (
	ReasonFirst      = "first"      // no leaf was stored
	ReasonRenewal    = "renewal"    // the stored one was near the end of its life
	ReasonNames      = "names"      // it lacked a name sandboxes reach the monitor at
	ReasonActivation = "activation" // it came from a CA that no longer signs
	ReasonUnreadable = "unreadable" // it could not be read or did not verify
)

Reasons a leaf is issued, on Issued.Reason and in the hub_ca.leaf_issued row.

View Source
const ActivationGrace = 3 * time.Minute

ActivationGrace is how long after an activation a member that is not the leader waits for the leader to reissue a leaf from the new CA before it does so itself.

View Source
const BusTopic = "hub_ca"

BusTopic is the hub cluster bus topic a rotation step is announced on, so every member re-reads its CAs at once rather than at its next minute's tick.

View Source
const EndpointRotation = "hub_ca_rotation"

EndpointRotation is the hub_members endpoint a member advertises when its build takes part in a CA rotation: it refreshes its trust, records what each dispatch trusts and reports what it serves. A member without it would keep signing with the CA it opened at start, so an activation is refused while one is live.

View Source
const MaxConstraintNames = 32

MaxConstraintNames bounds the names one CA's constraints permit.

View Source
const MemberReportStale = 3 * time.Minute

MemberReportStale is how old a member's report may be before the member is taken to have stopped refreshing: it reports every minute.

Variables

View Source
var (
	// ErrNoCA: tls: auto has never run here, so there is nothing to rotate.
	ErrNoCA = errors.New("hubca: there is no hub CA to rotate — no credential monitor has run under tls: auto here")
	// ErrWrongPhase: the rotation is not at the step asked for.
	ErrWrongPhase = errors.New("hubca: the rotation is not at that step")
	// ErrRunsWouldBreak: an activation found runs it would break.
	ErrRunsWouldBreak = errors.New("hubca: runs dispatched before the stage are still running")
	// ErrMembersBehind: a live member has not adopted the step before.
	ErrMembersBehind = errors.New("hubca: not every hub member has caught up")
	// ErrLeavesBehind: a leaf still comes from the previous CA.
	ErrLeavesBehind = errors.New("hubca: a monitor's certificate still comes from the previous CA")
)

Errors a step refuses with. Each is wrapped with the particulars.

View Source
var ErrNoKey = errors.New("hubca: the hub's certificate authority needs CLOOP_SECRET_KEY (or its key file, " +
	"CLOOP_SECRET_KEY_FILE), which its private key is sealed under")

ErrNoKey is returned when the hub has no sealing key to keep the CA under.

View Source
var ErrNotMinted = errors.New("hubca: not issued yet")

ErrNotMinted is returned for a CA or a leaf that does not exist yet: a hub that has never started a monitor in auto mode.

Functions

func Abort added in v0.0.7

func Abort(env Env, detail string) (statedb.HubCARotationRow, error)

Abort destroys the staged CA, which was never activated: every dispatch that trusted it trusts the active CA too, so nothing breaks.

func BundleSerials added in v0.0.7

func BundleSerials(bundle []byte) []string

BundleSerials lists the serials of the certificates in a PEM bundle, in order; a block that does not parse is skipped.

func Constrained added in v0.0.7

func Constrained(c *x509.Certificate) bool

Constrained reports whether a CA certificate carries name constraints.

func ConstraintNames added in v0.0.7

func ConstraintNames(c *x509.Certificate) []string

ConstraintNames lists the names a CA's constraints permit, as an operator gave them; nil for a CA without constraints.

func Covers

func Covers(c *x509.Certificate, want []string) bool

Covers reports whether a certificate carries every one of want's names.

func FirstPEM added in v0.0.7

func FirstPEM(bundle []byte) []byte

FirstPEM is the first certificate of a PEM bundle, PEM-encoded: the active CA, which State.Bundle puts first.

func Label added in v0.0.7

func Label(serials []string) string

Label renders serials the way a dispatch records them (executor.LabelHubCATrust): sorted, comma-separated.

func Missing

func Missing(c *x509.Certificate, want []string) []string

Missing returns want's names a certificate does not carry.

func NormalizeSANs

func NormalizeSANs(in []string) ([]string, error)

NormalizeSANs validates, lowercases, de-duplicates and sorts names.

func ParseCertPEM

func ParseCertPEM(b []byte) (*x509.Certificate, error)

ParseCertPEM decodes exactly one certificate from PEM.

func ParseLabel added in v0.0.7

func ParseLabel(v string) []string

ParseLabel reads a recorded trust label back.

func Permitted added in v0.0.7

func Permitted(c *x509.Certificate, names []string) (ok, refused []string)

Permitted splits names into those a CA certificate may vouch for and those its name constraints refuse. A CA without constraints permits every name.

func SANsFor

func SANsFor(advertiseBase, listenAddr string) ([]string, error)

SANsFor returns the names a monitor's certificate must carry: the host of advertiseBase — the https URL sandboxes are pointed at — and the host of listenAddr when it names one, rather than every interface.

The listen address is there for the sandbox that shares the hub's network namespace and dials it directly, and for a hub whose advertise URL is the bound address; an unspecified bind (":8443", "0.0.0.0:8443") names nothing a client could dial, so it adds nothing.

func Serial added in v0.0.7

func Serial(c *x509.Certificate) string

Serial is a certificate's serial as the hub records it: lowercase hex of its big-endian bytes, the form hub_tls, the trust labels and the audit trail use. (big.Int's Text(16) drops a leading zero nibble, so it is not.)

func StoredLeafNames added in v0.0.7

func StoredLeafNames(s *Store) ([]string, error)

StoredLeafNames is every name a stored leaf carries: what the monitors are reached at by every member, as far as the hub has issued for them.

Types

type ActivateRequest added in v0.0.7

type ActivateRequest struct {
	// Force activates although runs dispatched before the stage are still
	// running: they stop verifying the monitors, and are named.
	Force bool
	// contains filtered or unexported fields
}

ActivateRequest asks for an activation.

type ActivateResult added in v0.0.7

type ActivateResult struct {
	Rotation statedb.HubCARotationRow `json:"rotation"`
	// Broken are the runs a forced activation broke.
	Broken []Run `json:"broken,omitempty"`
}

ActivateResult is an activation taken.

func Activate added in v0.0.7

func Activate(env Env, req ActivateRequest) (ActivateResult, error)

Activate makes the staged CA the one leaves are issued from.

type Authority

type Authority struct {
	// contains filtered or unexported fields
}

Authority is the hub's CA, opened for signing.

func OpenAuthority

func OpenAuthority(s *Store, sealer Sealer, o Options) (*Authority, error)

OpenAuthority returns the hub's CA, minting it on the first call any hub process makes against this control plane.

Two processes minting at the same moment cannot both win: the insert is ON CONFLICT DO NOTHING, and the loser opens the winner's CA instead of its own. A CA that exists is never replaced here — every sandbox already given it would refuse its successor.

func (*Authority) CertPEM

func (a *Authority) CertPEM() []byte

CertPEM returns a copy of the CA certificate, PEM-encoded. Public.

func (*Authority) Certificate

func (a *Authority) Certificate() *x509.Certificate

Certificate returns the CA certificate.

func (*Authority) Serial

func (a *Authority) Serial() string

Serial is the CA's serial in lowercase hex.

type CAInfo added in v0.0.7

type CAInfo struct {
	Slot        Slot      `json:"slot"`
	Serial      string    `json:"serial"`
	Fingerprint string    `json:"fingerprint"`
	NotBefore   time.Time `json:"not_before"`
	NotAfter    time.Time `json:"not_after"`
	// Names are the names the CA's X.509 name constraints permit; empty for a
	// CA without constraints, which may vouch for any name.
	Names    []string          `json:"names,omitempty"`
	IssuedAt time.Time         `json:"issued_at,omitzero"`
	IssuedBy string            `json:"issued_by,omitempty"`
	Cert     *x509.Certificate `json:"-"`
	PEM      []byte            `json:"-"`
}

CAInfo is one CA as anybody may read it: the certificate, never the key.

type EmergencyResult added in v0.0.7

type EmergencyResult struct {
	Rotation statedb.HubCARotationRow `json:"rotation"`
	// Replaced are the CAs it took out of every bundle.
	Replaced []string `json:"replaced"`
	CA       *CAInfo  `json:"ca"`
	// Cut are the runs whose proxy sessions the hub members end.
	Cut []Run `json:"cut,omitempty"`
	// Leaves are the monitors' certificates it reissued from the new CA.
	Leaves []Issued `json:"leaves,omitempty"`
}

EmergencyResult is an emergency rotation taken.

func Emergency added in v0.0.7

func Emergency(env Env, req StageRequest) (EmergencyResult, error)

Emergency replaces every CA at once with a fresh one, for a key believed compromised now: a staged CA is abandoned too, since its key sits in the same database. Every run that trusts only the CAs it replaces is named, and recorded on the rotation, so each hub member ends the run's proxy sessions — whoever holds the old key could otherwise answer for the monitors and take the session tokens those runs present. It refuses while a member predates rotation, which would go on signing with the replaced CA.

type Env added in v0.0.7

type Env struct {
	Store  *Store
	Sealer Sealer
	// Options carries the clock, who is acting (Actor) and where the step's
	// record goes (Rotation, Audit).
	Options Options
	// Runs lists the dispatches still running; nil reads the control plane's
	// executor sessions.
	Runs func() ([]Run, error)
	// Alive judges a hub member row; nil counts every member that has not
	// left. The CLI passes hubcluster.RowAlive, a member its own view.
	Alive func(statedb.HubMemberRow) bool
}

Env is what a step works against.

type Issued

type Issued struct {
	// CA is true for the CA itself, false for a monitor's leaf.
	CA bool
	// Monitor is the leaf's monitor; empty for the CA.
	Monitor Monitor
	Serial  string
	// Fingerprint is the SHA-256 of the certificate's DER, in hex: what an
	// operator compares against the PEM a sandbox was given.
	Fingerprint string
	Names       []string
	NotAfter    time.Time
	// Replaced is the serial of the leaf this one replaced, if any.
	Replaced string
	// Issuer is the serial of the CA that signed a leaf.
	Issuer string
	// Reason says why a leaf was issued: Reason*.
	Reason string
}

Issued describes a certificate this process put in the store: the CA, or a monitor's leaf. Certificates only — nothing here is secret.

func ReissueLeaves added in v0.0.7

func ReissueLeaves(s *Store, sealer Sealer, o Options) ([]Issued, error)

ReissueLeaves replaces every stored leaf the active CA did not sign with one it did, for the names the stored leaf carries as far as the CA permits them: what the cluster leader does after an activation, done at once by an emergency. It reports the leaves it issued.

type Leaf

type Leaf struct {
	Monitor  Monitor
	Serial   string
	Cert     *x509.Certificate
	CertPEM  []byte
	IssuedBy string
	// contains filtered or unexported fields
}

Leaf is a monitor's serving certificate, opened.

func (*Leaf) SANs

func (l *Leaf) SANs() []string

SANs lists the names the leaf carries.

type LeafInfo

type LeafInfo struct {
	Monitor  Monitor
	Cert     *x509.Certificate
	SANs     []string
	Issuer   string
	IssuedBy string
	IssuedAt time.Time
}

LeafInfo is what can be read about a monitor's leaf without opening its key.

type LeafStatus added in v0.0.7

type LeafStatus struct {
	Monitor  Monitor   `json:"monitor"`
	Serial   string    `json:"serial"`
	Issuer   string    `json:"issuer"`
	Slot     Slot      `json:"slot,omitempty"`
	Names    []string  `json:"names"`
	NotAfter time.Time `json:"not_after"`
}

LeafStatus is a monitor's stored leaf and the CA it chains to.

type Member added in v0.0.7

type Member struct {
	ID       string `json:"id"`
	Hostname string `json:"hostname,omitempty"`
	PID      int    `json:"pid,omitempty"`
	Version  string `json:"version,omitempty"`
	// Rotates reports that the member's build takes part in a rotation
	// (EndpointRotation).
	Rotates bool `json:"rotates"`
	// Report is what the member last said it serves; nil when it has said
	// nothing — it runs no credential monitor under tls: auto.
	Report *statedb.HubCAMemberRow `json:"-"`
}

Member is a live hub member as a rotation sees it.

func LiveMembers added in v0.0.7

func LiveMembers(db *statedb.DB, alive func(statedb.HubMemberRow) bool) ([]Member, error)

LiveMembers reads the hub members alive now, judged by alive, and what each last reported serving. A nil alive counts every member that has not left.

func (Member) Name added in v0.0.7

func (m Member) Name() string

Name names the member to an operator.

type MemberStatus added in v0.0.7

type MemberStatus struct {
	Member
	Trusts    []string                        `json:"trusts,omitempty"`
	Active    string                          `json:"active,omitempty"`
	Leaves    map[string]statedb.HubCALeafAck `json:"leaves,omitempty"`
	AdoptedAt time.Time                       `json:"adopted_at,omitzero"`
	SeenAt    time.Time                       `json:"seen_at,omitzero"`
	// Serves reports that the member runs a credential monitor under tls:
	// auto: it reported, recently.
	Serves bool `json:"serves"`
	// CaughtUp is false while the member trusts, signs with or serves
	// something the rotation's current step has moved past; Behind says what.
	CaughtUp bool   `json:"caught_up"`
	Behind   string `json:"behind,omitempty"`
}

MemberStatus is a member and whether it has caught up with the rotation.

type MembersError added in v0.0.7

type MembersError struct {
	Members []MemberStatus
	// Old reports that some predate rotation: no flag overrides that.
	Old bool
}

MembersError carries the members a step waits for.

func (*MembersError) Error added in v0.0.7

func (e *MembersError) Error() string

func (*MembersError) Unwrap added in v0.0.7

func (e *MembersError) Unwrap() error

type Monitor

type Monitor string

Monitor names a listener whose certificate the hub issues.

const (
	// GitProxy is the git interception proxy (executors.git_proxy).
	GitProxy Monitor = "git_proxy"
	// KubeGuard is the Kubernetes access monitor (executors.kube_guard).
	KubeGuard Monitor = "kube_guard"
)

func Monitors

func Monitors() []Monitor

Monitors lists every monitor the hub issues for, in a stable order.

func (Monitor) ConfigKey

func (m Monitor) ConfigKey() string

ConfigKey is the configuration section the monitor is configured by.

func (Monitor) Label

func (m Monitor) Label() string

Label is how a message names the monitor.

func (Monitor) Valid

func (m Monitor) Valid() bool

Valid reports whether m is a monitor this package issues for.

type Options

type Options struct {
	// Now is the clock; nil uses time.Now.
	Now func() time.Time
	// Actor names the hub process issuing, for the row's issued_by.
	Actor string
	// Audit receives one record per certificate this process minted or
	// issued — never one it adopted from another process. Nil drops them.
	Audit func(Issued)
	// Rotation receives one record per rotation step this process took
	// (rotate.go). Nil drops them.
	Rotation func(RotationEvent)
}

Options adjusts an operation.

type Phase added in v0.0.7

type Phase string

Phase is where the control plane is in a rotation.

const (
	// PhaseNone: no CA has been minted — tls: auto has never run here.
	PhaseNone Phase = "none"
	// PhaseSteady: one CA, which signs and which sandboxes trust.
	PhaseSteady Phase = "steady"
	// PhaseStaged: a second CA is staged. Sandboxes dispatched from now on
	// trust both; leaves still come from the first.
	PhaseStaged Phase = "staged"
	// PhaseActivated: leaves come from the new CA; the one it replaced is
	// still trusted, until it is retired.
	PhaseActivated Phase = "activated"
)

type RetireResult added in v0.0.7

type RetireResult struct {
	Rotation statedb.HubCARotationRow `json:"rotation"`
	Retired  string                   `json:"retired"`
}

RetireResult is a retirement taken.

func RetirePrevious added in v0.0.7

func RetirePrevious(env Env) (RetireResult, error)

RetirePrevious destroys the previous CA once nothing serves its leaves.

type RotationEvent added in v0.0.7

type RotationEvent struct {
	Step       Step
	RotationID string
	FromSerial string
	ToSerial   string
	// Fingerprint and NotAfter describe the CA a stage minted.
	Fingerprint string
	NotAfter    time.Time
	Names       []string
	// Forced are the runs an activation was told to break.
	Forced []string
	// CutRuns are the runs whose proxy sessions an emergency ends.
	CutRuns   []string
	Emergency bool
	Detail    string
}

RotationEvent describes a step this process took. Certificates and names only: no key appears in one.

func (RotationEvent) Payload added in v0.0.7

func (e RotationEvent) Payload(via string) map[string]any

Payload is the audit row's payload for the step, with via naming what took it (the CLI, the dashboard). Its keys are the ones pkg/auditaction lists for the step's action.

type Run added in v0.0.7

type Run struct {
	ID         string    `json:"run_id,omitempty"`
	SessionID  string    `json:"session_id"`
	Project    string    `json:"project,omitempty"`
	TaskID     int       `json:"task_id,omitempty"`
	ExecutorID string    `json:"executor_id,omitempty"`
	StartedAt  time.Time `json:"started_at,omitzero"`
	// Trusts are the hub CA serials the dispatch was told to trust, and Uses
	// the paths it was told them on (UseGitProxy, UseKubeGuard, UseNode).
	// Recorded is false for a dispatch made by a build from before rotation.
	Trusts   []string `json:"trusts,omitempty"`
	Uses     []string `json:"uses,omitempty"`
	Recorded bool     `json:"recorded"`
}

Run is a dispatch still running, as a rotation sees it.

func RunningRuns added in v0.0.7

func RunningRuns(db *statedb.DB) ([]Run, error)

RunningRuns reads the dispatches the control plane has on record as running.

func RunsFrom added in v0.0.7

func RunsFrom(rows []statedb.ExecutorSessionRow) []Run

RunsFrom reads the runs out of executor session rows, keeping those still running.

func (Run) Breaks added in v0.0.7

func (r Run) Breaks(serial string) bool

Breaks reports whether the run would stop verifying a monitor that serves a leaf from the CA with serial.

func (Run) Depends added in v0.0.7

func (r Run) Depends() bool

Depends reports whether the run verifies a monitor against the hub's CA at all: it was given the CA on some path, or nobody recorded whether it was.

func (Run) Describe added in v0.0.7

func (r Run) Describe() string

Describe names the run, where it runs and since when.

func (Run) Name added in v0.0.7

func (r Run) Name() string

Name is how a run is named to an operator: its run id, or its executor session's.

func (Run) TrustsCA added in v0.0.7

func (r Run) TrustsCA(serial string) bool

TrustsCA reports whether the run was told to trust the CA with serial.

type RunsError added in v0.0.7

type RunsError struct{ Runs []Run }

RunsError carries the runs an activation would break.

func (*RunsError) Error added in v0.0.7

func (e *RunsError) Error() string

func (*RunsError) Unwrap added in v0.0.7

func (e *RunsError) Unwrap() error

type Sealer

type Sealer interface {
	SealFor(aad string, plaintext []byte) (secretbroker.Envelope, error)
	OpenEnvelope(aad string, env secretbroker.Envelope) ([]byte, error)
}

Sealer is the part of a *secretbroker.Keyring this package uses.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is one monitor's certificate, as its listener serves it.

func NewServer

func NewServer(cfg ServerConfig) (*Server, error)

NewServer settles the monitor's leaf — the stored one, or a new one when it is missing, near the end of its life, or misses a name — and returns a server for it.

func (*Server) CAPEM

func (s *Server) CAPEM() []byte

CAPEM returns what sandboxes are told to trust: every CA the control plane currently trusts, the active one first. Public.

func (*Server) Current

func (s *Server) Current() *Leaf

Current returns the leaf being served.

func (*Server) GetCertificate

func (s *Server) GetCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error)

GetCertificate is tls.Config.GetCertificate.

func (*Server) Monitor

func (s *Server) Monitor() Monitor

Monitor names what this server's certificate is for.

func (*Server) Refresh

func (s *Server) Refresh() (bool, error)

Refresh starts serving the leaf the store holds now, replacing it only when it is within EmergencyWithin of expiry, misses a name this member needs, or was issued by a CA that no longer signs and the leader has not replaced it within ActivationGrace. Every member runs it.

func (*Server) Refused added in v0.0.7

func (s *Server) Refused() []string

Refused returns the names this member wants that the active CA's name constraints do not permit: names its leaf does not carry.

func (*Server) Renew

func (s *Server) Renew() (bool, error)

Renew replaces the leaf when less than RenewWithin of its life remains, or when it was not issued by the active CA. It is the cluster leader's duty, and reports whether a leaf was issued.

func (*Server) TLSConfig

func (s *Server) TLSConfig(minVersion string) (*tls.Config, error)

TLSConfig is the listener's configuration: the hub's TLS parameters around this server's certificate.

func (*Server) Trust added in v0.0.7

func (s *Server) Trust() *Trust

Trust is the view of the CAs this server issues and judges leaves by.

func (*Server) Want

func (s *Server) Want() []string

Want returns the names this member asked for.

type ServerConfig

type ServerConfig struct {
	Monitor Monitor
	Store   *Store
	Sealer  Sealer
	// Trust is the process's view of the control plane's CAs, which a
	// rotation changes under a running server. Authority instead pins one CA
	// for the server's life: a caller without a store.
	Trust     *Trust
	Authority *Authority
	// Want are the names the monitor's sandboxes reach it at: SANsFor.
	Want    []string
	Options Options
	// Logf receives one line per certificate issued. Nil discards them.
	Logf func(format string, args ...any)
}

ServerConfig describes one monitor's certificate.

type Slot added in v0.0.7

type Slot string

Slot names one of the CA rows.

const (
	// SlotActive is the CA leaves are issued from.
	SlotActive Slot = "active"
	// SlotNext is a CA staged to replace it.
	SlotNext Slot = "next"
	// SlotPrevious is the CA an activation replaced, trusted until retired.
	SlotPrevious Slot = "previous"
)

type Snapshot added in v0.0.7

type Snapshot struct {
	Bundle  []byte
	Serials []string
}

Snapshot is the trust one dispatch is given: read once, so every path that hands a sandbox the hub's CA — git, a kubeconfig, Node — hands it the same set, and the dispatch can record which.

func (Snapshot) ActiveOnly added in v0.0.7

func (s Snapshot) ActiveOnly() Snapshot

ActiveOnly is the bundle reduced to the active CA: what a receiver that cannot hold two is given (an agent before protocol v25 placing a bundle for Node, Task 20438).

func (Snapshot) Trusts added in v0.0.7

func (s Snapshot) Trusts(serial string) bool

Trusts reports whether the snapshot holds the CA with serial.

type StageRequest added in v0.0.7

type StageRequest struct {
	// Names are the names the new CA's constraints permit, beside the ones
	// every stored leaf already carries: what the monitors are reached at, and
	// any name an advertise URL is about to move to.
	Names []string
	// NoNameConstraints mints the new CA without constraints, as the first one
	// was: it can then vouch for any name.
	NoNameConstraints bool
	// Emergency marks the stage as Emergency's first step.
	Emergency bool
}

StageRequest asks for a stage.

type StageResult added in v0.0.7

type StageResult struct {
	Rotation statedb.HubCARotationRow `json:"rotation"`
	CA       *CAInfo                  `json:"ca"`
}

StageResult is a stage taken.

func Stage added in v0.0.7

func Stage(env Env, req StageRequest) (StageResult, error)

Stage mints and stores the CA that will replace the active one. Refused while another rotation is under way.

type State added in v0.0.7

type State struct {
	Active   *CAInfo `json:"active,omitempty"`
	Next     *CAInfo `json:"next,omitempty"`
	Previous *CAInfo `json:"previous,omitempty"`
	// Rotation is the rotation under way, nil when there is none.
	Rotation *statedb.HubCARotationRow `json:"-"`
}

State is the control plane's CAs and the rotation under way, read without opening a key.

func ReadState added in v0.0.7

func ReadState(s *Store) (State, error)

ReadState reads the CAs and the rotation under way. A control plane that has never minted a CA reads as PhaseNone, not as an error.

func (State) Bundle added in v0.0.7

func (s State) Bundle() []byte

Bundle is the PEM of every trusted CA, the active one first: what git's sslCAInfo, a kubeconfig's certificate-authority-data and Node's NODE_EXTRA_CA_CERTS are given. Public.

func (State) ByIssuer added in v0.0.7

func (s State) ByIssuer(cert *x509.Certificate) *CAInfo

ByIssuer returns the trusted CA whose key signed cert, or nil.

func (State) Generation added in v0.0.7

func (s State) Generation() string

Generation identifies this set of CAs and which of them signs: it changes with every step of a rotation and with nothing else.

func (State) Phase added in v0.0.7

func (s State) Phase() Phase

Phase says where the control plane is in a rotation.

func (State) Serials added in v0.0.7

func (s State) Serials() []string

Serials are the trusted CAs' serials, the active one first.

func (State) Trusted added in v0.0.7

func (s State) Trusted() []*CAInfo

Trusted lists the CAs a sandbox dispatched now is told to trust, the active one first.

type Status added in v0.0.7

type Status struct {
	Phase    Phase                     `json:"phase"`
	Active   *CAInfo                   `json:"active,omitempty"`
	Next     *CAInfo                   `json:"next,omitempty"`
	Previous *CAInfo                   `json:"previous,omitempty"`
	Rotation *statedb.HubCARotationRow `json:"rotation,omitempty"`
	Members  []MemberStatus            `json:"members"`
	Leaves   []LeafStatus              `json:"leaves"`
	// Blocking are the runs the next step would break: while staged, those
	// that do not trust the staged CA; once activated, those that trust only
	// the previous one.
	Blocking []Run `json:"blocking,omitempty"`
	// Running counts the runs on record as running.
	Running int `json:"running"`
	// NextStep says what an operator can do now.
	NextStep string `json:"next_step"`
	// Ready reports that the next step would not be refused.
	Ready bool `json:"ready"`
}

Status is where a rotation stands, for `--status`, Settings → Hub health and the doctor.

func ReadStatus added in v0.0.7

func ReadStatus(env Env) (Status, error)

ReadStatus reads where a rotation stands.

type Step added in v0.0.7

type Step string

Step names a rotation step, on RotationEvent and in the audit trail.

const (
	StepStage          Step = "stage"
	StepActivate       Step = "activate"
	StepRetirePrevious Step = "retire_previous"
	StepAbandon        Step = "abandon"
	StepEmergency      Step = "emergency"
)

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is the hub_tls table. It is also the secretbroker.SealedSet through which `cloop hub key rotate` rewraps the keys it holds.

func NewStore

func NewStore(db *statedb.DB) (*Store, error)

NewStore adapts a control-plane database. Which database matters: the CA belongs to the hub, and a project's state.db is written by whoever can push to that project.

func (*Store) CountSealedByKey

func (s *Store) CountSealedByKey() (map[string]int, error)

CountSealedByKey groups the rows by the key sealing them.

func (*Store) ListSealedNotUnder

func (s *Store) ListSealedNotUnder(keyID string, limit int) ([]secretbroker.SealedRow, error)

ListSealedNotUnder returns rows sealed under another key.

func (*Store) ReadCA

func (s *Store) ReadCA() (*x509.Certificate, []byte, error)

ReadCA returns the CA certificate the control plane holds, without opening its key — what `cloop hub doctor` reads. ErrNotMinted when there is none.

func (*Store) ReadLeaf

func (s *Store) ReadLeaf(m Monitor) (LeafInfo, error)

ReadLeaf returns a monitor's current leaf, without its key. ErrNotMinted when none has been issued.

func (*Store) ReplaceSealed

func (s *Store) ReplaceSealed(id string, expect, next secretbroker.Envelope) (bool, error)

ReplaceSealed swaps a row's key envelope under compare-and-swap.

func (*Store) Rotations added in v0.0.7

func (s *Store) Rotations(limit int) ([]statedb.HubCARotationRow, error)

Rotations returns the most recent CA rotations first, at most limit.

func (*Store) SealedSetName

func (s *Store) SealedSetName() string

SealedSetName identifies the set in rotation reports.

type Trust added in v0.0.7

type Trust struct {
	// contains filtered or unexported fields
}

Trust is a hub process's view of the control plane's CAs: the State it last read, and the active CA opened for signing. Safe for concurrent use.

func OpenTrust added in v0.0.7

func OpenTrust(s *Store, sealer Sealer, o Options) (*Trust, error)

OpenTrust opens the control plane's CAs, minting the first one when no hub process has yet (OpenAuthority).

func StaticTrust added in v0.0.7

func StaticTrust(a *Authority) *Trust

StaticTrust is a Trust over one opened CA and nothing else, never refreshed: for a caller that holds an Authority rather than a store.

func (*Trust) AdoptedAt added in v0.0.7

func (t *Trust) AdoptedAt() time.Time

AdoptedAt is when this process started handing out the current bundle.

func (*Trust) Authority added in v0.0.7

func (t *Trust) Authority() *Authority

Authority is the CA leaves are issued from.

func (*Trust) Bundle added in v0.0.7

func (t *Trust) Bundle() []byte

Bundle is the PEM a sandbox dispatched now is told to trust.

func (*Trust) Refresh added in v0.0.7

func (t *Trust) Refresh() (bool, error)

Refresh re-reads the CAs, opening the active one's key when it changed, and reports whether anything a sandbox would be told changed. On an error the view it had is kept: a hub that cannot read its database keeps serving what it served.

func (*Trust) Report added in v0.0.7

func (t *Trust) Report(instanceID string, servers ...*Server) error

Report records what this process signs with, hands out and serves, under its cluster member id: what a rotation's step reads to tell whether every member has caught up (statedb.HubCAMemberRow). servers are the process's monitor certificates; a nil one is skipped.

func (*Trust) Serials added in v0.0.7

func (t *Trust) Serials() []string

Serials are the serials of the CAs in Bundle, the active one first.

func (*Trust) Snapshot added in v0.0.7

func (t *Trust) Snapshot() Snapshot

Snapshot reads the current bundle and serials together.

func (*Trust) State added in v0.0.7

func (t *Trust) State() State

State is the CAs as last read.

func (*Trust) Withdraw added in v0.0.7

func (t *Trust) Withdraw(instanceID string) error

Withdraw removes this process's report: it runs no monitor under tls: auto any more, so a rotation has nothing of it to wait for.

Jump to

Keyboard shortcuts

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