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
- Variables
- func ContainsHandle(text string) bool
- func IsHandle(value string) bool
- type AnswerField
- type Binding
- type Direction
- type Header
- type Request
- type RequestField
- type RequestInput
- type Route
- type Sealed
- type Sealer
- func (s *Sealer) ExpandAnswer(key, routeID string, body []byte, headers []Header) ([]byte, int, error)
- func (s *Sealer) Listed(routeID string) bool
- func (s *Sealer) Release(key string)
- func (s *Sealer) SealRequest(input RequestInput) (Sealed, error)
- func (s *Sealer) Store() *Store
- func (s *Sealer) Table() *Table
- type Secret
- type Store
- type Table
- type Target
- type TargetRule
- type Use
Constants ¶
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.
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.
const FieldsFormat = "anixops.node-secret-fields/v1"
FieldsFormat is the format of config/node-secret-fields.json.
const Placeholder = nodesecrets.Placeholder
Placeholder is the masked value of a node secret. Sent back, it keeps the stored secret, so it passes unchanged.
const Prefix = v2compat.SealedHandlePrefix
Prefix starts every handle (v2compat.SealedHandlePrefix).
Variables ¶
var ( 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.
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 ¶
ContainsHandle reports whether text holds a sealed handle anywhere.
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 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 ¶
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 ¶
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 ¶
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) 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.
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 (*Store) Live ¶
Live reports whether a handle is in the store: sealed or minted for a request in flight.
func (*Store) Mint ¶
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 ¶
Pending reports how many requests the store holds, for tests and diagnostics.
func (*Store) Release ¶
Release ends a request: every handle sealed or minted for it is dropped with its secret. Releasing twice is harmless.
func (*Store) Resolve ¶
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 ¶
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.
type Target ¶
Target is what a sealed secret is stored for: a kind of config/node-secret-fields.json and a resource id.
type TargetRule ¶
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.