Documentation
¶
Overview ¶
Package plugin runs out-of-process extensions behind a signed, digest-pinned package and an operator-approved ability list (ADR 034).
Index ¶
- Constants
- Variables
- func Fingerprint(pub ed25519.PublicKey) string
- func ParsePublicKey(b64 string) (ed25519.PublicKey, error)
- func Sign(priv ed25519.PrivateKey, manifestRaw []byte, digest string) string
- func SignedMessage(manifestRaw []byte, digest string) []byte
- func Verify(keys []TrustedKey, keyID string, manifestRaw []byte, digest, sigB64 string) error
- type AuditEvent
- type Auditor
- type Config
- type Containers
- type DBTX
- type Delivery
- type InstallRequest
- type InvalidError
- type Manager
- func (m *Manager) Approve(ctx context.Context, name string, abilities []string, actor string) (Record, error)
- func (m *Manager) Disable(ctx context.Context, name, actor string) (Record, error)
- func (m *Manager) Enable(ctx context.Context, name, actor string) (Record, error)
- func (m *Manager) Get(ctx context.Context, name string) (Record, error)
- func (m *Manager) Install(ctx context.Context, req InstallRequest, actor string) (Record, error)
- func (m *Manager) List(ctx context.Context) ([]Record, error)
- func (m *Manager) Reconcile(ctx context.Context)
- func (m *Manager) Remove(ctx context.Context, name, actor string) error
- func (m *Manager) Run(ctx context.Context)
- func (m *Manager) Running(name string) bool
- func (m *Manager) Send(ctx context.Context, name, secret string, n Notification) (Delivery, error)
- func (m *Manager) TrustAdd(ctx context.Context, name, publicKeyB64, actor string) (TrustedKey, error)
- func (m *Manager) TrustKeys(ctx context.Context) ([]TrustedKey, error)
- func (m *Manager) TrustRemove(ctx context.Context, keyID, actor string) error
- type Manifest
- type Notification
- type Record
- type SQLStore
- func (s *SQLStore) AddKey(ctx context.Context, k TrustedKey) error
- func (s *SQLStore) DeletePlugin(ctx context.Context, name string) error
- func (s *SQLStore) GetPlugin(ctx context.Context, name string) (Record, error)
- func (s *SQLStore) InsertPlugin(ctx context.Context, r Record) error
- func (s *SQLStore) ListKeys(ctx context.Context) ([]TrustedKey, error)
- func (s *SQLStore) ListPlugins(ctx context.Context) ([]Record, error)
- func (s *SQLStore) RemoveKey(ctx context.Context, keyID string) error
- func (s *SQLStore) SetLastError(ctx context.Context, name, msg, updatedAt string) error
- func (s *SQLStore) UpdatePlugin(ctx context.Context, r Record) error
- type Store
- type TrustedKey
Constants ¶
const ( AuditInstall = "plugin.install" AuditApprove = "plugin.approve" AuditEnable = "plugin.enable" AuditDisable = "plugin.disable" AuditRemove = "plugin.remove" AuditAbilityUsed = "plugin.ability_used" AuditTrustAdd = "plugin.trust_add" AuditTrustRemove = "plugin.trust_remove" )
Audit actions written for plugin lifecycle and ability use.
const ( AbilityRead = "read" AbilityReadSensitive = "read:sensitive" )
Abilities a plugin may be granted. Both come from the scoped-token vocabulary (ADR 012); root and every write ability are refused.
const ( StateInstalled = "installed" StateEnabled = "enabled" StateDisabled = "disabled" StateRemoving = "removing" )
Lifecycle states of an installed plugin.
const (
KindNotificationChannel = "notification_channel"
)
Extension kinds. Slice 1 ships one.
const ManifestAPIVersion = 1
ManifestAPIVersion is the manifest schema version this build accepts.
Variables ¶
var ( ErrBusy = errors.New("plugin: too many calls in flight") ErrCircuitOpen = errors.New("plugin: paused after repeated failures") ErrTooLarge = errors.New("plugin: payload is larger than the configured limit") ErrKind = errors.New("plugin: not a notification channel") )
Call failures. Callers match with errors.Is.
var ( ErrNotFound = errors.New("plugin: not found") ErrExists = errors.New("plugin: already installed") ErrNotApproved = errors.New("plugin: abilities have not been approved") ErrState = errors.New("plugin: not allowed in its current state") )
Sentinel errors. Callers match with errors.Is.
var ( ErrUntrusted = errors.New("plugin: signing key is not in the trust list") ErrBadSignature = errors.New("plugin: signature does not verify") ErrDigestMismatch = errors.New("plugin: image digest does not match the pinned digest") )
Verification failures. Callers match with errors.Is.
var ContractVersions = []uint32{1}
ContractVersions are the plugin contract versions this host speaks.
Functions ¶
func Fingerprint ¶
Fingerprint is the stable identifier of an ed25519 public key.
func ParsePublicKey ¶
ParsePublicKey decodes a standard base64 raw 32 byte ed25519 public key.
func Sign ¶
func Sign(priv ed25519.PrivateKey, manifestRaw []byte, digest string) string
Sign produces the detached base64 signature for a manifest and digest.
func SignedMessage ¶
SignedMessage is the exact byte string a publisher signs: a domain tag, the sha256 of the manifest bytes as shipped, and the pinned image digest.
Types ¶
type AuditEvent ¶
AuditEvent is one plugin audit record. Detail must never carry a secret.
type Auditor ¶
type Auditor interface {
Record(ctx context.Context, e AuditEvent) error
}
Auditor persists audit events. A failure on an ability use refuses the call.
type Config ¶
type Config struct {
Namespace string
DataDir string
UID, GID int
MemoryBytes int64
NanoCPUs int64
PidsLimit int64
CallTimeout time.Duration
StartTimeout time.Duration
HealthTimeout time.Duration
ReconcileInterval time.Duration
StopTimeout time.Duration
BackoffBase time.Duration
BackoffMax time.Duration
BreakerCooldown time.Duration
HealthFailures int
BreakerFailures int
MaxConcurrent int
MaxEventBytes int
MaxConfigBytes int
MaxSecretBytes int
MaxResponseBytes int
}
Config holds the runtime limits. Zero fields take the defaults in withDefaults.
type Containers ¶
type Containers interface {
InspectByName(ctx context.Context, name string) (*docker.ContainerState, error)
ListByPrefix(ctx context.Context, prefix string) ([]docker.ContainerState, error)
Create(ctx context.Context, spec docker.ContainerSpec) (string, error)
Start(ctx context.Context, id string) error
Stop(ctx context.Context, id string, timeout time.Duration) error
Remove(ctx context.Context, id string, force bool) error
EnsureNetwork(ctx context.Context, name string) (string, error)
}
Containers is the slice of the Docker wrapper the runtime uses.
type DBTX ¶
type DBTX interface {
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
}
DBTX is the slice of *sql.DB (and the control plane's store.DB) the SQL store needs.
type InstallRequest ¶
type InstallRequest struct {
Manifest []byte
Signature string
KeyID string
ExpectedDigest string
ConfigJSON string
}
InstallRequest is everything an operator submits to install a plugin.
type InvalidError ¶
type InvalidError struct{ Msg string }
InvalidError marks a request the operator can fix, as opposed to an internal failure.
func (*InvalidError) Error ¶
func (e *InvalidError) Error() string
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager owns plugin installation, approval and supervision.
func NewManager ¶
NewManager builds a Manager. audit and docker must be non-nil.
func (*Manager) Approve ¶
func (m *Manager) Approve(ctx context.Context, name string, abilities []string, actor string) (Record, error)
Approve records the abilities the operator grants. They must be a subset of what the manifest requested; nothing is ever granted implicitly.
func (*Manager) Enable ¶
Enable allows the supervisor to run the plugin. It needs a prior approval that includes read.
func (*Manager) Install ¶
Install verifies and records a plugin. It never approves abilities and never starts anything.
func (*Manager) Reconcile ¶
Reconcile converges running containers to the stored plugin state. It is level-triggered and safe to call at any time.
func (*Manager) Remove ¶
Remove marks a plugin for removal and tries to clean up at once. If the container cannot be removed now the row stays in the removing state and the supervisor retries on its next pass.
func (*Manager) Send ¶
Send hands one notification to an enabled notification_channel plugin. secret is the credential for this call only: it is never stored or logged here.
func (*Manager) TrustAdd ¶
func (m *Manager) TrustAdd(ctx context.Context, name, publicKeyB64, actor string) (TrustedKey, error)
TrustAdd adds a publisher key to the trust list.
type Manifest ¶
type Manifest struct {
APIVersion int `yaml:"api_version" json:"api_version"`
Name string `yaml:"name" json:"name"`
Version string `yaml:"version" json:"version"`
Kind string `yaml:"kind" json:"kind"`
Publisher string `yaml:"publisher" json:"publisher"`
Description string `yaml:"description" json:"description"`
Image string `yaml:"image" json:"image"`
Abilities []string `yaml:"abilities" json:"abilities"`
OutboundHosts []string `yaml:"outbound_hosts" json:"outbound_hosts"`
}
Manifest is the plugin.yaml a publisher signs together with the image digest.
func ParseManifest ¶
ParseManifest decodes and validates raw manifest bytes. Unknown fields are an error so a typo in an ability list can never silently widen or narrow it.
type Notification ¶
type Notification struct {
ID string
Title string
Body string
Status string
Severity string
ResourceID string
Link string
At time.Time
// SensitiveLines are log excerpts. They reach the plugin only when the
// operator approved read:sensitive for it.
SensitiveLines []string
}
Notification is the one event a notification_channel plugin receives.
type Record ¶
type Record struct {
Name string `json:"name"`
Version string `json:"version"`
Kind string `json:"kind"`
Publisher string `json:"publisher"`
Description string `json:"description"`
Image string `json:"image"`
Digest string `json:"digest"`
Manifest string `json:"manifest"`
Signature string `json:"-"`
KeyID string `json:"key_id"`
RequestedAbilities []string `json:"requested_abilities"`
ApprovedAbilities []string `json:"approved_abilities"`
OutboundHosts []string `json:"outbound_hosts"`
ConfigJSON string `json:"config_json"`
State string `json:"state"`
ApprovedAt string `json:"approved_at"`
ApprovedBy string `json:"approved_by"`
InstalledAt string `json:"installed_at"`
InstalledBy string `json:"installed_by"`
UpdatedAt string `json:"updated_at"`
LastError string `json:"last_error"`
}
Record is one installed plugin as stored.
type SQLStore ¶
type SQLStore struct {
// contains filtered or unexported fields
}
SQLStore implements Store over the control plane database.
func (*SQLStore) AddKey ¶
func (s *SQLStore) AddKey(ctx context.Context, k TrustedKey) error
AddKey trusts a publisher key.
func (*SQLStore) DeletePlugin ¶
DeletePlugin removes a plugin row.
func (*SQLStore) InsertPlugin ¶
InsertPlugin adds a plugin, or returns ErrExists.
func (*SQLStore) ListKeys ¶
func (s *SQLStore) ListKeys(ctx context.Context) ([]TrustedKey, error)
ListKeys returns the trust list.
func (*SQLStore) ListPlugins ¶
ListPlugins returns every plugin, by name.
func (*SQLStore) SetLastError ¶
SetLastError records the latest runtime failure without touching state or approvals.
type Store ¶
type Store interface {
ListPlugins(ctx context.Context) ([]Record, error)
GetPlugin(ctx context.Context, name string) (Record, error)
InsertPlugin(ctx context.Context, r Record) error
UpdatePlugin(ctx context.Context, r Record) error
SetLastError(ctx context.Context, name, msg, updatedAt string) error
DeletePlugin(ctx context.Context, name string) error
ListKeys(ctx context.Context) ([]TrustedKey, error)
AddKey(ctx context.Context, k TrustedKey) error
RemoveKey(ctx context.Context, keyID string) error
}
Store persists plugins and the trust list.