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
- Variables
- func CheckDockerAlone(sources []Source) error
- func DefaultDetectors() []string
- func DefaultStructured(production bool) string
- func DefaultUnmask(production bool) string
- func FormatDuration(d time.Duration) string
- func FormatSize(n int64) string
- func Load(cwd string) (map[string]Profile, string, error)
- func LoadFile(path string) (map[string]Profile, error)
- func LoadFrom(cwd, userConfigPath string) (map[string]Profile, string, error)
- func OptInDetectors() []string
- func ParseDuration(s string) (time.Duration, error)
- func ParseProfiles(data []byte, name string) (map[string]Profile, error)
- func ParseSize(s string) (int64, error)
- func ValidContainerName(n string) bool
- func ValidIndex(name string) bool
- type Budgets
- type Limits
- type Policy
- type Profile
- type Remote
- type Source
Constants ¶
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.
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.
const ( UnmaskNever = "never" UnmaskApproved = "approved" )
Unmask modes: whether the agent may ask a human to unmask a value.
const ( LookupFree = "free" LookupApproved = "approved" )
Lookup modes: whether locklog_lookup is free (rate-limited) or a ticket the human approves.
const ( RotationSession = "session" RotationNever = "never" )
Pseudonym rotation keywords; any other value is a duration.
const ( RangeCeiling = 400 * Day BytesCeiling = 64 * GiB RecordsCeiling = 1000 OutputCeiling = 1 * MiB PIIRulesCeiling = 500 // 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.
const ( KindFile = "file" KindJournald = "journald" KindDocker = "docker" KindLoki = "loki" // KindElastic is Elasticsearch 8.x, KindOpenSearch OpenSearch 2.x. KindElastic = "elastic" KindOpenSearch = "opensearch" )
Source kinds.
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.
const ( KiB int64 = 1 << 10 MiB int64 = 1 << 20 GiB int64 = 1 << 30 TiB int64 = 1 << 40 )
Byte sizes.
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.
const Day = 24 * time.Hour
Day is 24 hours: the unit of the long ranges ("7d", "400d").
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 ¶
var Formats = []string{"auto", "json", "logfmt", "syslog", "cri", "docker-json", "combined", "plain"}
Formats of log lines. "auto" detects the format per line.
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.
var Kinds = []string{KindFile, KindJournald, KindDocker, KindLoki, KindElastic, KindOpenSearch}
Kinds lists the source kinds in a fixed order.
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.
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 ¶
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 ¶
DefaultStructured is redact-unknown on production, detect elsewhere.
func DefaultUnmask ¶
DefaultUnmask is never on production, approved elsewhere.
func FormatDuration ¶
FormatDuration is the inverse of ParseDuration: whole days as "Nd", anything else in Go's form.
func FormatSize ¶
FormatSize writes n with the largest binary unit that divides it.
func Load ¶
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 LoadFrom ¶
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 ¶
ParseDuration parses a Go duration ("90m", "24h") or a whole number of days ("7d"). Only positive durations are valid.
func ParseProfiles ¶
ParseProfiles decodes and validates config data; name labels errors. Errors never quote a value that could hold a secret.
func ParseSize ¶
ParseSize parses a positive byte size written with a binary unit: "64KiB", "4GiB", "512B".
func ValidContainerName ¶
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 ¶
ValidIndex reports whether name is an index name or trailing-'*' pattern a source may name.
Types ¶
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"`
}
Limits bound what the agent's free calls can cost and return.
func DefaultLimits ¶
DefaultLimits returns the limits of a profile that sets none.
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"`
}
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 ¶
Canonical sorts and de-duplicates the lists of p: its JSON is the fingerprinted form.
func (Policy) Describe ¶
Describe is the policy as lines for the console's status and review screens.
func (Policy) Diff ¶
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, 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).
func (Policy) Fingerprint ¶
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"`
}
Profile is one named set of log sources with its masking and budget policy. It never holds a secret.
func (Profile) RotationEvery ¶
RotationEvery is the rotation interval: 0 for "session" (a new key per console session) and for "never".
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 ¶
TrustedFields is every field of s locklog trusts: the parser's known fields (and journald's) plus the human's, sorted.