Documentation
¶
Overview ¶
Package docker is the Docker log source: the json-file logs of the containers whose names the human approved, read from the containers root (`docker info .DockerRootDir` + /containers, bound read-only and non-recursive by the launcher), through a name -> id map the launcher keeps current.
The map ¶
The launcher writes the map into a host directory bound read-only, as a directory, at /run/locklog-map (MapDir). Each version is a file "map.v<N>" (N decimal, from 1, no leading zero) written atomically; the newest valid version wins. A version is:
locklog-map 1 c <id> <name> <max_file> <compress> x <id>
one entry per line, fields separated by one space, every line ending with "\n". A "c" line maps a json-file container: its 64 lower-case hex id, its name (a container name the config accepts), its max-file (1..100) and whether rotated files are compressed (0 or 1). An "x" line names a locklog console container (by its label or its name prefix): never served. Any malformed line, a duplicate id or name, refuses that version, and then nothing is served (fail closed: an older version is never used instead).
What is served ¶
Whatever the map says, a container is served only when its name matches one of the source's approved globs (path.Match: '*' and '?'), its name does not start with config.ConsolePrefix, and its id is neither an "x" id nor the console's own. Of a served container, only <Root>/<id>/<id>-json.log and <id>-json.log.N (.N.gz when compressed; .1 while Docker has not gzipped it yet), 1 <= N < max_file, are opened: probed by name (the 0710 directories cannot be listed with gid 0), beneath the root, never across a mount point (file.Options.NoXDev). Every record carries the trusted field "container" (the name).
Streams are "<id>/<name>/<file stream>": a renamed container's earlier references are stale.
Index ¶
- Constants
- Variables
- func Guard(production bool, ll landlock.Status, openat2 bool) error
- func IsLabel(name string) bool
- func Openat2() bool
- func Residuals(ll landlock.Status, openat2 bool) []string
- func SelfIDs() []string
- type Container
- type ContainersStatus
- type Map
- type Options
- type Source
- func (s *Source) Around(ctx context.Context, ref source.RawRef, before, after int) ([]source.RawRecord, error)
- func (s *Source) AroundMeasured(ctx context.Context, ref source.RawRef, before, after int) ([]source.RawRecord, int64, error)
- func (s *Source) ContainersStatus() (ContainersStatus, error)
- func (s *Source) Describe(ctx context.Context) (source.Schema, error)
- func (s *Source) IndexCounts(ctx context.Context, q source.CountQuery) (source.CountResult, error)
- func (s *Source) IndexStep(ctx context.Context, maxBytes int64, upkeep bool) (int64, bool, error)
- func (s *Source) Kind() string
- func (s *Source) Name() string
- func (s *Source) NumericTerms()
- func (s *Source) Plan(ctx context.Context, r source.Range, sel source.Selector) (source.Byteplan, error)
- func (s *Source) Reread(ctx context.Context, ref source.RawRef) (source.RawRecord, error)
- func (s *Source) Scan(ctx context.Context, ch source.Chunk) (source.Iterator, error)
Constants ¶
const ( // Kind is the source kind. Kind = "docker" // DefaultMapDir is where the launcher binds the map directory. DefaultMapDir = "/run/locklog-map" // RootEnv names the environment variable the launcher sets to the // containers root, bound at its own path. RootEnv = "LOCKLOG_DOCKER_ROOT" // ContainerField is the trusted field holding the container name. ContainerField = "container" )
const ( // MapOK: the newest version is valid. MapOK = "ok" // MapNone: no version yet (nothing is served). MapNone = "none" // MapInvalid: the newest version is refused (nothing is served). MapInvalid = "invalid" )
The states of the containers map (ContainersStatus.Map).
const ( // MaxFiles bounds a container's max-file (Docker's json-file accepts // more; the launcher clamps to it). MaxFiles = 100 )
The map file format. The launcher writes it; the console only reads it.
Variables ¶
var ErrUnguarded = errors.New("docker source refused on a production profile: neither Landlock nor openat2 with RESOLVE_NO_XDEV is available, " +
"so mounts propagated under the containers root (other containers' /dev/shm, swarm secrets) are guarded only by a mount comparison in this process; " +
"use a kernel with Landlock (>= 5.13, in the lsm= list) or openat2 (>= 5.6) and a seccomp profile that allows them")
ErrUnguarded refuses a docker source on a production profile that has neither guard at full strength.
Functions ¶
func Guard ¶
Guard decides whether a docker source may start: on a production profile it needs Landlock (enforced or partial) or openat2 with RESOLVE_NO_XDEV; with only one of them it starts, and Residuals names what is missing.
func IsLabel ¶
IsLabel reports whether a trusted name of a docker source is a label: the container, the runtime's stream, an attrs.<key>.
func Openat2 ¶
func Openat2() bool
Openat2 reports whether openat2 with RESOLVE_NO_XDEV works here (Linux >= 5.6, not blocked by seccomp): the file source then refuses mount crossings in the kernel, not by a comparison.
func SelfIDs ¶
func SelfIDs() []string
SelfIDs returns the ids (full, or the 12-character prefix) of the container this process runs in: from the sources of the /etc/hostname, /etc/hosts and /etc/resolv.conf mounts in /proc/self/mountinfo, and from a hostname of 12 hex characters (Docker's default). Empty outside a container.
Types ¶
type Container ¶
type Container struct {
ID string // 64 lower-case hex characters
Name string
MaxFile int // 1..MaxFiles: the live file and MaxFile-1 rotated ones
Compress bool
}
Container is one mapped json-file container.
type ContainersStatus ¶ added in v0.2.0
type ContainersStatus struct {
// Map is the state of the containers map.
Map string `json:"map"`
// Served counts the containers the map and the globs serve.
Served int `json:"served"`
// Stale counts the served containers whose log file is gone (the
// container was removed): the map lags behind Docker, and they hold
// nothing to read.
Stale int `json:"stale"`
}
ContainersStatus is the docker source's part of :status and locklog_status: counts only, never a container's name or id.
type Map ¶
type Map struct {
Version uint64
Containers []Container
// Consoles are the ids of locklog console containers: never served.
Consoles map[string]bool
}
Map is one valid version of the containers map.
type Options ¶
type Options struct {
Name string
// Containers are the approved container name globs.
Containers []string
// Attrs are the keys of the json-file frame's "attrs" object kept (the
// log driver's labels and env): each is the member <key> of the nested
// object attribute "attrs", addressed by the path "attrs.<key>"; the
// other keys are dropped.
Attrs []string
// Root is the containers root, as mounted (absolute).
Root string
// MapDir is the map directory (default DefaultMapDir).
MapDir string
// Parse is the base of the parser options (multiline, location);
// the format and the attributes are set by the source.
Parse parse.Options
// Trusted are the trusted names the index counts; ContainerField is
// always added. The container, the stream and attrs.<key> are labels
// (frame attributes, parse.Event.Attrs), the others line fields.
Trusted []string
// Index is the local index store (nil: no index).
Index *index.Store
// Sensitive reports a trusted value a detector flags.
Sensitive func(field, value string) bool
// RulesGeneration changes when the rules behind Sensitive change.
RulesGeneration func() uint64
// Now is the clock (tests).
Now func() time.Time
// Self returns the ids of the console's own container (full, or
// prefixes of at least 12 characters); default SelfIDs. Called once.
Self func() []string
}
Options configure a docker source.
type Source ¶
type Source struct {
// contains filtered or unexported fields
}
Source is a docker source. It is safe for concurrent use.
func (*Source) Around ¶
func (s *Source) Around(ctx context.Context, ref source.RawRef, before, after int) ([]source.RawRecord, error)
Around returns the records around ref, from its stream.
func (*Source) AroundMeasured ¶
func (s *Source) AroundMeasured(ctx context.Context, ref source.RawRef, before, after int) ([]source.RawRecord, int64, error)
AroundMeasured is Around, also returning the bytes the inner file source processed (source.AroundMeter).
func (*Source) ContainersStatus ¶ added in v0.2.0
func (s *Source) ContainersStatus() (ContainersStatus, error)
ContainersStatus reports the containers map and the served containers, the stale ones counted: a served container whose live log file is gone. Each is checked by name (a stat beneath the root, no read).
func (*Source) Describe ¶
Describe merges the served containers' schemas. The container field's values are the served names.
func (*Source) IndexCounts ¶
func (s *Source) IndexCounts(ctx context.Context, q source.CountQuery) (source.CountResult, error)
IndexCounts merges the served containers' index counts; a selector term on the container prunes whole containers first.
func (*Source) IndexStep ¶
IndexStep indexes the served containers in turn, within maxBytes (upkeep: see file.Source.IndexStep).
func (*Source) NumericTerms ¶ added in v0.2.0
func (s *Source) NumericTerms()
NumericTerms implements source.NumericSelector: the file sources and the container filter treat an ambiguous value of a numeric term as unknown.
func (*Source) Plan ¶
func (s *Source) Plan(ctx context.Context, r source.Range, sel source.Selector) (source.Byteplan, error)
Plan returns the chunks of the served containers matching sel, container by container (sorted by name), each newest stream first.