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
- Variables
- func Abort(env Env, detail string) (statedb.HubCARotationRow, error)
- func BundleSerials(bundle []byte) []string
- func Constrained(c *x509.Certificate) bool
- func ConstraintNames(c *x509.Certificate) []string
- func Covers(c *x509.Certificate, want []string) bool
- func FirstPEM(bundle []byte) []byte
- func Label(serials []string) string
- func Missing(c *x509.Certificate, want []string) []string
- func NormalizeSANs(in []string) ([]string, error)
- func ParseCertPEM(b []byte) (*x509.Certificate, error)
- func ParseLabel(v string) []string
- func Permitted(c *x509.Certificate, names []string) (ok, refused []string)
- func SANsFor(advertiseBase, listenAddr string) ([]string, error)
- func Serial(c *x509.Certificate) string
- func StoredLeafNames(s *Store) ([]string, error)
- type ActivateRequest
- type ActivateResult
- type Authority
- type CAInfo
- type EmergencyResult
- type Env
- type Issued
- type Leaf
- type LeafInfo
- type LeafStatus
- type Member
- type MemberStatus
- type MembersError
- type Monitor
- type Options
- type Phase
- type RetireResult
- type RotationEvent
- type Run
- type RunsError
- type Sealer
- type Server
- func (s *Server) CAPEM() []byte
- func (s *Server) Current() *Leaf
- func (s *Server) GetCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error)
- func (s *Server) Monitor() Monitor
- func (s *Server) Refresh() (bool, error)
- func (s *Server) Refused() []string
- func (s *Server) Renew() (bool, error)
- func (s *Server) TLSConfig(minVersion string) (*tls.Config, error)
- func (s *Server) Trust() *Trust
- func (s *Server) Want() []string
- type ServerConfig
- type Slot
- type Snapshot
- type StageRequest
- type StageResult
- type State
- type Status
- type Step
- type Store
- func (s *Store) CountSealedByKey() (map[string]int, error)
- func (s *Store) ListSealedNotUnder(keyID string, limit int) ([]secretbroker.SealedRow, error)
- func (s *Store) ReadCA() (*x509.Certificate, []byte, error)
- func (s *Store) ReadLeaf(m Monitor) (LeafInfo, error)
- func (s *Store) ReplaceSealed(id string, expect, next secretbroker.Envelope) (bool, error)
- func (s *Store) Rotations(limit int) ([]statedb.HubCARotationRow, error)
- func (s *Store) SealedSetName() string
- type Trust
- func (t *Trust) AdoptedAt() time.Time
- func (t *Trust) Authority() *Authority
- func (t *Trust) Bundle() []byte
- func (t *Trust) Refresh() (bool, error)
- func (t *Trust) Report(instanceID string, servers ...*Server) error
- func (t *Trust) Serials() []string
- func (t *Trust) Snapshot() Snapshot
- func (t *Trust) State() State
- func (t *Trust) Withdraw(instanceID string) error
Constants ¶
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 )
const ( UseGitProxy = "git_proxy" UseKubeGuard = "kube_guard" UseNode = "node" )
Paths a dispatch is given the hub's CA on (executor.LabelHubCAUses).
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.
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.
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.
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.
const MaxConstraintNames = 32
MaxConstraintNames bounds the names one CA's constraints permit.
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 ¶
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.
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.
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
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
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
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 ¶
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
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 ¶
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
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 ¶
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) Certificate ¶
func (a *Authority) Certificate() *x509.Certificate
Certificate returns the CA certificate.
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
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.
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
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.
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.
func Monitors ¶
func Monitors() []Monitor
Monitors lists every monitor the hub issues for, in a stable order.
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.
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
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
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
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.
type RunsError ¶ added in v0.0.7
type RunsError struct{ Runs []Run }
RunsError carries the runs an activation would break.
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 ¶
CAPEM returns what sandboxes are told to trust: every CA the control plane currently trusts, the active one first. Public.
func (*Server) GetCertificate ¶
func (s *Server) GetCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error)
GetCertificate is tls.Config.GetCertificate.
func (*Server) Refresh ¶
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
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 ¶
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 ¶
TLSConfig is the listener's configuration: the hub's TLS parameters around this server's certificate.
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 Snapshot ¶ added in v0.0.7
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
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).
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
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
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
Generation identifies this set of CAs and which of them signs: it changes with every step of a rotation and with nothing else.
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
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.
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 ¶
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 ¶
CountSealedByKey groups the rows by the key sealing them.
func (*Store) ListSealedNotUnder ¶
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 ¶
ReadLeaf returns a monitor's current leaf, without its key. ErrNotMinted when none has been issued.
func (*Store) ReplaceSealed ¶
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 ¶
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
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
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
AdoptedAt is when this process started handing out the current bundle.
func (*Trust) Refresh ¶ added in v0.0.7
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
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
Serials are the serials of the CAs in Bundle, the active one first.