Documentation
¶
Overview ¶
Package managed reads the company-managed configuration of the lock family: one file, set by the company's admin (MDM, Ansible, a package), that bounds the policy of every lock, lox and lea on the machine. A user may tighten what it allows, never loosen it.
The file is /etc/lockfamily/managed.toml on Linux and /Library/Application Support/lockfamily/managed.toml on macOS. It and its directory must be owned by root and writable by root only: a badly owned file is a refusal to start, never a file ignored, since breaking it would otherwise get around it. An optional cosign signature (managed.toml.sigstore.json, next to it) is checked against the company identity set at install time (signer.toml, root-owned too); a signature present but invalid is a refusal, and [family] require_signature = true makes it mandatory. A missing file means no managed policy.
A lock in a lox container has neither cosign nor the network to verify the signature: lox verifies it on the host and writes, next to the file, managed.toml.verified (VerifiedStamp), root-owned too. A stamp that matches the managed file, its signature and signer.toml stands for the signature check; one that does not is a refusal. It is trusted because whoever can write it can already replace the managed file itself.
Each tool has its section, [<tool>.bounds], [<tool>.defaults] and [<tool>.profiles.<name>] for the locks, [lox] and [lea] decoded whole by their owner. The precedence is:
hard-coded floor > managed bounds, enforced values and profiles > project file > user file > managed defaults > built-in defaults
A product decodes its managed defaults into its config before the user and project files (Decode overlays a struct), merges its profiles with MergeProfiles (a managed profile wins as a whole and cannot be redefined), and the console checks the merged result against the bounds (Check) at start and at every policy poll.
Index ¶
- Constants
- func ClampDuration(configured, max time.Duration) time.Duration
- func DefaultPath() string
- func MergeProfiles[T any](managed, project, user map[string]T) (map[string]T, error)
- func VerifiedStamp(f *File) (string, error)
- type Bounds
- type Family
- type File
- type Source
- type Vault
- type Violation
Constants ¶
const ( FileName = "managed.toml" BundleName = FileName + ".sigstore.json" SignerName = "signer.toml" // VerifiedName is the stamp lox writes once it verified the signature // on the host (VerifiedStamp). VerifiedName = FileName + ".verified" )
File names, in the managed directory.
const ( KindBounds = "bounds" KindDefaults = "defaults" KindProfiles = "profiles" )
Section kinds of a lock's section.
const Version = 1
Version is the only managed file version this package reads.
Variables ¶
This section is empty.
Functions ¶
func ClampDuration ¶
ClampDuration is a duration within a managed maximum, the way ticket lifetimes are clamped (ticket.ClampTTL): a configured value of 0 or less (none, unlimited) or above max takes max; max of 0 or less bounds nothing.
func DefaultPath ¶
func DefaultPath() string
DefaultPath is the managed file of this OS: "" where the family reads none yet (Windows).
func MergeProfiles ¶
MergeProfiles merges a tool's profiles by precedence: a project profile replaces a user profile of the same name as a whole, and a managed profile wins as a whole: a project or user profile of a managed name is refused, never merged nor ignored, so that the user knows the profile they wrote does not apply.
func VerifiedStamp ¶ added in v0.18.0
VerifiedStamp is the line of managed.toml.verified for f, a file Load read and whose signature it verified: lox writes it, root-owned, next to the managed file it mounts in a lock's container, where the lock cannot run cosign. It is an error when f is not signed.
Types ¶
type Bounds ¶
type Bounds struct {
// Tool is the section's name ("locksql"), Profile the profile checked.
Tool, Profile string
// Ceiling is the checked policy with every bounded field set to its
// bound: the loosest policy the managed file allows for this profile.
// The tool builds it, and its own Diff then decides, as for an
// approval, whether the policy loosens it. A list bound on a
// single-valued field (credentials = ["vault", "ask"]) sets the field
// to the policy's own value when it is in the list, and to the first
// allowed value otherwise; an enforced value is a bound with one
// allowed value. Nil: the file bounds nothing of this policy.
Ceiling config.Policy
// Keys maps a Diff field to its bound's key when they differ; a field
// absent keeps its name (bounds are named after the profile keys).
Keys map[string]string
}
Bounds are a tool's [<tool>.bounds] applied to one policy: what Check compares the policy with.
type Family ¶
type Family struct {
// RequireConfinedAgent refuses an agent that does not run confined
// (lockkit#133).
RequireConfinedAgent bool `toml:"require_confined_agent"`
// RequireSignature refuses the managed file unless it is signed.
RequireSignature bool `toml:"require_signature"`
// Vault is the Vault every lock uses; each lock enforces it.
Vault *Vault `toml:"vault"`
}
Family is the [family] section: rules for every tool.
type File ¶
type File struct {
// Path is where it was read ("" when parsed from bytes).
Path string
// Fingerprint is the hex sha256 of its bytes, recorded with every
// approval and audit record made under it.
Fingerprint string
Organisation string
// Signed: its signature was present and verified.
Signed bool
Family Family
// contains filtered or unexported fields
}
File is a managed file read and trusted.
func Load ¶
Load reads the machine's managed file. It returns nil and no error when there is none. Any other failure (a badly owned file or directory, an invalid file, a signature that does not verify or is missing when required) is an error: the caller refuses to start, or ends its session.
func Parse ¶
Parse decodes and validates a managed file's bytes: version 1, known sections only, no secret-looking key, valid profile names. It checks neither ownership nor signature: Load does.
func (*File) Decode ¶
Decode decodes the table at key (["locksql", "bounds"], ["lox"], ["locksql", "profiles", "prod-erp"]) into into, strictly: a key into does not declare is refused, at any depth of nested structs. A map or an any (into itself, or one of its fields) declares every key under it, nested tables and arrays of tables included. It returns false, into untouched, when f is nil or has no such table. into is overlaid, not reset: a product decodes its managed defaults first, then its config files over them.
func (*File) Describe ¶
Describe is one line for a console's start screen and a tool's `managed show`.
func (*File) RequireConfinedAgent ¶
RequireConfinedAgent reports [family] require_confined_agent; false for a nil File (no managed policy).
type Source ¶
type Source struct {
// contains filtered or unexported fields
}
Source reads the managed file at one path, re-verifying the signature only when the file, its signature or the signer identity change.
type Vault ¶
type Vault struct {
Address string `toml:"address"`
Namespace string `toml:"namespace"`
CA string `toml:"ca"`
Required bool `toml:"required"`
}
Vault is [family] vault: with Required, Vault is the only credential source of every lock.
type Violation ¶
type Violation struct {
// Key is the managed key that refuses it ("locksql.bounds.tier").
Key string
// Profile, Field and Value are the policy's; Bound is the ceiling's
// value of the field ("" for a set element beyond an allowed set).
Profile, Field, Value, Bound string
}
Violation is one field of a policy beyond its managed bound.