Documentation
¶
Overview ¶
Package logconsole is locklog's console backend for lockkit: the agent's log methods (log.status, log.sources, log.search, log.count, ...), the checks the console makes before it opens a log (the mount roots and the .locklog directory the launcher checked, no network it was not given), the policy of a profile, and the audit record of every call. lockkit's console holds the terminal, the policy review, the approval screens and the audit log; the engine (Engine) reads and masks the logs.
Index ¶
- Constants
- Variables
- func CheckMounts(o Options) error
- func InImage(uid int, stat func(string) (os.FileInfo, error)) bool
- func Sanitizer() *sanitize.Sanitizer
- func ShowResultsFrom(ctx context.Context) bool
- func WithApprove(ctx context.Context, a Approve) context.Context
- func WithShowResults(ctx context.Context, on bool) context.Context
- type Approve
- type Backend
- func (b *Backend) Checks(ctx context.Context, s console.Session) []console.Finding
- func (b *Backend) Connect(ctx context.Context, c console.Credentials) (console.Session, error)
- func (b *Backend) LoadPolicy() (console.Policy, error)
- func (b *Backend) Methods() map[string]console.Handler
- func (b *Backend) Status(s console.Session) any
- type Caller
- type ClearView
- type Declined
- type Engine
- type OpenOptions
- type Opener
- type Options
- type Policy
- type Record
- type Refusal
- type Revealer
- type Roots
Constants ¶
const ( MethodStatus = "log.status" MethodSources = "log.sources" MethodSearch = "log.search" MethodCount = "log.count" // MethodPatterns is the top message templates of a range, optionally // against a baseline window (locklog_patterns). MethodPatterns = "log.patterns" // MethodContext, MethodTrace and MethodTail read around a ref, follow // an id across sources and follow new records (locklog_context, // locklog_trace, locklog_tail). MethodContext = "log.context" MethodTrace = "log.trace" MethodTail = "log.tail" // MethodScan is a call over the free budgets, approved once (class // read) for its whole plan (locklog_scan); MethodUnmask reveals exact // pseudonyms of one record on a read-pii approval (locklog_unmask); // MethodLookup gives the pseudonyms of clear values, rate-limited // (locklog_lookup). Policy changes go through the console's own // change.request (locklog_request_change). MethodScan = "log.scan" MethodUnmask = "log.unmask" MethodLookup = "log.lookup" )
The agent's methods. Each is free (no approval) within the budgets the engine enforces, and audited.
const EventCall = "log.call"
Audit events of locklog's calls.
const SystemFile = "/etc/locklog/system.toml"
SystemFile is the separated setup's file in locklog's image.
Variables ¶
var ErrConnLost = errors.New("the log session is lost")
ErrConnLost is returned (wrapped) by an engine whose logs can no longer be trusted to be the ones approved (a mount swapped, the engine closed): the console drops the session (console.Env.Lost) and the agent gets ipc.CodeConnLost; the next call reconnects, checking everything again.
var JournalDirs = []string{"/var/log/journal", "/run/log/journal"}
JournalDirs are the journal directories the launcher binds for a journald source, when they exist on the host.
var Methods = []string{MethodStatus, MethodSources, MethodSearch, MethodCount, MethodPatterns, MethodContext, MethodTrace, MethodTail, MethodScan, MethodUnmask, MethodLookup}
Methods lists the methods served, in a fixed order.
Functions ¶
func CheckMounts ¶
checkMounts compares, in the launcher's container, the device and inode of .locklog and of every mount root with what the launcher checked on the host: a directory swapped (for a link, another directory) between the check and docker run is refused before anything is read.
CheckMounts is exported so that the console command runs it before it reads .locklog at all; LoadPolicy and Connect run it again.
func InImage ¶
InImage reports whether this process runs in locklog's image: as the console account, or with the image's system file present. The console runs only in the launcher's container (or `lox up`'s), which always passes LOCKLOG_EXPECT_DIR: a host holding the system file but started without the launcher is refused, by design.
func Sanitizer ¶
Sanitizer scrubs locklog's error text: URL userinfo and Authorization headers, after the secrets lockkit knows.
func ShowResultsFrom ¶
ShowResultsFrom reports the clear-results switch of the call.
func WithApprove ¶
WithApprove attaches the call's approver to ctx.
Types ¶
type Approve ¶
Approve asks the human to approve a call's operation on the console's approval screen (console.Env.Approve for the call's request).
func ApproveFrom ¶
ApproveFrom returns the call's approver, or nil.
type Backend ¶
type Backend struct {
// contains filtered or unexported fields
}
Backend implements console.Backend.
func (*Backend) Checks ¶
Checks implements console.Backend: a console with no remote source and no LOCKLOG_NETWORK runs with no network; any interface but the loopback means it was started otherwise, and it refuses.
func (*Backend) Connect ¶
Connect implements console.Backend: the launcher's checks first, then the engine of the policy in force.
func (*Backend) LoadPolicy ¶
LoadPolicy implements console.Backend: the profile from the project's .locklog/config.toml with the launch environment.
type ClearView ¶
ClearView is a call's clear-view state: the console's clear-results switch (Ctrl-O) and what the engine keeps for it (its own records).
func ClearViewFrom ¶
ClearViewFrom returns the call's clear-view state, or nil.
type Declined ¶
Declined is an engine's error for a call the human did not approve: Resp is the console's answer (a denial, a timeout, a pending ticket), sent to the agent as is.
type Engine ¶
type Engine interface {
Handle(ctx context.Context, method string, params json.RawMessage, c Caller) (result any, refused *Refusal, err error)
// Status is the engine's part of log.status and :status.
Status(ctx context.Context) any
Close() error
}
Engine answers the agent's log methods. params is the request's raw JSON, validated by the engine; result is a masked, typed value that marshals to JSON. A refusal is the agent's error (over budget, a personal value in a predicate, ...); err is the engine's own failure.
type OpenOptions ¶
type OpenOptions struct {
// Policy is the approved policy in force: the engine reads only the
// sources it names.
Policy config.Policy
// Credentials are the secret of the profile's remote source (zero for
// local sources).
Credentials egress.Credentials
// StateDir is the console's state directory (home volume).
StateDir string
// Roots are the mount roots of the policy's local sources, checked
// against the launcher's (PlanRoots): the only directories the
// sources may be given.
Roots Roots
// Project is the project root ("" for none): its .locklog holds the
// human's PII rules.
Project string
}
OpenOptions is what an engine is opened with.
type Opener ¶
type Opener func(ctx context.Context, o OpenOptions) (Engine, error)
Opener opens the engine of a policy.
type Options ¶
type Options struct {
Profile string
// Root is the project root ("" for none).
Root string
// StateDir is the console's state base.
StateDir string
// Network and ExtraRoots are LOCKLOG_NETWORK and LOCKLOG_EXTRA_ROOTS
// as the launcher passed them: they are part of the policy.
Network string
ExtraRoots []string
// ExpectDir and ExpectRoots are LOCKLOG_EXPECT_DIR and
// LOCKLOG_EXPECT_ROOTS: the device and inode of .locklog and of each
// mount root, as the launcher checked them on the host.
ExpectDir string
ExpectRoots string
// DockerRoot is LOCKLOG_DOCKER_ROOT: the containers root the launcher
// bound for a docker source.
DockerRoot string
// InContainer is true in locklog's image (InImage): LOCKLOG_EXPECT_DIR
// is then required, and Root must be the directory the launcher
// started the console in.
InContainer bool
// SysClassNet is /sys/class/net (tests replace it).
SysClassNet string
Open Opener
}
Options locate the profile a console serves and the launcher's checks.
type Policy ¶
Policy is a locklog policy as the console handles it.
type Record ¶
type Record struct {
audit.Base
Method string `json:"method"`
Sources []string `json:"sources,omitempty"`
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`
// Tool is the tool an approved scan runs (log.scan).
Tool string `json:"tool,omitempty"`
// Pseudonyms name what an unmask revealed or a lookup resolved, by
// pseudonym only (never the clear values).
Pseudonyms []string `json:"pseudonyms,omitempty"`
// ShownClear counts the records shown in clear on the console's
// terminal (results on, Ctrl-O), never to the agent.
ShownClear int `json:"shown_clear,omitempty"`
}
Record is the audit record of one agent call: the method, the sources and the range it named, and the outcome. It never holds a predicate, a value or a log line: those are the agent's and the logs' text, which the detectors may miss.
type Refusal ¶
Refusal is an answer the agent gets as a structured refusal: Message is prose that quotes no value of the agent's call nor of the logs; Info carries the code (E_OVER_BUDGET, E_PII_IN_QUERY, ...), retry and hint.
type Revealer ¶
Revealer is implemented by an engine that can show the records of a result in clear on the console's terminal (the clear view, Ctrl-O): one line per record, secrets and redactions kept. The lines are never part of an answer to the agent.
type Roots ¶
type Roots struct {
// Dirs are the directories of the file sources' globs
// (mountplan.Dir), sorted.
Dirs []string
// Journal are the journal directories bound (JournalDirs that
// exist on the host).
Journal []string
// Docker is the containers root (LOCKLOG_DOCKER_ROOT), "" without a
// docker source.
Docker string
// DockerChecked is set when the launcher could stat the containers
// root from the host and passed its device:inode; usually it cannot
// (/var/lib/docker is 0710 root), and the root is then the launcher's
// "not checked from the host" case.
DockerChecked bool
}
Roots are the mount roots of a policy's local sources, each one the launcher bound and checked (LOCKLOG_EXPECT_ROOTS): the only directories the sources are given.
func PlanRoots ¶
PlanRoots derives the mount plan of pr (mountplan.Lines) and returns its roots. In the launcher's container (o.InContainer) every planned directory must be one the launcher checked, after CheckMounts passed: a file glob's directory and each journal directory an entry of LOCKLOG_EXPECT_ROOTS, the containers root LOCKLOG_DOCKER_ROOT either such an entry or the launcher's "not checked from the host" case (a clean absolute path ending in /containers, a directory and not a link). A planned root the launcher did not check refuses the policy: the console was not started by the launcher with this plan. Outside the image (a developer's build) nothing was checked, and the planned directories are the roots.