config

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Nov 6, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package config loads locklog profiles from the project and user config files (`.locklog/config.toml`, then the user's), applies the defaults, refuses anything that looks like a secret or that the production rules forbid, and computes the security-relevant policy of a profile. The file lookup, the secret-safe decoding, the shared profile base and the diff helpers are lockkit's.

Index

Constants

View Source
const (
	PresetFullAuto = "full-auto"
	PresetDefault  = "default"
)

The presets: PresetFullAuto sets every action to auto, PresetDefault is DefaultAutoRules.

View Source
const (
	// StructuredRedactUnknown redacts every leaf that is neither trusted
	// nor named by an allow rule (the production default).
	StructuredRedactUnknown = mask.StructuredRedactUnknown
	// StructuredDetect masks what rules, names and detectors find.
	StructuredDetect = mask.StructuredDetect
)

Structured modes: how the leaves of structured records (JSON, logfmt, journald, syslog structured data) are masked.

View Source
const (
	// TextDetect masks what the detectors find (the default).
	TextDetect = "detect"
	// TextTemplate also replaces every variable token of a clustered
	// template.
	TextTemplate = "template"
)

Text modes: how free text is masked.

View Source
const (
	UnmaskNever    = "never"
	UnmaskApproved = "approved"
)

Unmask modes: whether the agent may ask a human to unmask a value.

View Source
const (
	LookupFree     = "free"
	LookupApproved = "approved"
)

Lookup modes: whether locklog_lookup is free (rate-limited) or a ticket the human approves.

View Source
const (
	RotationSession = "session"
	RotationNever   = "never"
)

Pseudonym rotation keywords; any other value is a duration.

View Source
const (
	RangeCeiling    = 400 * Day
	BytesCeiling    = 64 * GiB
	RecordsCeiling  = 1000
	OutputCeiling   = 1 * MiB
	PIIRulesCeiling = 500
	// CallsCeiling bounds limits.max_calls: each call may hold its
	// per-call budgets at once.
	CallsCeiling = 64
	// Rolling budgets: ceilings no profile can go past either.
	BytesPerHourCeiling = 1 * TiB
	RateCeiling         = 6000
	LookupsCeiling      = 1000
	PIIAddsCeiling      = 100
	DefaultRotation     = 7 * Day
	DefaultMaxAge       = 30 * Day
	MinRotation         = time.Hour
	MaxPseudonymAge     = 400 * Day
	DefaultMaxSession   = 12 * time.Hour
	DefaultIdle         = time.Hour
	MinIdleTimeout      = time.Minute
	MaxMaxSession       = 7 * Day
)

Hard ceilings of the per-call budgets: no profile can go past them.

View Source
const (
	KindFile     = "file"
	KindJournald = "journald"
	KindDocker   = "docker"
	KindLoki     = "loki"
	// KindElastic is Elasticsearch 8.x, KindOpenSearch OpenSearch 2.x.
	KindElastic    = "elastic"
	KindOpenSearch = "opensearch"
)

Source kinds.

View Source
const (
	AuthNone   = "none"
	AuthBasic  = "basic"
	AuthBearer = "bearer"
	AuthMTLS   = "mtls"
	// AuthAPIKey is Elasticsearch's "Authorization: ApiKey <base64>":
	// the secret is the encoded key (kind = "elastic" only).
	AuthAPIKey = "api_key"
)

Auth modes of a remote source.

View Source
const (
	KiB int64 = 1 << 10
	MiB int64 = 1 << 20
	GiB int64 = 1 << 30
	TiB int64 = 1 << 40
)

Byte sizes.

View Source
const ConsolePrefix = "locklog-console"

ConsolePrefix starts the name of every locklog console container. A container glob that can match any name with this prefix is refused; the docker source also skips console containers by label and id when it reads, whatever the glob.

View Source
const Day = 24 * time.Hour

Day is 24 hours: the unit of the long ranges ("7d", "400d").

View Source
const DefaultMaxCalls = 4

DefaultMaxCalls is the agent calls a console runs at once when the profile does not set limits.max_calls (engine.DefaultMaxCalls).

View Source
const Version = 1

Version is the config file format this binary reads. A file with a later version is refused: it was written for a newer locklog.

Variables

AutoActions lists the actions in the order they are shown.

View Source
var DefaultAutoRules = AutoRules{Read: AutoAsk, Unmask: AutoAsk, Lookup: AutoAsk}

DefaultAutoRules is the auto mode of a profile that sets none: every ticket asked, as before auto rules existed (an approved scan covers a whole plan, an unmask and an approved lookup are read-pii). Making any of them auto is the human's explicit, reviewed loosening.

View Source
var Formats = []string{"auto", "json", "logfmt", "syslog", "cri", "docker-json", "combined", "plain"}

Formats of log lines. "auto" detects the format per line.

View Source
var FullAutoRules = AutoRules{Read: AutoAuto, Unmask: AutoAuto, Lookup: AutoAuto}

FullAutoRules is the full-auto preset: every action auto.

View Source
var JournaldTrusted = []string{"CODE_FILE", "CODE_FUNC", "CODE_LINE", "CONTAINER_NAME", "PRIORITY",
	"SYSLOG_IDENTIFIER", "_HOSTNAME", "_PID", "_SYSTEMD_UNIT", "_TRANSPORT"}

JournaldTrusted are the journald fields locklog trusts: shown in clear (after the detectors) and selectable. MESSAGE is text, masked.

Kinds lists the source kinds in a fixed order.

View Source
var LooseningKeys = []string{"production", "prefilter", "unmask", "lookup", "network", "user_journals", "allow", "extra_roots"}

LooseningKeys are the profile keys whose loosening is a policy-loosen change request when the agent proposes it, and a confirmation at the console when the human edits it. Every other loosening (a new source, path, container, unit, trusted field or label, a larger limit) is reviewed the same way; these are the keys named for the agent.

View Source
var Multilines = []string{"none", "indent"}

Multiline modes: how lines are assembled into events. "indent" joins a line that starts with whitespace to the event before it (stack traces).

Functions

func CheckDockerAlone

func CheckDockerAlone(sources []Source) error

CheckDockerAlone refuses a docker source beside a file or journald source (the mount plan applies it: a profile may still describe both, e.g. for review, but no console mounts them together). Reading the containers root needs gid 0, and a supplementary group applies to the whole console process: beside other bound log directories it would open every file of theirs readable by group root. Remote sources stay allowed.

func DefaultDetectors

func DefaultDetectors() []string

DefaultDetectors is the detector set of a profile that sets none (mask.DefaultValueDetectors: lockkit's defaults and ip). person_name and phone_loose are opt-in for their false positives (OptInDetectors). Secret detection is not a detector setting: it is always on, and a profile naming "secret" is refused.

func DefaultStructured

func DefaultStructured(production bool) string

DefaultStructured is redact-unknown on production, detect elsewhere.

func DefaultUnmask

func DefaultUnmask(production bool) string

DefaultUnmask is never on production, approved elsewhere.

func FormatDuration

func FormatDuration(d time.Duration) string

FormatDuration is the inverse of ParseDuration: whole days as "Nd", anything else in Go's form.

func FormatSize

func FormatSize(n int64) string

FormatSize writes n with the largest binary unit that divides it.

func Load

func Load(cwd string) (map[string]Profile, string, error)

Load reads the user config and the project config (found by walking up from cwd). On a profile name present in both, the project profile wins as a whole. It also returns the project root ("" when none).

func LoadFile

func LoadFile(path string) (map[string]Profile, error)

LoadFile reads the profiles of one config file.

func LoadFrom

func LoadFrom(cwd, userConfigPath string) (map[string]Profile, string, error)

LoadFrom is Load with an explicit user config path ("" for none). A missing user config file is not an error.

func OptInDetectors

func OptInDetectors() []string

OptInDetectors are the value detectors a profile may add to the default set by naming them in `detectors`.

func ParseDuration

func ParseDuration(s string) (time.Duration, error)

ParseDuration parses a Go duration ("90m", "24h") or a whole number of days ("7d"). Only positive durations are valid.

func ParseProfiles

func ParseProfiles(data []byte, name string) (map[string]Profile, error)

ParseProfiles decodes and validates config data; name labels errors. Errors never quote a value that could hold a secret.

func ParseSize

func ParseSize(s string) (int64, error)

ParseSize parses a positive byte size written with a binary unit: "64KiB", "4GiB", "512B".

func ValidContainerName

func ValidContainerName(n string) bool

ValidContainerName reports whether n is a container name (not a glob) the docker source may serve: the characters of a container glob, without '*' and '?'.

func ValidIndex

func ValidIndex(name string) bool

ValidIndex reports whether name is an index name or trailing-'*' pattern a source may name.

Types

type AutoAction added in v0.2.0

type AutoAction string

AutoAction is what a rule applies to.

const (
	// ActionRead is an approved scan (locklog_scan): the masked records
	// of a whole plan, one ticket for all its continuations (risk read).
	ActionRead AutoAction = "read"
	// ActionUnmask is an unmask (locklog_unmask): clear values to the
	// agent (risk read-pii).
	ActionUnmask AutoAction = "unmask"
	// ActionLookup is a lookup: with lookup = "approved", its ticket
	// (risk read-pii); deny refuses free lookups too.
	ActionLookup AutoAction = "lookup"
)

The actions of an auto rule.

type AutoRules added in v0.2.0

type AutoRules struct {
	Read   AutoValue `json:"read,omitempty"`
	Unmask AutoValue `json:"unmask,omitempty"`
	Lookup AutoValue `json:"lookup,omitempty"`
}

AutoRules is the auto mode of a profile, one value per action. The zero value of a field is its default (DefaultAutoRules): a profile stores only what differs from it, so that a policy approved before auto rules existed keeps its fingerprint.

func (AutoRules) Effective added in v0.2.0

func (r AutoRules) Effective() AutoRules

Effective is r with every action set (defaults filled in).

func (AutoRules) Get added in v0.2.0

func (r AutoRules) Get(a AutoAction) AutoValue

Get is the value of action a, its default when r does not set it; an unknown action, or a value that is not one, is deny (fail closed).

func (AutoRules) Map added in v0.2.0

func (r AutoRules) Map() map[string]AutoValue

Map is r's effective rules by action name: what `locklog profile rules --json` prints for lox run.

func (AutoRules) Preset added in v0.2.0

func (r AutoRules) Preset() string

Preset names the preset r is, "" for none.

func (AutoRules) RuleText added in v0.2.0

func (r AutoRules) RuleText(a AutoAction) string

RuleText is the rule of action a as the audit records it: "auto.read = ask".

func (AutoRules) String added in v0.2.0

func (r AutoRules) String() string

String is r in one line: "read ask · unmask ask · lookup ask", with the preset it is when it is one.

type AutoValue added in v0.2.0

type AutoValue string

AutoValue is what auto mode does with one action.

const (
	// AutoDeny refuses the action, even when a human would approve it.
	AutoDeny AutoValue = "deny"
	// AutoAsk asks the human every time.
	AutoAsk AutoValue = "ask"
	// AutoAuto leaves the ticket to lox run's auto mode.
	AutoAuto AutoValue = "auto"
)

The values of an action, from the strictest.

func ParseAutoValue added in v0.2.0

func ParseAutoValue(s string) (AutoValue, error)

ParseAutoValue parses "auto", "ask" or "deny". Its error never quotes s.

type Budgets

type Budgets struct {
	// Range is the widest time range of a call with text, regex or
	// masked-field predicates.
	Range time.Duration `json:"range"`
	// CountRange is the widest range of a count on trusted fields only,
	// served from the local index or server-side metric queries.
	CountRange time.Duration `json:"count_range"`
	// MaxBytes is the most bytes one call processes (remote: fetches).
	MaxBytes int64 `json:"max_bytes"`
	// BytesPerHour is the rolling budget of bytes processed per hour.
	BytesPerHour int64 `json:"bytes_per_hour"`
	// MetricQueriesPerHour and RequestsPerMinute bound the load put on a
	// remote backend (remote only; 0 for local).
	MetricQueriesPerHour int `json:"metric_queries_per_hour,omitempty"`
	RequestsPerMinute    int `json:"requests_per_minute,omitempty"`
}

Budgets are the per-call and rolling budgets of one kind of source (local: files, journald, containers; remote: Loki and the like).

type Limits

type Limits struct {
	Local  Budgets `json:"local"`
	Remote Budgets `json:"remote"`
	// MaxRecords and MaxOutputBytes cap one call's output.
	MaxRecords     int   `json:"max_records"`
	MaxOutputBytes int64 `json:"max_output_bytes"`
	// LookupsPerHour caps the distinct values locklog_lookup resolves per
	// hour for the whole console, LookupsPerHourPerUID per peer uid.
	LookupsPerHour       int `json:"lookups_per_hour"`
	LookupsPerHourPerUID int `json:"lookups_per_hour_per_uid"`
	// PIIAddsPerHour and PIIRulesMax cap the agent's own masking rules.
	PIIAddsPerHour int `json:"pii_adds_per_hour"`
	PIIRulesMax    int `json:"pii_rules_max"`
	// MaxCalls caps the agent calls the console runs at once; a call over
	// it is refused with E_BUSY. 0 is the default (DefaultMaxCalls), and
	// is left out of the policy's JSON so that a profile that does not
	// set it keeps its fingerprint.
	MaxCalls int `json:"max_calls,omitempty"`
}

Limits bound what the agent's free calls can cost and return.

func DefaultLimits

func DefaultLimits(production bool) Limits

DefaultLimits returns the limits of a profile that sets none.

func (Limits) Calls added in v0.2.0

func (l Limits) Calls() int

Calls is the agent calls the console runs at once.

type Policy

type Policy struct {
	Profile Profile `json:"profile"`
	// Network is LOCKLOG_NETWORK: a Docker network the console joins to
	// reach a backend ("" for none).
	Network string `json:"network"`
	// ExtraRoots is LOCKLOG_EXTRA_ROOTS: mount roots beyond the built-in
	// allowlist, sorted.
	ExtraRoots []string `json:"extra_roots"`
	// PIIAllow are the allow rules of the project's .locklog/pii.toml in
	// their canonical form (mask.Rule.Text), sorted: an allow rule loosens
	// the masking, so it applies only once part of an approved policy.
	PIIAllow []string `json:"pii_allow,omitempty"`
}

Policy is the security-relevant view of one profile plus the launch environment the human chose (the network the console joins, the extra mount roots): what the console fingerprints, compares with the last approved one and asks the human about before applying any loosening.

func Canonical

func Canonical(p Policy) Policy

Canonical sorts and de-duplicates the lists of p: its JSON is the fingerprinted form.

func NewPolicy

func NewPolicy(p Profile, network string, extraRoots []string) (Policy, error)

NewPolicy builds the canonical policy of p started with network and extraRoots.

func (Policy) Describe

func (p Policy) Describe() []string

Describe is the policy as lines for the console's status and review screens.

func (Policy) Diff

func (p Policy) Diff(approved kconfig.Policy) []kconfig.Change

Diff lists the changes from approved to p and marks each loosening: production true → false (and the session limits, through kconfig.DiffBase), structured redact-unknown → detect, text template → detect, a removed detector, unmask never → approved, lookup approved → free, strict on → off, prefilter or user_journals off → on, a longer pseudonym rotation or max age, any larger limit, another network, an added extra root, an added allow rule of .locklog/pii.toml, and for sources: a new source, another kind, format or multiline mode, an added path, unit (or every unit), container, allowed field, attr, trusted field or label, recursive off → on, and for a remote source any change of url, selector, auth, org_id or connection (kconfig.DiffBase), and an auto rule moved toward auto (deny → ask → auto).

func (Policy) Fingerprint

func (p Policy) Fingerprint() string

Fingerprint is the policy's fingerprint (policy_fp): it binds refs, cursors and approvals to the policy they were made under.

type Profile

type Profile struct {
	Name string `json:"name"`
	// Base carries production and the session limits; its connection
	// fields are unused (each remote source has its own).
	kconfig.Base
	Structured string   `json:"structured"`
	Text       string   `json:"text"`
	Detectors  []string `json:"detectors"`
	Unmask     string   `json:"unmask"`
	Lookup     string   `json:"lookup"`
	// Strict makes every search and count a ticket the human approves.
	Strict bool `json:"strict"`
	// Prefilter matches clear text before masking (non-production only):
	// faster, but latency then reveals how many records hold a substring.
	Prefilter bool `json:"prefilter"`
	// UserJournals also serves user-*.journal files.
	UserJournals bool `json:"user_journals"`
	// PseudonymRotation is "session", "never" or a duration ("7d");
	// PseudonymMaxAge is when an unrotated key shows red.
	PseudonymRotation string        `json:"pseudonym_rotation"`
	PseudonymMaxAge   time.Duration `json:"pseudonym_max_age"`
	Limits            Limits        `json:"limits"`
	// Sources are sorted by name.
	Sources []Source `json:"sources"`
	// Auto is the profile's auto mode for lox run (auto.go): only the
	// actions that differ from DefaultAutoRules, nil when none does. Read
	// it with AutoRules.
	Auto *AutoRules `json:"auto,omitempty"`
}

Profile is one named set of log sources with its masking and budget policy. It never holds a secret.

func (Profile) AutoRules added in v0.2.0

func (p Profile) AutoRules() AutoRules

AutoRules is the effective auto mode of p.

func (Profile) RotationEvery

func (p Profile) RotationEvery() time.Duration

RotationEvery is the rotation interval: 0 for "session" (a new key per console session) and for "never".

func (Profile) Source

func (p Profile) Source(n string) (Source, bool)

Source returns the source named n.

type Remote

type Remote struct {
	URL string `json:"url"`
	// Selector is ANDed into every query: label = value (Loki), field =
	// value (Elasticsearch, OpenSearch).
	Selector map[string]string `json:"selector"`
	// TrustedLabels and TrustedMetadata (Loki) are shown (after the
	// detectors) and selectable; every other label and field is dropped.
	TrustedLabels   []string `json:"trusted_labels"`
	TrustedMetadata []string `json:"trusted_metadata"`
	Auth            string   `json:"auth"`
	OrgID           string   `json:"org_id,omitempty"`

	// Elasticsearch and OpenSearch: the indices, aliases, data streams or
	// trailing-'*' patterns read; the keyword fields shown (after the
	// detectors), selectable and countable (every other field is
	// dropped); the time, message and tiebreaker fields; the OpenSearch
	// roles the human vouches grant no write or manage permission.
	Indices       []string `json:"indices,omitempty"`
	TrustedFields []string `json:"trusted_fields,omitempty"`
	TimeField     string   `json:"time_field,omitempty"`
	MessageField  string   `json:"message_field,omitempty"`
	TieBreaker    string   `json:"tiebreaker,omitempty"`
	ReadOnlyRoles []string `json:"read_only_roles,omitempty"`
	// Base holds user, credentials, vault_path and the TLS settings.
	kconfig.Base
}

Remote is the connection and server-side scope of a remote source.

type Source

type Source struct {
	Name string `json:"name"`
	Kind string `json:"kind"`
	// Format is the format of a line (of the message, for journald,
	// containers and Loki); Multiline how lines become events.
	Format    string `json:"format"`
	Multiline string `json:"multiline"`
	// Trusted are the fields the human trusts beyond the parser's own:
	// shown in clear after the detectors, selectable and countable.
	Trusted []string `json:"trusted"`

	// File: absolute path globs; ** (one per glob) only when Recursive.
	Paths     []string `json:"paths,omitempty"`
	Recursive bool     `json:"recursive,omitempty"`

	// journald: the units served (empty: every unit), extra fields
	// allowed besides the trusted ones and MESSAGE.
	Units []string `json:"units,omitempty"`
	Allow []string `json:"allow,omitempty"`

	// Docker: container name globs, and the json-file attrs allowed.
	Containers []string `json:"containers,omitempty"`
	Attrs      []string `json:"attrs,omitempty"`

	// Loki, Elasticsearch, OpenSearch.
	Remote *Remote `json:"remote,omitempty"`
}

Source is one approved log source of a profile. It never holds a secret.

func (Source) TrustedFields

func (s Source) TrustedFields() []string

TrustedFields is every field of s locklog trusts: the parser's known fields (and journald's) plus the human's, sorted.

Jump to

Keyboard shortcuts

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