sealedsecrets

package
v4.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package sealedsecrets keeps node secrets away from package hosts (docs/architecture/node-ops-service.md section 3.7, NO-4).

For the routes and fields of config/node-secret-fields.json the kernel's v2 gateway replaces every secret an administrator sends with an opaque, single-use handle before the package host reads the request, and expands the handles the kernel minted for a secret shown once only in the answer to the request they were minted for. A handle lives in kernel memory only, bound to one request (its key, package generation, request id and route), its target and its field, and dies with the request. Handles and the secrets they stand for never appear in logs, metric labels, the KernelNodeOps ledger or error texts.

Index

Constants

View Source
const (
	TargetProxy           = "proxy"
	TargetForward         = "forward"
	TargetProtocol        = "protocol"
	TargetCleanAgent      = "clean_agent"
	TargetRegistrationKey = "registration_key"
	// TargetNone is a route whose secrets are never stored (validation):
	// its handles never resolve.
	TargetNone = "none"
	// TargetDial is a route whose secret is presented once, by the kernel,
	// to the address the request names, and never stored (a connection
	// test): its handles resolve for the bound request only, for no
	// resource.
	TargetDial = "dial"
)

Target kinds: what a route's sealed secrets may be stored for.

View Source
const (
	// FieldValue is one secret value: a string. The placeholder and an
	// empty string pass unchanged; any other non-string value fails the
	// substitution, so the legacy handler answers it.
	FieldValue = "value"
	// FieldDocument is a JSON document (a protocol setting, a raw
	// configuration), inline or as a JSON string: every value under a key
	// that nodesecrets.IsSecretKey marks is sealed, as the administrator's
	// answers mask it.
	FieldDocument = "document"
)

Request field kinds.

View Source
const FieldsFormat = "anixops.node-secret-fields/v1"

FieldsFormat is the format of config/node-secret-fields.json.

View Source
const Placeholder = nodesecrets.Placeholder

Placeholder is the masked value of a node secret. Sent back, it keeps the stored secret, so it passes unchanged.

Prefix starts every handle (v2compat.SealedHandlePrefix).

Variables

View Source
var (
	ErrFieldsUnavailable = errors.New("the node secret field list is unavailable")
	ErrNotJSON           = errors.New("the request body is not the JSON the route takes")
	ErrValueNotString    = errors.New("a secret field holds a value that is not a string")
	ErrTargetInvalid     = errors.New("the route's target is not a resource id")
	ErrTooLarge          = errors.New("the sealed request exceeds the request body limit")
	ErrAnswerHandle      = errors.New("the answer holds a sealed handle it cannot show")
	ErrStore             = errors.New("the sealed secret store failed")
)

Why a substitution or an expansion failed. They are the complete, fixed set of reasons the gateway counts.

View Source
var (
	// ErrRefused is every refused resolution, mint or expansion. Its text
	// names no handle, value, request or field.
	ErrRefused = errors.New("sealed secret handle refused")
	// ErrRequestEnded is a binding whose request has ended or was never
	// sealed.
	ErrRequestEnded = errors.New("the sealed request has ended")
)

Functions

func ContainsHandle

func ContainsHandle(text string) bool

ContainsHandle reports whether text holds a sealed handle anywhere.

func IsHandle

func IsHandle(value string) bool

IsHandle reports whether value is a sealed handle.

Types

type AnswerField

type AnswerField struct {
	Pointer string
	// Name names the secret, as SecretHandle.field does: only a handle the
	// kernel minted under this name expands here.
	Name string
	// contains filtered or unexported fields
}

AnswerField is an answer position where a secret is shown once.

type Binding

type Binding struct {
	Key        string
	PackageID  string
	Generation uint64
	RequestID  string
	RouteID    string
}

Binding is a verified request binding as a KernelNodeOps executor holds it: the live request the package is serving.

type Direction

type Direction uint8

Direction is where a handle came from.

const (
	// Inbound handles stand for secrets an administrator's request carried.
	Inbound Direction = iota + 1
	// Outbound handles stand for secrets the kernel generated for the
	// request's answer.
	Outbound
)
type Header struct {
	Name  string
	Value string
}

Header is one answer header.

type Request

type Request struct {
	PackageID  string
	Generation uint64
	RequestID  string
	RouteID    string
	// Target is the route's target for this request: ID 0 with New for a
	// resource the request creates (the first resolution binds it), or
	// kind none.
	Target   Target
	New      bool
	Deadline time.Time
}

Request is one gateway request whose secrets are sealed.

type RequestField

type RequestField struct {
	Pointer string
	Kind    string
	// contains filtered or unexported fields
}

RequestField is a request position that carries a secret an administrator types.

type RequestInput

type RequestInput struct {
	PackageID  string
	Generation uint64
	RequestID  string
	RouteID    string
	Deadline   time.Time
	Body       []byte
	PathParams map[string]string
	// BodyLimit bounds the sealed body, as the gateway bounds the request
	// body; zero leaves it unbounded.
	BodyLimit int64
}

RequestInput is one gateway request of a listed route.

type Route

type Route struct {
	ID      string
	Target  TargetRule
	Request []RequestField
	Answer  []AnswerField
}

Route is one listed route.

type Sealed

