Documentation
¶
Overview ¶
Package daemon implements openbloxd: the policy broker that owns the Docker connection so its callers need no socket access.
Index ¶
Constants ¶
const ( TransportUnix = "unix" TransportTLS = "tls" )
Transport names the way a request arrived.
Variables ¶
This section is empty.
Functions ¶
func Listen ¶
Listen creates the Unix socket the daemon serves on.
It refuses to start rather than serve on a socket it could not lock down: a permissive socket is indistinguishable from a working one until something uses it, and by then the caller is trusting a boundary that is not there.
A leftover socket from an unclean shutdown is removed first. Only a socket — removing anything else would let a misconfigured path delete a real file.
func ListenTLS ¶ added in v0.7.0
func ListenTLS(cfg ListenConfig) (net.Listener, error)
ListenTLS creates the network listener the daemon serves on.
Two gates, both during the handshake. The client certificate must chain to the configured CA, and its Common Name must be on the allowlist.
The second gate is not belt-and-braces. With verification alone the CA is the whole access control list, so a CA shared with anything else silently grants sandbox creation to whatever that other thing issued. The allowlist is what makes a CA mis-issuance survivable, and what makes the set of permitted callers something an operator can read in one place.
Rejecting during the handshake rather than in a middleware means a caller that fails either gate never reaches the request router at all.
func WithCaller ¶ added in v0.7.0
WithCaller records the caller on the request context, over every transport.
Name is empty for a Unix caller because SO_PEERCRED is unimplemented; that is the local transport's identity seam and is unrelated to this one.
Types ¶
type Backend ¶
type Backend interface {
sandbox.Backend
DialPort(ctx context.Context, name string, port int) (net.Conn, error)
Reap(ctx context.Context) ([]string, error)
}
Backend is what the daemon needs from a provisioner: the library contract plus the two methods outside it that the broker exposes.
type Caller ¶ added in v0.7.0
Caller is who made a request.
Nothing consumes this yet. It exists anyway because a transport that discards the caller's identity has to be reopened to add per-caller quotas or an audit trail, and the place to record identity is where it is still available.
Transport is carried explicitly rather than inferred from an empty Name: a log line for a security boundary should say whether a request arrived locally or over a network, not leave it to be deduced.
type Config ¶
type Config struct {
Socket string `yaml:"socket"`
SocketGroup string `yaml:"socket_group"`
Listen *ListenConfig `yaml:"listen"`
ReapInterval time.Duration `yaml:"reap_interval"`
Profiles map[string]Profile `yaml:"profiles"`
}
Config is the daemon's whole configuration.
type ListenConfig ¶ added in v0.7.0
ListenConfig is the network listener. Absent means the daemon serves only its Unix socket, which stays the default and the recommended arrangement wherever caller and daemon share a host.
func (ListenConfig) IsWildcardHost ¶ added in v0.7.0
func (l ListenConfig) IsWildcardHost() bool
IsWildcardHost reports whether the address binds every interface. That is a legitimate choice for a daemon whose network namespace is already the boundary, and a serious mistake otherwise — so it is warned about at boot rather than refused.
type Profile ¶
type Profile struct {
Image string `yaml:"image"`
Runtime string `yaml:"runtime"`
Egress string `yaml:"egress"`
User string `yaml:"user"`
CPUs float64 `yaml:"cpus"`
MemoryMB int64 `yaml:"memory_mb"`
DiskMB int64 `yaml:"disk_mb"`
MaxProcesses int `yaml:"max_processes"`
MaxSandboxes int `yaml:"max_sandboxes"`
IdleTimeout time.Duration `yaml:"idle_timeout"`
MaxAge time.Duration `yaml:"max_age"`
DefaultTimeout time.Duration `yaml:"default_timeout"`
MaxTimeout time.Duration `yaml:"max_timeout"`
RegistryAuth *RegistryAuth `yaml:"registry_auth"`
}
Profile is one named isolation policy. Every field here is deliberately unreachable from a request: this struct is the reason WithRuntime and WithEgress cannot be asked for over the wire.
func (Profile) DigestPinned ¶
DigestPinned reports whether the profile's image is pinned by digest. The daemon warns rather than refuses: refusing would make a local tag-built image unusable in development, where there is no registry to pin against.
func (Profile) Options ¶
func (p Profile) Options() []sandbox.CreateOption
Options renders the profile as library options.
This function is the only place in openbloxd that produces WithRuntime or WithEgress, and its sole input is the config file. Nothing derived from a request reaches it. Keep it that way.
type RegistryAuth ¶
RegistryAuth authenticates image pulls. It lives here, and only here: the credentials never leave the daemon and are never a request field.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server routes broker requests onto a Backend under a fixed policy.
func (*Server) Handler ¶
Handler returns the route table.
No path carries a version prefix: the daemon and its client ship together and speak over a local socket, so there is no independently versioned consumer to protect. A header can version this later without a guess baked into a path.
type TLSConfig ¶ added in v0.7.0
type TLSConfig struct {
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
ClientCAFile string `yaml:"client_ca_file"`
AllowedClientCNs []string `yaml:"allowed_client_cns"`
}
TLSConfig is the daemon's half of the mTLS credential, plus the allowlist that stops the CA from being the whole access control list.