type Sealed struct {
	// Key names the sealed request; the bridge capability carries it, and
	// Release ends it.
	Key string
	// Body is what the package host reads; the kernel's legacy handler
	// reads the original.
	Body []byte
	// Count is the number of secrets sealed.
	Count int
}

Sealed is a request sealed for its package host.

type Sealer

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

Sealer seals the gateway's requests and expands its answers for the routes of a field list.

func DefaultSealer

func DefaultSealer() *Sealer

DefaultSealer is the process's sealer: the field list the kernel binary embeds, on DefaultStore.

func NewSealer

func NewSealer(table *Table, err error, store *Store) *Sealer

NewSealer returns a sealer for table on store. A nil table with err fails closed: every request with a body is refused.

func (*Sealer) ExpandAnswer

func (s *Sealer) ExpandAnswer(key, routeID string, body []byte, headers []Header) ([]byte, int, error)

ExpandAnswer returns a package's answer as the client gets it: every handle the kernel minted for this request (key) under the name of the listed answer field it stands in is replaced by its secret, once. Any other handle that would reach the client fails it: a handle at a listed answer field that is not one of this request's, or a handle sealed or minted for any request in flight, anywhere in the body or the headers. A string at an unlisted position that has the shape of a handle but is none is data and passes. It returns the answer and how many handles it expanded.

func (*Sealer) Listed

func (s *Sealer) Listed(routeID string) bool

Listed reports whether a route's requests are sealed: it is in the field list, or the list is unavailable and nothing can be told.

func (*Sealer) Release

func (s *Sealer) Release(key string)

Release ends a sealed request.

func (*Sealer) SealRequest

func (s *Sealer) SealRequest(input RequestInput) (Sealed, error)

SealRequest replaces every secret of a listed route's request body with a handle bound to the request. It fails closed: a body that is not JSON, a secret field holding a value that is not a string, a target path parameter that is not an id, a sealed body over the limit, or an unavailable field list is an error, and the caller serves the request without the package host or refuses it. On success the caller releases the key when the request ends, with or without an error.

func (*Sealer) Store

func (s *Sealer) Store() *Store

Store returns the sealer's store.

func (*Sealer) Table

func (s *Sealer) Table() *Table

Table returns the sealer's field list, nil when it is unavailable.

type Secret

type Secret struct {
	// Value is the secret: a string, or with JSON set the JSON encoding of
	// a non-string value (an array under a secret key).
	Value string
	JSON  bool
}

Secret is a resolved value.

type Store

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

Store holds the handles of the requests in flight. The zero value is not usable; use NewStore.

func DefaultStore

func DefaultStore() *Store

DefaultStore is the process's store: the gateway seals into it and the KernelNodeOps engine resolves from it.

func NewStore

func NewStore(now func() time.Time) *Store

NewStore returns an empty store. now defaults to time.Now.

func (*Store) Live

func (s *Store) Live(handle string) bool

Live reports whether a handle is in the store: sealed or minted for a request in flight.

func (*Store) Mint

func (s *Store) Mint(binding Binding, name, value string) (string, time.Time, error)

Mint stores a secret the kernel generated for the answer to the request a binding names, under a name the route's answer shows (SecretHandle.field), and returns its handle and when it expires. The gateway expands it in that answer only.

func (*Store) Pending

func (s *Store) Pending() int

Pending reports how many requests the store holds, for tests and diagnostics.

func (*Store) Release

func (s *Store) Release(key string)

Release ends a request: every handle sealed or minted for it is dropped with its secret. Releasing twice is harmless.

func (*Store) Resolve

func (s *Store) Resolve(binding Binding, uses ...Use) ([]Secret, error)

Resolve resolves inbound handles for the request a binding names, all or none, and each once: a handle sealed from another request, route, target or field, one used before, one the kernel minted for an answer, or one of a route that stores no secret (target kind none) is refused, and nothing is used. A request that creates its target binds it at its first resolution: every later one must name the same resource. A dial target names no resource: a use names the kind and no id.

type Table

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

Table is the kernel-owned list of the v2 routes whose requests or answers carry node secrets, and where (config/node-secret-fields.json).

func ParseTable

func ParseTable(raw []byte) (*Table, error)

ParseTable reads and checks a field list. The route gate (config/scripts/check_plugin_only_routes.py) also checks every route id against config/package-extraction.json.

func (*Table) Route

func (t *Table) Route(routeID string) (*Route, bool)

Route returns a listed route.

func (*Table) RouteIDs

func (t *Table) RouteIDs() []string

RouteIDs returns the listed route ids.

type Target

type Target struct {
	Kind string
	ID   uint64
}

Target is what a sealed secret is stored for: a kind of config/node-secret-fields.json and a resource id.

type TargetRule

type TargetRule struct {
	Kind      string
	PathParam string
	New       bool
}

TargetRule says what the route's sealed secrets may be stored for: the resource named by a path parameter, a resource the request creates, or nothing.

type Use

type Use struct {
	Handle string
	Target Target
	// Field is the request position the handle was sealed from: the listed
	// pointer as config/node-secret-fields.json spells it, followed, in a
	// document, by the secret's pointer inside the document (for example
	// "/reality_settings/private_key").
	Field string
}

Use is one resolution an executor asks for: the handle, and the target and field the secret is stored for.

Jump to

Keyboard shortcuts

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